/ / Jaki jest najlepszy sposób przekazania zdarzenia do ViewModel? - c #, wpf, xaml, mvvm

Jaki jest najlepszy sposób przekazania zdarzenia do ViewModel? - c #, wpf, xaml, mvvm

Sprawa jest taka: mam zdarzenie sterujące, na które chcę, aby mój ViewModel zareagował. Obecnie robię to, wykonując polecenie niewidocznego przycisku, jak w poniższym przykładzie.

W View.xaml:

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

W View.xaml.cs:

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

Działa to dobrze, ale dla mnie wygląda na hack. Zastanawiam się, czy jest lepszy (standardowy) sposób na zrobienie tego? Nie mogłem znaleźć żadnych przykładów i właśnie to sam „wymyśliłem”.

Odpowiedzi:

7 dla odpowiedzi № 1

Używając MVVM, ogólnym sposobem obsługi zdarzeń jest po prostu ich zawinięcie Załączone właściwości, albo użyj Załączone wydarzenia. Oto przykład z użyciem PreviewKeyDown wydarzenie w załączonej nieruchomości:

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);
}

Pamiętaj, że korzystanie z narzędzia jest równie łatwe (i lepsze) ICommand zamiast faktycznego KeyEventArgs obiekt, który tak naprawdę nie powinien znajdować się w modelu widoku. Wystarczy utworzyć właściwość Attached typu ICommand i nazwij to od tego TextBox_PreviewKeyDown zamiast tego handler:

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);
}

Tak czy inaczej, użyłby czegoś takiego:

<TextBox TextBoxProperties.PreviewKeyDown="SomeKeyEventHandler" />

Lub jeśli użyłeś preferowanego ICommand metoda:

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

2 dla odpowiedzi nr 2

Osobiście nigdy nie musiałem używaćwłaściwość dołączona do obsługi zdarzenia formantu. W twoim przykładzie formant chce wiedzieć, kiedy „SearchResultRefreshed”, a następnie informuje ViewModel za pomocą ukrytego formantu ... dlaczego ViewModel już nie wie, że wyniki mają został odświeżony?

Jeśli wyniki pochodzą z ViewModel wpierwsze miejsce, a wiązanie służy do wyświetlania ich w obrębie twojej kontroli, następnie wiedza o tym, że wyniki wyszukiwania zostały odświeżone, powinna opierać się na twoim ViewModel - nie twoim widoku.

W nielicznych przypadkach stwierdziłem potrzebę oderwania się od ICommands i powiązania danych.


0 dla odpowiedzi № 3

Powinieneś dodać właściwość zależności DataRefreshed do twojej kontroli, aby się z nią związać

tutaj przykład, jak to zrobić

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); }
}

Następnie możesz na przykład manipulować swoją właściwością, jak każdą inną właściwością WPF SearchResultRefreshed który jest zdefiniowany w twoim ViewModel

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

zapoznaj się z poniższym samouczkiem, aby dowiedzieć się więcej dependecyproperty and attachedproperty