Comparer une interface utilisateur pilotée par les événements à une interface utilisateur liée aux données
Une interface utilisateur pilotée par les événements est conçue autour des événements exposés par un contrôle. Ces événements peuvent être associés au code du gestionnaire d’événements qui est appelé lorsque l’événement est déclenché. Prenons l’exemple d’un bouton qui, lorsqu’un utilisateur clique dessus, effectue une opération de longue durée. Le gestionnaire d’événements affecté à l’événement Clicked
peut démarrer l’opération, puis définir la propriété IsEnabled
du bouton sur false
, empêchant ainsi l’utilisateur de cliquer à nouveau sur le bouton pendant l’exécution de l’opération.
Une interface utilisateur liée aux données utilise la liaison de données pour présenter des données et interagir avec elles. Les propriétés des contrôles sont liées aux propriétés de l’objet de données, et ces liaisons peuvent détecter les modifications apportées aux propriétés. Revenons au bouton qui effectue une opération de longue durée dans l’exemple précédent. Au lieu de désactiver le bouton dans le code-behind, nous lions la propriété IsEnabled
à la propriété IsBusy
de l’objet de données. Chaque fois que l’objet de données devient occupé (« busy »), l’état activé du bouton est automatiquement modifié pour refléter la situation.
Avantages et inconvénients de l’utilisation d’événements et du code-behind
L’utilisation du gestionnaire d’événements du contrôle avec du code-behind est un moyen rapide et pratique de concevoir la logique d’application pour votre interface utilisateur. Vous utilisez du code pour appeler des services pour obtenir des données, effectuer des opérations sur ces données et interagir avec les contrôles de la page. Le code est utilisé pour synchroniser l’interface utilisateur et les données.
Prenons l’exemple d’une application de service météo. Le fragment XAML suivant contient un bouton d’interface utilisateur simple que l’utilisateur sélectionne pour obtenir les dernières données et mettre à jour l’interface utilisateur avec l’humidité.
<VerticalStackLayout Margin="10">
<HorizontalStackLayout Spacing="20">
<Label Text="Postal Code:" VerticalOptions="Center" />
<Entry x:Name="PostalCode" WidthRequest="100" />
<Button x:Name="RefreshWeatherButton" Text="Refresh" WidthRequest="200" Clicked="RefreshWeatherButton_Clicked" />
</HorizontalStackLayout>
<Label x:Name="Humidity" Text="Humidity: ?" />
</VerticalStackLayout>
Cet exemple comprend trois contrôles nommés :
- Contrôle
Entry
nommé PostalCode. - Contrôle
Button
nommé RefreshWeatherButton. - Contrôle
Label
nommé Humidity.
RefreshWeatherButton
possède un gestionnaire d’événements déclaré pour l’événement Clicked
. Lorsque l’utilisateur clique sur le bouton, le gestionnaire d’événements interroge un service météo pour obtenir les dernières prévisions météorologiques, en utilisant les données entrées dans le contrôle d’entrée PostalCode
, puis définit le texte de l’étiquette Humidity
sur l’humidité actuelle.
private void RefreshWeatherButton_Clicked(object sender, EventArgs e)
{
WeatherService.Location = PostalCode.Text;
WeatherService.Refresh();
Humidity.Text = $"Humidity: {WeatherService.Humidity}";
}
Dans ce gestionnaire d’événement unique, trois contrôles sont étroitement couplés les uns aux autres et aux données par le biais du code-behind.
Cette conception fonctionne très bien pour les petites interfaces utilisateur, mais dès qu’elles sont plus complexes, la gestion d’un code-behind étroitement couplé peut devenir problématique. Si vous supprimez ou modifiez un contrôle, vous devez nettoyer tout le code utilisant ces contrôles d’interface utilisateur (ce qui peut inclure le gestionnaire d’événements). Si vous décidez de redéfinir l’interface utilisateur, vous devez également refactoriser beaucoup de code. Et lorsque la structure de données de stockage change, vous devez vous plonger dans le code de chaque interface utilisateur pour que tout reste synchronisé.
La liaison de données simplifie les choses
Les liaisons de données peuvent être implémentées en XAML ou dans le code, mais elles sont beaucoup plus courantes en XAML où elles contribuent à réduire la taille du fichier code-behind. En remplaçant le code procédural dans les gestionnaires d’événements par du code déclaratif ou un balisage, l’application est simplifiée et clarifiée. Étant donné que les liaisons ne nécessitent pas de code-behind, vous pouvez facilement créer, modifier ou redéfinir l’interface utilisateur pour l’adapter à la façon dont vous souhaitez présenter les données.
Prenons le même exemple que dans la section précédente, mais mettons-le à jour pour utiliser la liaison de données :
<VerticalStackLayout Margin="10">
<HorizontalStackLayout Spacing="20">
<Label Text="Postal Code:" VerticalOptions="Center" />
<Entry Text="{Binding Location, Mode=OneWayToSource}" WidthRequest="100" />
<Button Text="Refresh" Command="{Binding RefreshWeather}" WidthRequest="200" />
</HorizontalStackLayout>
<Label Text="{Binding Humidity}" />
</VerticalStackLayout>
Vous pouvez repérer les propriétés liées aux données, celles-ci utilisant la syntaxe d’extension XAML {Binding ...}
pour la valeur de la propriété. Ne vous souciez pas des détails, car nous les aborderons plus loin dans ce module.
Les trois mêmes contrôles sont déclarés dans le code XAML, mais aucun d’entre eux n’est nommé puisqu’un nom n’est pas obligatoire :
Contrôle
Entry
:La propriété
Text
de ce contrôle est liée à une propriété nomméeLocation
.Contrôle
Button
:La propriété
Command
du bouton est liée à une propriété nomméeRefreshWeather
.Command
est une propriété sur le bouton qui appelle du code lorsque l’utilisateur appuie sur le bouton. Il s’agit d’une méthode alternative à l’utilisation de l’événementClicked
dans la liaison de données.Contrôle
Label
:Cette propriété
Text
est liée à une propriété nomméeHumidity
.
Dans cette interface utilisateur simple, la totalité du code-behind est éliminée. Bien que ce ne soit pas le but de la liaison de données, il est généralement possible de supprimer tout le code-behind. Le code-behind a toujours sa place. C’est à vous de décider dans quelle mesure vous souhaitez implémenter la liaison de données.
L’interface utilisateur est désormais faiblement couplée à un objet de données. Pourquoi est-elle faiblement couplée et non étroitement couplée ? Cela est dû à la façon dont les liaisons sont évaluées. Chaque contrôle possède une propriété BindingContext
. Si le contexte n’est pas défini, le contexte du contrôle parent est utilisé, et ainsi de suite jusqu’à ce que la racine du XAML soit évaluée. Lorsque les liaisons sont évaluées, l’instance d’objet du contexte est vérifiée pour déterminer si les propriétés requises existent, comme la liaison Text
du contrôle d’étiquette à la propriété Humidity
du contexte. Si Humidity
n’existe pas sur le contexte, rien ne se passe.
L’interface utilisateur étant faiblement couplée, vous pouvez la reconcevoir sans craindre d’arrêter le code. Toutefois, vous pouvez affecter le fonctionnement de l’application. Par exemple, si vous supprimez le bouton, l’application se compile et s’exécute toujours, mais vous n’avez aucun moyen d’actualiser la météo. D’un autre côté, vous pouvez remplacer les contrôles Entry
et Button
par le contrôle SearchBar
unique. Ce contrôle vous permet d’entrer du texte et d’appeler une commande.
<SearchBar Text="{Binding Location, Mode=OneWayToSource}" SearchCommand="{Binding RefreshWeather}" />
Comme vous pouvez le voir, l’utilisation de la liaison de données dans la conception de votre interface utilisateur peut vous aider à faire évoluer et à modifier votre interface utilisateur sans trop de travail. Elle synchronise automatiquement l’interface utilisateur avec les données, et la logique de l’application est séparée de l’interface utilisateur.