2011-06-21 44 views
17

Tôi đang làm việc phiên bản thứ hai của một ứng dụng, và là một phần của việc viết lại, tôi phải chuyển sang kiến ​​trúc MVVM. Tôi đang nhận được áp lực để đặt hoàn toàn mỗi bit của mã trong lớp mô hình xem - có C# trong mã phía sau tập tin được cau mày khi. (Tôi biết, tôi biết ... Tôi hiểu rằng mã phía sau không phải là một điều xấu, nhưng nó không phải là cuộc gọi của tôi thời gian này).Kết nối sự kiện WPF với ViewModel (đối với các lớp không phải lệnh)

Đối với các đối tượng thực hiện giao diện lệnh, thật dễ dàng. Tôi đã có thể tìm thấy một tấn thông tin về cách liên kết Lệnh của các đối tượng này với một ICommand trong mô hình khung nhìn. Vấn đề là đối với các đối tượng không có giao diện này, ví dụ:

<ListBox 
    x:Name="myListBox" 
    MouseDoubleClick="myCallbackFunction"> 

<!-- ... --> 

</ListBox> 

Tôi muốn biết cách liên kết sự kiện MouseDoubleClick cho Listbox với hàm myCallbackFunction, được triển khai trong mô hình chế độ xem. Điều này thậm chí có thể?

Cảm ơn!

+1

Câu hỏi trùng lặp http://stackoverflow.com/questions/939388/binding-commands-to-events –

Trả lời

8

Điều này không thể trực tiếp. Nó có thể được thực hiện thông qua một thuộc tính đính kèm hoặc hành vi, mặc dù nó vẫn sẽ là một chút khôn lanh để tìm và gọi phương thức thích hợp (điều này có thể được thực hiện thông qua Reflection khá dễ dàng).

Điều đó đang được nói, điều này thường được xử lý qua ICommand - Ví dụ: MVVM Light có hành vi tuyệt vời EventToCommand để ánh xạ bất kỳ sự kiện nào tới ICommand trên ViewModel. Ưu điểm của việc sử dụng ICommand là bạn vẫn có thể sử dụng DataBinding, vì ICommand được tiếp xúc như một thuộc tính.

1

Một cách có thể để xử lý các sự kiện trong mã phía sau và gọi phương thức thích hợp xem mô hình từ mã đằng sau

Bạn cũng có thể đi cho một số sẵn sàng thực hiện thư viện chỉ huy như this hướng dẫn được sử dụng ACB

4

Để trả lời trực tiếp câu hỏi của bạn, vui lòng tham khảo Why to avoid the codebehind in WPF MVVM pattern? Nó gợi ý hai điều có thể bạn muốn.

Tuy nhiên, tại sao bạn muốn ràng buộc MouseDoubleClick của ListBox với ICommand của bạn trong chế độ xem?

Cách khác là bạn viết phương thức trong một codebehind để đăng ký MouseDoubleClick. Nó không phải là xấu do sự thật của những điều sau đây.

  1. Databinding có ý nghĩa là tương tác giữa chế độ xem và chế độ xem. Ví dụ, khi người dùng nhập một số văn bản vào một TextBox, một viewmodel cũng được cập nhật. Ngược lại, nếu một viewmodel lấy dữ liệu từ một cơ sở dữ liệu, nó sẽ được hiển thị ở dạng xem. Tuy nhiên, nó không phải là trường hợp này mà ICommand trong viewmodel của bạn liên kết với khung nhìn.

  2. Tất nhiên, CanExcute của ICommand sẽ quan trọng đối với mô hình chế độ xem của bạn, nhưng trong nhiều trường hợp, nó không liên quan đến chế độ xem hoặc không liên quan. Trong trường hợp này, sự khác biệt giữa ràng buộc ICommand và việc viết codebehind là nơi sự kiện MouseDoubleClick được liên kết với một ICommand hoặc được đăng ký với một trình xử lý sự kiện.

+0

Sự kiện MouseDoubleClick trên ListBox chỉ là một ví dụ tồn tại trong mã di sản và tôi không thể giữ sự kiện cụ thể đó. Tuy nhiên, tôi muốn biết nếu có một cách để tránh mã phía sau cho bất kỳ sự kiện như thế này. Và mã của tôi hiện có một trình xử lý sự kiện đơn giản trong đoạn mã mà sau đó gọi một phương thức trong mô hình khung nhìn. Nhưng vì lý do chính trị tại văn phòng của tôi, tôi được hướng dẫn tìm cách tránh viết mã trong đoạn mã phía sau. – RobotNerd

+0

