/ / Quelle est la meilleure façon de transmettre un événement à ViewModel? - c #, wpf, xaml, mvvm

Quelle est la meilleure façon de passer un événement à ViewModel? - c #, wpf, xaml, mvvm

Le cas est le suivant: J'ai un événement de contrôle sur lequel je veux que mon ViewModel réagisse. Actuellement, je le fais en exécutant une commande de bouton invisible comme dans l'exemple ci-dessous.

Dans View.xaml:

<Control x:Name="SearchResultGrid" ... DataRefreshed="SearchResultRefreshed" />
<Button x:Name="SearchResultRefreshedButton" Visibility="Collapsed" Command="{Binding SearchResultRefreshedCommand}" />

Dans View.xaml.cs:

private void SearchResultRefreshed(object sender, EventArgs e)
{
if (SearchResultRefreshedButton.Command != null)
{
SearchResultRefreshedButton.Command.Execute(SearchResultGrid.ResultRowCount);
}
}

Cela fonctionne bien, mais cela ressemble à un hack pour moi. Je me demande s'il y a une meilleure façon (standard) de faire cela? Je n'ai pas pu trouver d'exemples et c'est ce que j'ai "inventé" moi-même.

Réponses:

7 pour la réponse № 1

En utilisant MVVM, la manière générale de gérer les événements est de simplement les encapsuler Propriétés attachées, Ou utiliser Événements attachés. Voici un exemple utilisant le PreviewKeyDown événement dans une propriété attenante:

public static DependencyProperty PreviewKeyDownProperty = DependencyProperty.RegisterAttached("PreviewKeyDown", typeof(KeyEventHandler), typeof(TextBoxProperties), new UIPropertyMetadata(null, OnPreviewKeyDownChanged));

public static KeyEventHandler GetPreviewKeyDown(DependencyObject dependencyObject)
{
return (KeyEventHandler)dependencyObject.GetValue(PreviewKeyDownProperty);
}

public static void SetPreviewKeyDown(DependencyObject dependencyObject, KeyEventHandler value)
{
dependencyObject.SetValue(PreviewKeyDownProperty, value);
}

public static void OnPreviewKeyDownChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
TextBox textBox = dependencyObject as TextBox;
if (e.OldValue == null && e.NewValue != null) textBox.PreviewKeyDown += TextBox_PreviewKeyDown;
else if (e.OldValue != null && e.NewValue == null) textBox.PreviewKeyDown -= TextBox_PreviewKeyDown;
}

private static void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
TextBox textBox = sender as TextBox;
KeyEventHandler eventHandler = GetPreviewKeyDown(textBox);
if (eventHandler != null) eventHandler(sender, e);
}

Notez qu'il est tout aussi facile (et mieux aussi) d'utiliser un ICommand au lieu du réel KeyEventArgs objet qui ne devrait pas vraiment être dans le modèle de vue. Il suffit de créer une propriété attachée de type ICommand et appeler ça de cette TextBox_PreviewKeyDown gestionnaire à la place:

private static void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
TextBox textBox = sender as TextBox;
ICommand command = PreviewKeyDownCommand(textBox);
if (command != null && command.CanExecute(textBox)) command.Execute(textBox);
}

De toute façon, il serait utilisé quelque chose comme ceci:

<TextBox TextBoxProperties.PreviewKeyDown="SomeKeyEventHandler" />

Ou si vous avez utilisé l'option préférée ICommand méthode:

<TextBox TextBoxProperties.PreviewKeyDownCommand="{Binding SomeCommand}" />

2 pour la réponse № 2

Personnellement, je n’ai jamais eu besoin d’utiliser unpropriété attachée pour gérer l'événement d'un contrôle. Dans votre exemple, d'un contrôle voulant savoir quand le "SearchResultRefreshed" puis informer le ViewModel via le contrôle caché ... pourquoi le ViewModel ne sait pas déjà que les résultats ont été rafraîchi?

Si les résultats proviennent du ViewModel dansen premier lieu, et la liaison est utilisée pour les afficher sous votre contrôle, alors la connaissance que les résultats de la recherche ont été actualisés doit être pilotée par votre ViewModel - pas votre vue.

Dans quelques cas seulement, j'ai trouvé un besoin de rompre avec les ICommandes et la liaison de données.


0 pour la réponse № 3

Vous devez ajouter une propriété de dépendance DataRefreshed à votre contrôle pour y lier

ici un exemple comment vous pouvez le faire

public static readonly DependencyProperty DataRefreshedProperty = DependencyProperty.Register(
"DataRefreshed",
typeof(bool),
typeof("typeof yourcontrol here "),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnDataRefreshedChanged)
)
);
public bool DataRefreshed
{
get { return (bool)GetValue(DataRefreshedProperty); }
set { SetValue(DataRefreshedProperty, value); }
}

Ensuite, vous pouvez manipuler votre propriété comme n'importe quelle autre propriété WPF par exemple SearchResultRefreshed qui est défini dans votre ViewModel

<Control x:Name="SearchResultGrid" ... DataRefreshed="{Binding SearchResultRefreshed}" />
<Button x:Name="SearchResultRefreshedButton" Visibility="Collapsed" Command="{Binding SearchResultRefreshedCommand}" />

jetez un œil au tutoriel suivant pour en savoir plus dependecyproperty and attachedproperty