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 № 1Uż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