Như phần trên cùng của câu trả lời của tôi và @Reed Copsey cũng đã đề cập ở trên, có hai điều có thể bạn muốn sử dụng, đó là Thuộc tính đính kèm hoặc Hành vi. Chúng được mô tả tại [câu hỏi của tôi] (http://stackoverflow.com/questions/6421372/why-to-avoid-the-codebehind-in-wpf-mvvm-pattern). Tuy nhiên, tôi muốn biết lý do tại sao bạn được khuyến khích để tránh viết mã trong mã hehind. Tôi nghĩ rằng câu trả lời của @ slugster về [câu hỏi của tôi] (http://stackoverflow.com/questions/6421372/why-to-avoid-the-codebehind-in-wpf-mvvm-pattern) sẽ giúp bạn. –

+0

Lý do là logic nghiệp vụ cần được tách hoàn toàn khỏi HMI (tôi đang làm việc với "purists"). Tuy nhiên, tôi đã thử các giải pháp mà bạn đã liên kết ở trên, nhưng tôi vẫn chưa thể làm việc được. Mọi giải pháp tiềm năng đều kém thanh lịch hơn nhiều so với việc sử dụng mã phía sau làm trung gian. Tôi đã quyết định gắn bó với mã ban đầu của mình và xem liệu tôi có thể thúc đẩy điều đó thông qua bài đánh giá ngang hàng tiếp theo của tôi hay không. – RobotNerd

4

WPF hỗ trợ phần mở rộng đánh dấu trên các sự kiện như của .NET 4.5.Sử dụng khả năng đó, tôi thực hiện một phần mở rộng ràng buộc phương pháp cực kỳ linh hoạt và viết về nó ở đây:

http://www.singulink.com/CodeIndex/post/building-the-ultimate-wpf-event-method-binding-extension

có thể được sử dụng để liên kết với một phương pháp sử dụng đầy đủ cú pháp con đường bất động sản, hỗ trợ các ràng buộc và phần mở rộng đánh dấu khác như các đối số, và tự động định tuyến đến phương thức khớp với chữ ký của các đối số được cung cấp. Dưới đây là một số ví dụ sử dụng:

<!-- Basic usage --> 
<Button Click="{data:MethodBinding OpenFromFile}" Content="Open" /> 

<!-- Pass in a binding as a method argument --> 
<Button Click="{data:MethodBinding Save, {Binding CurrentItem}}" Content="Save" /> 

<!-- Another example of a binding, but this time to a property on another element --> 
<ComboBox x:Name="ExistingItems" ItemsSource="{Binding ExistingItems}" /> 
<Button Click="{data:MethodBinding Edit, {Binding SelectedItem, ElementName=ExistingItems}}" /> 

<!-- Pass in a hard-coded method argument, XAML string automatically converted to the proper type --> 
<ToggleButton Checked="{data:MethodBinding SetWebServiceState, True}" 
       Content="Web Service" 
       Unchecked="{data:MethodBinding SetWebServiceState, False}" /> 

<!-- Pass in sender, and match method signature automatically --> 
<Canvas PreviewMouseDown="{data:MethodBinding SetCurrentElement, {data:EventSender}, ThrowOnMethodMissing=False}"> 
    <controls:DesignerElementTypeA /> 
    <controls:DesignerElementTypeB /> 
    <controls:DesignerElementTypeC /> 
</Canvas> 

    <!-- Pass in EventArgs --> 
<Canvas MouseDown="{data:MethodBinding StartDrawing, {data:EventArgs}}" 
     MouseMove="{data:MethodBinding AddDrawingPoint, {data:EventArgs}}" 
     MouseUp="{data:MethodBinding EndDrawing, {data:EventArgs}}" /> 

<!-- Support binding to methods further in a property path --> 
<Button Content="SaveDocument" Click="{data:MethodBinding CurrentDocument.DocumentService.Save, {Binding CurrentDocument}}" /> 

Xem phương pháp mô hình chữ ký:

public void OpenFromFile(); 
public void Save(DocumentModel model); 
public void Edit(DocumentModel model); 

public void SetWebServiceState(bool state); 

public void SetCurrentElement(DesignerElementTypeA element); 
public void SetCurrentElement(DesignerElementTypeB element); 
public void SetCurrentElement(DesignerElementTypeC element); 

public void StartDrawing(MouseEventArgs e); 
public void AddDrawingPoint(MouseEventArgs e); 
public void EndDrawing(MouseEventArgs e); 

public class Document 
{ 
    // Fetches the document service for handling this document 
    public DocumentService DocumentService { get; } 
} 

public class DocumentService 
{ 
    public void Save(Document document); 
} 
+1

Đây là cách làm đúng đắn. – John

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