2009-03-16 20 views

Odpowiedz

22

Różnica polega na tym, że funkcja RelayCommand może przyjmować uczestników. Możesz zdefiniować RelayCommand poza ViewModel. ViewModel może następnie dodać delegatów do polecenia, gdy tworzy i wiąże polecenie do obiektu interfejsu użytkownika, takiego jak kontrolka. Delegaci z kolei mają dostęp do prywatnej zmiennej ViewModel, ponieważ są one zdefiniowane w zakresie samego Modelu widoku.

Służy do zmniejszania ilości kodu zawartego w ViewModelu, ponieważ trend definiuje polecenie Routed jako klasę zagnieżdżoną wewnątrz obiektu ViewModel. Funkcjonalność tych dwóch jest poza tym podobna.

67

RoutedCommand jest częścią WPF, a RelayCommand został stworzony przez ucznia WPF, Josh Smith;).

Poważnie, jednak RS Conley opisał niektóre różnice. Kluczową różnicą jest to, że RoutedCommand jest implementacją ICommand, która używa RoutedEvent do trasowania przez drzewo aż do znalezienia CommandBinding dla polecenia, podczas gdy RelayCommand nie wykonuje routingu, a zamiast tego wykonuje bezpośrednio delegata. W scenariuszu M-V-VM RelayCommand (DelegateCommand in Prism) jest prawdopodobnie lepszym wyborem.

34

Odnośnie stosowania RelayCommand i RoutedCommand w MVVM główna różnica dla mnie jest następująca:

Położenie kodu

RelayCommand pozwala realizować polecenia w każdej klasie (jak ICommand-PROPERTY z delegatami), który następnie jest konwencjonalnie podany do kontroli, która wywołuje polecenie. Ta klasa to ViewModel. Jeśli używasz polecenia routowanego, będziesz musiał zaimplementować metody związane z poleceniem w kodzie beffind kontrolki, ponieważ metody są określone przez atrybuty elementu CommandBinding. Zakładając, że ścisła MVVM oznacza posiadanie "pustego" pliku codebehind, w rzeczywistości nie ma możliwości użycia standardowych poleceń routowanych z MVVM.

Co RS Conley powiedział, że RelayCommand pozwala zdefiniować RelayCommand poza ViewModel ma rację, ale przede wszystkim pozwala na zdefiniowanie jej wewnątrz ViewModel, który RoutedCommand nie.

Routing

Z drugiej strony, RelayCommands nie obsługują routing poprzez drzewa (jak wspomniano wcześniej), co nie jest problemem, tak długo, jak interfejs oparty jest na jednym viewmodel. Jeśli nie jest, na przykład jeśli masz kolekcję przedmiotów z własnymi modelami widoku i chcesz wywołać polecenie potomka ViewModel dla każdej pozycji z elementu nadrzędnego naraz, będziesz musiał użyć routingu (zobacz także CompositeCommands) .

W sumie, powiedziałbym, że standardowe RoutedCommands nie nadają się do użytku w ścisłej MVVM. RelayCommands są idealne dla MVVM, ale nie obsługują routingu, który może być potrzebny.

+0

Dzięki za dodatkową głębię wyjaśnień i odniesienie do CompositeCommands - to pomogło mi zobaczyć, gdzie pasują. –

13

Twierdzę, że RoutedCommands są całkowicie legalne w ścisłej MVVM. Chociaż usługi RelayCommands są często preferowane ze względu na ich prostotę, RoutedCommands czasami oferuje korzyści organizacyjne.Na przykład możesz chcieć, aby kilka różnych widoków łączyło się z udostępnioną instancją ICommand bez bezpośredniego ujawniania tego polecenia bazowym ViewModels.

Na marginesie pamiętaj, że ścisła MVVM nie zabrania używania kodu źródłowego. Jeśli to prawda, nie można zdefiniować niestandardowych właściwości zależności w widokach!

W celu wykorzystania RoutedCommand w ścisłe ramy MVVM można wykonać następujące kroki:

  1. zadeklarować statycznych RoutedCommand wystąpienie do polecenia niestandardowego. Możesz pominąć ten krok, jeśli planujesz użyć predefiniowanego polecenia z klasy ApplicationCommands. Na przykład:

    public static class MyCommands { 
        public static RoutedCommand MyCustomCommand = new RoutedCommand(); 
    } 
    
  2. Attach żądane widoki na RoutedCommand przy użyciu XAML:

    <Button Command="{x:Static local:MyCommands.MyCustomCommand}" /> 
    
  3. jeden z twoich poglądów, który jest związany z odpowiednim ViewModel (czyli w zależności od tego ViewModel implementuje funkcjonalność poleceń) potrzeb narażać własnego DependencyProperty które będą zobowiązane do implementacji ViewModel za:

    public partial class MainView : UserControl 
    { 
        public static readonly DependencyProperty MyCustomCommandProperty = 
         DependencyProperty.Register("MyCustomCommand", 
         typeof(ICommand), typeof(MainView), new UIPropertyMetadata(null)); 
    
        public ICommand MyCustomCommand { 
         get { return (ICommand)GetValue(MyCustomCommandProperty); } 
         set { SetValue(MyCustomCommandProperty, value); } 
        } 
    
  4. Th e sam widok powinno wiązać się z RoutedCommand od kroku 1. W XAML:

    <UserControl.CommandBindings> 
        <CommandBinding Command="{x:Static local:MyCommands.MyCustomCommand}" 
            CanExecute="MyCustomCommand_CanExecute" 
            Executed="MyCustomCommand_Executed" 
            /> 
    </UserControl.CommandBindings> 
    

    W kodzie z opóźnieniem do widoku powiązane obsługi zdarzeń będzie tylko przekazywać ICommand zależności od właściwości zadeklarowanej w kroku 3 :

    private void MyCustomCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e) { 
        var command = this.MyCustomCommand; 
        if (command != null) { 
         e.Handled = true; 
         e.CanExecute = command.CanExecute(e.Parameter); 
        } 
    } 
    private void MyCustomCommand_Executed(object sender, ExecutedRoutedEventArgs e) { 
        var command = this.MyCustomCommand; 
        if (command != null) { 
         e.Handled = true; 
         command.Execute(e.Parameter); 
        } 
    } 
    
  5. Wreszcie związać swoją realizację polecenia ViewModel (która powinna być ICommand) do właściwości niestandardowe zależność w XAML:

    <local:MainView DataContext="{Binding MainViewModel}" 
           MyCustomCommand="{Binding CustomCommand}" /> 
    

Zaletą tego podejścia jest to, że Twój ViewModel musi tylko dostarczać pojedynczą implementację interfejsu ICommand (a może to być nawet RelayCommand), podczas gdy dowolna liczba widoków może się do niego podłączyć poprzez RoutedCommand bez konieczności bycia bezpośrednio związany z tym ViewModel.

Niestety istnieje jedna z wad, ponieważ zdarzenie ICommand.CanExecuteChanged nie będzie działać. Kiedy twój ViewModel chce, aby View odświeżył właściwość CanExecute, musisz wywołać CommandManager.InvalidateRequerySuggested().