2010-02-10 41 views
8

Tôi đã sử dụng mẫu MVVM trong một thời gian, nhưng tôi vẫn gặp sự cố trong các tình huống thực tế. Đây là một số khác: Tôi sử dụng lệnh và bong bóng lên sự kiện để được xử lý trong ViewModel. Càng xa càng tốt. Nhưng dự án mà tôi đang sử dụng MVVM thực sự là một thư viện lớp. Khi tôi chạy mã lệnh, tôi cần có thể gửi một đối tượng trở lại ứng dụng gọi điện. Những cách được đề xuất để làm như vậy là gì?Lệnh trong MVVM (WPF) - cách trả về một giá trị?

Cụ thể: Trong ứng dụng gọi điện của tôi, tôi có trang XAML được liên kết trực tiếp với ViewModel của thư viện, chứa đối tượng "Thing1". Khi một nút được bấm, một phương thức trong ViewModel được gọi (gọi nó là "CopyThing1()"). Nó sao chép "Thing1" để tạo "Thing2". Sau đó, tôi cần phải gửi "Thing2" trở lại ứng dụng gọi điện.

Xin cảm ơn !!!

Trả lời

1

Mặc dù thông tin về Lệnh rõ ràng và chính xác nhưng không thể áp dụng trong trường hợp của tôi vì phản ứng bắt buộc xảy ra trong ứng dụng gọi KHÔNG sử dụng MVVM và nó không chỉ là phản hồi UI. Tôi đã điều tra Prism, nhưng thấy nó quá phức tạp cho những gì tôi cần vào lúc này. Tôi đã kết thúc huy động và xử lý các sự kiện, như mô tả ở đây -> WPF MVVM Correct Way to Fire Event on View From ViewModel

1

Nếu Thing2 là thuộc tính khác trên chế độ xem của bạn, bạn có thể sử dụng INotifyPropertyChanged bình thường để thông báo cho UI về thay đổi.

Bạn cũng có thể sử dụng Prism 's EventAggregator cho một cách tiếp cận tách rời hơn

+0

Cảm ơn. Đây là suy nghĩ ban đầu của tôi, nhưng phản hồi trong ứng dụng gọi điện sẽ không chỉ là phản hồi UI. Vì vậy, tôi đã không chắc chắn làm thế nào để tạo ra Thing2 để khởi động một sự kiện mà mã của ứng dụng gọi điện thoại có thể đáp ứng. –

+0

Thực ra, bạn có biết một ví dụ hay về sử dụng EventAggregator không? Ngoài ra, lợi thế của phiên bản Prism là gì so với hộp ngoài? –

+0

OK, tôi hiểu ngay bây giờ. Không nhận ra Prism đến từ đâu. QuickStart là ví dụ đơn giản nhất mà bạn biết không? –

10

lệnh không trả về giá trị, họ thay đổi trạng thái của ứng dụng của bạn. Trong trường hợp ICommands được gắn vào ViewModels thì nó khá đơn giản, bởi vì bạn có thể làm điều này bằng cách đơn giản là biến đổi ViewModel khi lệnh được thực hiện.

Sử dụng RelayCommand từ Josh Smith's excellent MVVM article:

public class MyViewModel : INotifyPropertyChanged 
{ 
    private readonly ICommand mutateCommand; 
    private Thing thing; 

    public MyViewModel() 
    { 
     this.mutateCommand = new RelayCommand(this.Mutate); 
    } 

    public ICommand MutateCommand 
    { 
     get { return this.mutateCommand; } 
    } 

    public Thing Thing 
    { 
     get { return this.thing; } 
     set 
     { 
      this.thing = value; 
      // raise PropertyChanged event here... 
     } 
    } 

    private void Mutate(object parameter) 
    { 
     this.Thing = new Thing(); 
    } 
} 

Sau khi bạn gọi myVM.MutateCommand.Execute(new object()); bạn có thể truy cập vào các giá trị mới của myVM.Thing.

+0

Cảm ơn. Tôi đã nghĩ về điều này. Trên thực tế ví dụ của tôi không phải là lớn nhất.Những gì tôi thực sự cố gắng làm là có một đối tượng (Thing1) mà trang XAML của tôi bị ràng buộc, và sau đó nhấp vào một nút trên trang đó và có một điều thứ hai (Thing2 - cùng cấu trúc như Thing1, nhưng không phải Thing1) đã khởi tạo . Vì vậy, tôi có thể khai báo một Thing1 và Thing2 trong ViewModel của tôi. Khi Thing2 được tạo, trang bị ràng buộc cần trả lời bằng mã-đằng sau nghĩa là nó không đơn giản là một câu trả lời liên quan đến giao diện người dùng cần thiết. Bạn không chắc chắn cách lấy mã để trả lời sự kiện không phải giao diện người dùng này. –

+0

@ml_black: Không sử dụng mã sau; sử dụng ViewModels và cho phép Views chỉ phản ánh rằng ViewModels thay đổi. Giao tiếp chỉ có một cách. Đó là một cách tiếp cận sạch hơn nhiều. –

+0

Tôi đồng ý. Nhưng ứng dụng gọi điện không sử dụng ViewModels. Và ViewModel này dành cho nhiều ứng dụng gọi điện. Vì vậy, trong trường hợp này, thông tin từ Thing2 phải được tiêu thụ bởi từng ứng dụng gọi theo cách riêng của nó. Thư viện là hoàn toàn MVVM. –

1

Cách tiếp cận lý tưởng là để xác định một lớp mới kế thừa từ ICommand như sau:

public abstract class Command2<T1, T2> : ICommand { 
    public abstract T2 Execute2(T1 parameter); 
} 

public class DelegateCommand2<T1, T2> : Command2<T1, T2> { 
    public DelegateCommand2(Func<T1, T2> execute, Predicate<T1> canExecute) { 
     _execute = execute; 
     _canExecute = canExecute; 
    } 

    public override T2 Execute2(T1 parameter) { 
     if (CanExecute(parameter) == false) 
      return default(T2); 
     else 
      return _execute((T1)parameter); 
    } 
} 

Lưu ý rằng Execute2 trả về giá trị giống như một hàm bình thường. Đây là cách sử dụng.

private readonly ICommand _commandExample = new DelegateCommand2<int, Point3D>(
     commandExample_Executed, 
     commandExample_CanExecute 
    ); 

    public Command2<int, Point_3D> CommandExample { 
     get { 
      return (Command2<int, Point_3D>) _commandExample; 
     } 
    } 

    private static Point3D commandExample_Executed(int index) { 
     return Fun1(index); //Fun1 returns a Point_3D 
    } 

    private static bool commandExample_CanExecute(int index) { 
     return true; 
    } 

Cuộc gọi Execute2 thay vì Thực thi sẽ trả về giá trị.

Các vấn đề liên quan