2009-02-11 5 views
2

Donc j'apprends actuellement WPF, et je veux faire une base de données simple entre une valeur booléenne, et si oui ou non un MenuItem est activé ou non.Liaison de données WPF IsEnabled Propriété

je code comme ceci:

<MenuItem Name="miSaveFile" Header="Save" Click="miSaveFile_Click" 
IsEnabled="{Binding}" /> 

Et dans le fichier .cs je mis:

miSaveFile.DataContext = dataChanged; 

Pour une raison quelconque le MenuItem ne semble pas être correctement reflétant l'état de dataChanged.

Qu'est-ce qui me manque?

Répondre

4

Il vaut mieux se lier à un objet qu'à un type primitif. Cet objet est souvent appelé "modèle" pour votre vue. WPF utilise l'interface INotifyPropertyChanged pour le modèle (ou souvent view-model) pour informer l'affichage que le modèle a changé d'état. Par conséquent, vous souhaiterez d'abord définir une classe de données en tant que modèle qui implémente l'interface INotifyPropertyChanged et déclenche l'événement PropertyChanged chaque fois qu'une propriété est modifiée.

Lorsque vous définissez une liaison, vous devez vous préoccuper de 5 éléments principaux sur la liaison. La liaison a un objet source, un chemin source sur l'objet source, un objet cible, une propriété cible sur l'objet cible et un convertisseur facultatif.

Si vous ne spécifiez pas la source, elle utilise par défaut le DataContext du contrôle sur lequel la liaison est définie. Il existe d'autres options pour définir la source. Here est un article Microsoft sur la définition de la source. Vous pouvez ensuite définir le chemin d'une propriété à retirer de la source pour la liaison. Dans votre cas, la source est un booléen et il n'y a pas de chemin car la liaison utilise l'ensemble de l'objet source.

La cible est toujours le contrôle sur lequel vous définissez la liaison et la propriété target est la propriété de ce contrôle auquel vous liez. Dans ce cas, MenuItem et IsEnabled.

Un convertisseur peut éventuellement convertir la valeur source en une valeur compatible avec la propriété cible. Vous pouvez utiliser n'importe quel objet pour un convertisseur qui implémente IValueConverter ou IMultiValueConverter (pour MutliBindings).

Dans votre cas, je créerais d'abord un modèle qui implémente INotifyPropertyChanged. Ensuite, j'attribuerais le DataContext du menu à une instance du modèle. Ensuite, je mettrais la liaison à:

IsEnabled="{Binding Path=EnableFlag}" 

(Où EnableFlag est une propriété booléenne dans le modèle que vous souhaitez menu pour se lier à)

Si vous configurez correctement l'interface INotifyPropertyChanged, l'élément de menu sera activé/désactivé chaque fois que vous modifiez cette propriété sur le modèle.

1

Comment l'interface utilisateur sait-elle que la variable dataChanged a réellement changé?

Je me lie normalement à une propriété sur un objet et laisse cette classe implémenter INotifyPropertyChanged. L'interface utilisateur est ensuite mise à jour "automagiquement" à chaque fois que l'événement PropertyChanged est appelé.

J'aurais

<MenuItem Name="miSaveFile" Header="Save" Click="miSaveFile_Click" 
IsEnabled="{Binding DataChanged}"</MenuItem> 

puis définissez miSaveFile.DataContext = myObject.DataChanged (myObject peut être si vous utilisez le code-behind)

Edit: Je viens de faire un test rapide . Si vous définissez le contexte de données directement à la propriété DataChanged, un abonnement à l'événement PropertyChanged sur l'objet propriétaire n'est pas ajouté. Mais la solution que je propose fonctionne.

+0

"? Comment savoir l'interface utilisateur lorsque la variable dataChanged a réellement changé" Bonne question. En ce moment je suis toujours dans l'étape Data_Binding-Is-Voodoo :) –

+0

Si vous voulez vraiment comprendre ce qui se passe (le truc vaudou) vous pouvez activer le framework .Net dans Visual Studio et regarder le code qui est en train d'être réalisé :) –

2

Pour un élément Menu, ne serait-il pas préférable d'utiliser le modèle Command plutôt que les propriétés Click et IsEnabled?

Après InitialiseComponent():

this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Save, fileSaveExecuted, fileSaveCanExecute)); 

D'autres méthodes:

/* here is where you set e.CanExecute true for enabled: */ 
    private void fileSaveCanExecute(object x, CanExecuteRoutedCommandEventArgs e)) { e.CanExecute = ...; e.Handled = true; } 
/* here is where you act on the command: */ 
    private void fileSaveExecuted(object sender, ExecutedRoutedEventArgs e) { ... } 

XAML:

<MenuItem Header="_Save" Command="Save"/>