MVVM Định tuyến và Lệnh chuyển tiếp


Câu trả lời:


69

RoutedCommand là một phần của WPF, trong khi RelayCommand được tạo ra bởi một Đệ tử WPF, Josh Smith;).

Tuy nhiên, nghiêm túc mà nói, RS Conley đã mô tả một số điểm khác biệt. Sự khác biệt chính là RoutedCommand là một triển khai ICommand sử dụng RoutedEvent để định tuyến qua cây cho đến khi tìm thấy CommandBinding cho lệnh, trong khi RelayCommand không định tuyến và thay vào đó thực thi trực tiếp một số đại biểu. Trong kịch bản MV-VM, RelayCommand (DelegateCommand trong Prism) có lẽ là lựa chọn tốt hơn.


34

Về việc sử dụng RelayCommand và RoutedCommand trong MVVM, sự khác biệt chính đối với tôi là:

Vị trí của mã

RelayCommand cho phép bạn thực hiện lệnh trong bất kỳ lớp nào (dưới dạng ICommand-thuộc tính với các đại biểu), sau đó được truyền dữ liệu về điều khiển theo quy ước, sẽ gọi lệnh. Lớp này là ViewModel . Nếu bạn sử dụng lệnh được định tuyến, bạn sẽ phải triển khai các phương thức liên quan đến lệnh trong phần của điều khiển, vì các phương thức được chỉ định bởi các thuộc tính của phần tử CommandBinding. Giả sử rằng MVVM nghiêm ngặt có nghĩa là có một tệp mã "trống", thực tế không có khả năng sử dụng các lệnh được định tuyến tiêu chuẩn với MVVM.

RS Conley đã nói gì, rằng RelayCommand cho phép bạn xác định RelayCommand bên ngoài ViewModel là đúng, nhưng trước hết nó cho phép bạn định nghĩa nó bên trong ViewModel, điều mà RoutedCommand thì không.

định tuyến

Mặt khác, RelayCommands không hỗ trợ định tuyến qua cây (như đã nói trước đây), điều này không phải là vấn đề, miễn là giao diện của bạn dựa trên một viewModel duy nhất. Nếu không, ví dụ: nếu bạn có một bộ sưu tập các mục với ViewModels của riêng chúng và muốn gọi một lệnh của ViewModel con cho từng mục từ phần tử mẹ cùng một lúc, bạn sẽ phải sử dụng định tuyến (xem thêm CompositeCommands) .

Nói chung, tôi sẽ nói rằng các RoutedCommand tiêu chuẩn không thể sử dụng được trong MVVM nghiêm ngặt. RelayCommands hoàn hảo cho MVVM nhưng không hỗ trợ định tuyến mà bạn có thể cần.


Cảm ơn bạn đã giải thích sâu hơn và tham chiếu đến CompositeCommands - điều đó đã giúp tôi biết chúng phù hợp ở đâu.
Lars Kemmann

22

Sự khác biệt là RelayCommand có thể chấp nhận các đại biểu. Bạn có thể xác định RelayCommand bên ngoài ViewModel. Sau đó, ViewModel có thể thêm đại diện vào lệnh khi nó tạo và liên kết lệnh với một đối tượng UI như một điều khiển. Đến lượt mình, các đại biểu có thể truy cập vào biến private của ViewModel khi chúng được xác định trong phạm vi của chính View Model.

Nó được sử dụng để cắt giảm lượng mã có trong ViewModel vì xu hướng là xác định lệnh Định tuyến như một lớp lồng nhau bên trong ViewModel. Chức năng của cả hai là tương tự nhau.


15

Tôi cho rằng RoutedCommands hoàn toàn hợp pháp trong MVVM nghiêm ngặt. Mặc dù RelayCommands thường được ưa chuộng hơn vì tính đơn giản của chúng, RoutedCommands đôi khi mang lại lợi thế về mặt tổ chức. Ví dụ: bạn có thể muốn một số dạng xem khác nhau kết nối với một phiên bản ICommand được chia sẻ mà không trực tiếp hiển thị lệnh đó cho các ViewModels bên dưới.

Ngoài ra, hãy nhớ rằng MVVM nghiêm ngặt không cấm sử dụng mã phía sau. Nếu điều đó là đúng thì bạn không bao giờ có thể xác định các thuộc tính phụ thuộc tùy chỉnh trong chế độ xem của mình!

Để sử dụng RoutedCommand trong khuôn khổ MVVM nghiêm ngặt, bạn có thể làm theo các bước sau:

  1. Khai báo một phiên bản RoutedCommand tĩnh cho lệnh tùy chỉnh của bạn. Bạn có thể bỏ qua bước này nếu định sử dụng lệnh được xác định trước từ lớp ApplicationCommands. Ví dụ:

    public static class MyCommands {
        public static RoutedCommand MyCustomCommand = new RoutedCommand();
    }
    
  2. Đính kèm các dạng xem mong muốn vào RoutedCommand bằng XAML:

    <Button Command="{x:Static local:MyCommands.MyCustomCommand}" />
    
  3. Một trong các chế độ xem của bạn được liên kết với ViewModel phù hợp (tức là bất kỳ ViewModel nào triển khai chức năng lệnh) cần phải hiển thị DependencyProperty tùy chỉnh sẽ bị ràng buộc với việc triển khai ViewModel của bạn:

    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. Chế độ xem tương tự sẽ tự liên kết với RoutedCommand từ bước 1. Trong XAML:

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

    Trong phần mã phía sau cho chế độ xem của bạn, các trình xử lý sự kiện được liên kết sẽ chỉ ủy quyền cho ICommand từ thuộc tính phụ thuộc được khai báo trong bước 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. Cuối cùng, liên kết việc triển khai lệnh ViewModel của bạn (phải là một ICommand) với thuộc tính phụ thuộc tùy chỉnh trong XAML:

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

Ưu điểm của cách tiếp cận này là ViewModel của bạn chỉ cần cung cấp một triển khai duy nhất của giao diện ICommand (và nó thậm chí có thể là RelayCommand), trong khi bất kỳ số lượng View nào cũng có thể gắn vào nó thông qua RoutedCommand mà không cần bị ràng buộc trực tiếp vào ViewModel.

Thật không may, có một nhược điểm là sự kiện ICommand.CanExecuteChanged sẽ không hoạt động. Khi ViewModel của bạn muốn View làm mới thuộc tính CanExecute thì bạn phải gọi CommandManager.InvalidateRequerySuggested ().

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.