Các ví dụ hay về Mẫu MVVM


141

Tôi hiện đang làm việc với mẫu Microsoft MVVM và thấy thiếu các ví dụ chi tiết gây nản lòng. Ví dụ về Sổ liên lạc đi kèm cho thấy rất ít Xử lý lệnh và ví dụ khác tôi đã tìm thấy là từ một bài báo của Tạp chí MSDN, trong đó các khái niệm tương tự nhau nhưng sử dụng một cách tiếp cận hơi khác và vẫn không có sự phức tạp. Có bất kỳ ví dụ MVVM nào mà ít nhất hiển thị các hoạt động CRUD cơ bản và chuyển đổi hộp thoại / nội dung không?


Đề xuất của mọi người thực sự hữu ích và tôi sẽ bắt đầu tổng hợp danh sách các tài nguyên tốt

Khung / Mẫu

Bài viết hữu ích

Screencasts

Thư viện bổ sung


Tôi vui mừng vì những tài nguyên này đã giúp. Tôi hiện đang sử dụng ứng dụng MVVM sản xuất thứ hai của mình và sẽ tiếp tục thêm nội dung sẽ hữu ích cho những người bắt đầu khi tôi bắt gặp nó.
jwarzech

Câu trả lời:


59

Thật không may, không có một ứng dụng ví dụ MVVM tuyệt vời nào làm được mọi thứ và có rất nhiều cách tiếp cận khác nhau để thực hiện. Trước tiên, bạn có thể muốn làm quen với một trong các khung ứng dụng ngoài kia (Prism là một lựa chọn hợp lý), vì chúng cung cấp cho bạn các công cụ tiện lợi như tiêm phụ thuộc, chỉ huy, tổng hợp sự kiện, v.v để dễ dàng thử các mẫu khác nhau phù hợp với bạn .

Bản phát hành lăng kính:
http://www.codeplex.com/CompổngWPF

Nó bao gồm một ứng dụng ví dụ khá hay (nhà giao dịch chứng khoán) cùng với rất nhiều ví dụ nhỏ hơn và cách thực hiện. Ít nhất đó là một minh chứng tốt về một số mẫu con phổ biến mà mọi người sử dụng để làm cho MVVM thực sự hoạt động. Họ có ví dụ cho cả CRUD và hộp thoại, tôi tin thế.

Lăng kính không nhất thiết phải cho mọi dự án, nhưng đó là một điều tốt để làm quen.

CRUD: Phần này khá dễ, các ràng buộc hai chiều của WPF giúp dễ dàng chỉnh sửa hầu hết dữ liệu. Bí quyết thực sự là cung cấp một mô hình giúp dễ dàng thiết lập giao diện người dùng. Ít nhất bạn muốn đảm bảo rằng ViewModel (hoặc đối tượng kinh doanh) của bạn thực hiện INotifyPropertyChangedđể hỗ trợ ràng buộc và bạn có thể liên kết các thuộc tính thẳng với các điều khiển UI, nhưng bạn cũng có thể muốn thực hiện IDataErrorInfođể xác thực. Thông thường, nếu bạn sử dụng một số loại giải pháp ORM, thiết lập CRUD là một cách nhanh chóng.

Bài viết này cho thấy các thao tác đơn giản: http://dotnetslackers.com/articles/wpf/WPFDataBindingWithLINQ.aspx

Nó được xây dựng trên LinqToSql, nhưng điều đó không liên quan đến ví dụ - tất cả những gì quan trọng là các đối tượng kinh doanh của bạn triển khai INotifyPropertyChanged(những lớp do LinqToSql tạo ra). MVVM không phải là điểm của ví dụ đó, nhưng tôi không nghĩ nó quan trọng trong trường hợp này.

Bài viết này chứng minh xác thực dữ liệu
http://bloss.msdn.com/wpfsdk/archive/2007/10/02/data-validation-in-3-5.aspx

Một lần nữa, hầu hết các giải pháp ORM tạo ra các lớp đã triển khai IDataErrorInfovà thường cung cấp một cơ chế để dễ dàng thêm các quy tắc xác thực tùy chỉnh.

Hầu hết thời gian bạn có thể lấy một đối tượng (mô hình) được tạo bởi một số ORM và bọc nó trong ViewModel giữ nó và ra lệnh lưu / xóa - và bạn đã sẵn sàng liên kết UI trực tiếp với các thuộc tính của mô hình.

Khung nhìn sẽ trông giống như thế này (ViewModel có một thuộc tính Itemchứa mô hình, giống như một lớp được tạo trong ORM):

<StackPanel>
   <StackPanel DataContext=Item>
      <TextBox Text="{Binding FirstName, Mode=TwoWay, ValidatesOnDataErrors=True}" />
      <TextBox Text="{Binding LastName, Mode=TwoWay, ValidatesOnDataErrors=True}" />
   </StackPanel>
   <Button Command="{Binding SaveCommand}" />
   <Button Command="{Binding CancelCommand}" />
</StackPanel>

Hộp thoại: Hộp thoại và MVVM có một chút khó khăn. Tôi thích sử dụng hương vị của cách tiếp cận Người hòa giải với các hộp thoại, bạn có thể đọc thêm một chút về nó trong câu hỏi StackOverflow này:
ví dụ về hộp thoại WPVM MVVM

Cách tiếp cận thông thường của tôi, không phải là MVVM khá cổ điển, có thể được tóm tắt như sau:

Một lớp cơ sở cho hộp thoại ViewModel hiển thị các lệnh cho các hành động cam kết và hủy bỏ, một sự kiện để cho chế độ xem biết rằng một hộp thoại đã sẵn sàng để đóng và bất cứ điều gì khác bạn sẽ cần trong tất cả các hộp thoại của mình.

Một khung nhìn chung cho hộp thoại của bạn - đây có thể là một cửa sổ hoặc điều khiển loại lớp phủ "phương thức" tùy chỉnh. Về cốt lõi, nó là một trình dẫn nội dung mà chúng ta đổ viewmodel vào và nó xử lý hệ thống dây để đóng cửa sổ - ví dụ về thay đổi bối cảnh dữ liệu, bạn có thể kiểm tra xem ViewModel mới có được kế thừa từ lớp cơ sở của bạn không và nếu nó là, đăng ký vào sự kiện đóng có liên quan (trình xử lý sẽ gán kết quả hộp thoại). Nếu bạn cung cấp chức năng đóng phổ quát thay thế (ví dụ nút X), bạn cũng nên đảm bảo chạy lệnh đóng có liên quan trên ViewModel.

Ở đâu đó bạn cần cung cấp các mẫu dữ liệu cho ViewModels của mình, chúng có thể rất đơn giản đặc biệt vì bạn có thể có chế độ xem cho mỗi hộp thoại được gói gọn trong một điều khiển riêng. Mẫu dữ liệu mặc định cho ViewModel sau đó sẽ trông giống như thế này:

<DataTemplate DataType="{x:Type vmodels:AddressEditViewModel}">
   <views:AddressEditView DataContext="{Binding}" />
</DataTemplate>

Chế độ xem hộp thoại cần có quyền truy cập vào các giao diện này, vì nếu không, nó sẽ không biết cách hiển thị ViewModel, ngoài giao diện người dùng hộp thoại được chia sẻ, nội dung của nó về cơ bản là:

<ContentControl Content="{Binding}" />

Mẫu dữ liệu ẩn sẽ ánh xạ khung nhìn tới mô hình, nhưng ai khởi chạy nó?

Đây là phần không phải là mvvm. Một cách để làm điều đó là sử dụng một sự kiện toàn cầu. Những gì tôi nghĩ là một điều tốt hơn để làm là sử dụng một thiết lập loại trình tổng hợp sự kiện, được cung cấp thông qua tiêm phụ thuộc - theo cách này sự kiện là toàn cầu đối với một container chứ không phải toàn bộ ứng dụng. Prism sử dụng khung thống nhất cho ngữ nghĩa container và nội dung phụ thuộc, và nói chung tôi thích Unity khá nhiều.

Thông thường, sẽ hợp lý khi cửa sổ gốc đăng ký sự kiện này - nó có thể mở hộp thoại và đặt bối cảnh dữ liệu của nó thành ViewModel được truyền vào với một sự kiện được nêu ra.

Thiết lập điều này theo cách này cho phép ViewModels yêu cầu ứng dụng mở hộp thoại và trả lời các hành động của người dùng ở đó mà không biết gì về giao diện người dùng, do đó, phần lớn MVVM-ness vẫn hoàn tất.

Tuy nhiên, có những lúc, UI phải nâng các hộp thoại lên, điều này có thể khiến mọi thứ trở nên phức tạp hơn một chút. Xem xét ví dụ, nếu vị trí hộp thoại phụ thuộc vào vị trí của nút mở nó. Trong trường hợp này, bạn cần có một số thông tin cụ thể về giao diện người dùng khi bạn yêu cầu mở hộp thoại. Tôi thường tạo một lớp riêng chứa ViewModel và một số thông tin UI có liên quan. Thật không may một số khớp nối dường như không thể tránh khỏi ở đó.

Mã giả của trình xử lý nút làm tăng hộp thoại cần dữ liệu vị trí phần tử:

ButtonClickHandler(sender, args){
    var vm = DataContext as ISomeDialogProvider; // check for null
    var ui_vm = new ViewModelContainer();
    // assign margin, width, or anything else that your custom dialog might require
    ...
    ui_vm.ViewModel = vm.SomeDialogViewModel; // or .GetSomeDialogViewModel()
    // raise the dialog show event
}

Khung nhìn hộp thoại sẽ liên kết với dữ liệu vị trí và chuyển ViewModel được chứa vào bên trong ContentControl. Bản thân ViewModel vẫn không biết gì về UI.

Nói chung, tôi không sử dụng thuộc tính DialogResultreturn của ShowDialog()phương thức hoặc hy vọng luồng sẽ bị chặn cho đến khi hộp thoại được đóng lại. Một hộp thoại phương thức không chuẩn không phải lúc nào cũng hoạt động như vậy và trong môi trường tổng hợp, bạn thường không thực sự muốn một trình xử lý sự kiện chặn như thế. Tôi thích để ViewModels giải quyết vấn đề này - người tạo ViewModel có thể đăng ký các sự kiện liên quan của nó, đặt phương thức cam kết / hủy, v.v., do đó không cần phải dựa vào cơ chế UI này.

Vì vậy, thay vì dòng chảy này:

// in code behind
var result = somedialog.ShowDialog();
if (result == ...

Tôi sử dụng:

// in view model
var vm = new SomeDialogViewModel(); // child view model
vm.CommitAction = delegate { this.DoSomething(vm); } // what happens on commit 
vm.CancelAction = delegate { this.DoNothing(vm); } // what happens on cancel/close (optional)
// raise dialog request event on the container

Tôi thích nó theo cách này bởi vì hầu hết các hộp thoại của tôi là các điều khiển giả chế độ không chặn và thực hiện theo cách này có vẻ đơn giản hơn so với làm việc xung quanh nó. Dễ dàng để kiểm tra đơn vị là tốt.


Cảm ơn câu trả lời chi tiết! Gần đây tôi phát hiện ra rằng vấn đề lớn nhất của tôi là khi tôi cần giao tiếp với MainViewModel với các mô hình khung nhìn khác để xử lý luồng ứng dụng. Tuy nhiên, dường như MVVM + Mediator dường như là phương pháp phổ biến.
jwarzech

2
Người hòa giải chắc chắn giúp, mô hình tổng hợp sự kiện (Prism có triển khai tốt) cũng thực sự hữu ích khi khớp nối thấp là mục tiêu. Ngoài ra, chế độ xem chính của bạn thường có chế độ xem con riêng và không nên gặp sự cố khi giao tiếp với chúng. Bạn cần sử dụng một trình hòa giải hoặc / và trình tổng hợp sự kiện khi các khung nhìn con bạn cần tương tác với các mô-đun khác trong ứng dụng của bạn mà chúng không nhất thiết phải biết - bao gồm cả UI (ví dụ hộp thoại của tôi là về trường hợp cụ thể này).
Egor

1
Các hướng dẫn để làm việc với các hộp thoại và cửa sổ đã thực sự hữu ích. Tuy nhiên, tôi bị mắc kẹt với một vài vấn đề: 1. Làm thế nào để bạn đặt tiêu đề cửa sổ từ chế độ xem? 2. Làm thế nào để bạn đối phó với việc thiết lập cửa sổ chủ sở hữu?
djskinner

@Daniel Skinner: Tôi giả sử bạn đang nói về các hộp thoại ở đây, hãy sửa tôi nếu tôi sai. Tiêu đề hộp thoại chỉ là một thuộc tính khác và bạn có thể liên kết nó với bất cứ thứ gì bạn thích. Nếu bạn đã làm theo cách tiếp cận của tôi với lớp viewmodel của hộp thoại cơ sở (giả sử nó có thuộc tính tiêu đề), thì trong cửa sổ hộp thoại chung của bạn, bạn có thể sử dụng UI để UI ràng buộc để đặt tiêu đề thành {Binding Path = DataContext.Title, ElementName = NameOfContentPresenter}. Cửa sổ chủ sở hữu là một mẹo nhỏ hơn - nó có nghĩa là người hòa giải thực sự bật lên hộp thoại cần biết về chế độ xem ứng dụng gốc.
Egor

Trong thực tế, tôi lấy lại điều đó - bất kể bạn cấu trúc điều này như thế nào tại một thời điểm bất cứ ai thực sự bật lên hộp thoại cần phải có một tham chiếu đến cửa sổ / chế độ xem ứng dụng gốc. Lưu ý nơi tôi đã nói "Thông thường, sẽ rất hợp lý khi cửa sổ gốc đăng ký sự kiện này - nó có thể mở hộp thoại và đặt bối cảnh dữ liệu của nó thành viewmodel được truyền vào với một sự kiện được nêu ra." Đây là nơi bạn sẽ đặt chủ sở hữu.
Egor

6

Jason Dolinger đã tốt thu hình màn ảnh của MVVM. Giống như Egor đã đề cập, không có một ví dụ tốt. Họ là tất cả hơn. Hầu hết là các ví dụ MVVM tốt, nhưng không phải khi bạn gặp các vấn đề phức tạp. Mọi người đều có cách riêng của họ. Laurent Bugnion cũng có một cách tốt để giao tiếp giữa các chế độ xem. http://blog.galasoft.ch/archive/2009/09/27/mvvm-light-toolkit-mesbah-v2-beta.aspx Cinch cũng là một ví dụ điển hình. Paul Stigs có một bài viết tốt giải thích rất nhiều với khuôn khổ Magellan của mình.


3

Bạn đã nhìn vào Caliburn ? Mẫu ContactManager có rất nhiều thứ hay ho trong đó. Các mẫu WPF chung cũng cung cấp một cái nhìn tổng quan về các lệnh. Các tài liệu là khá tốt và các diễn đàn đang hoạt động. Khuyến nghị!




2

Dự án mẫu trong khung Cinch hiển thị các công cụ điều hướng và CRUD cơ bản. Đây là một ví dụ khá hay về việc sử dụng MVVM và bao gồm một bài viết gồm nhiều phần giải thích việc sử dụng và động lực của nó.


2

Tôi cũng chia sẻ trong sự thất vọng của bạn. Tôi đang viết một ứng dụng và tôi có 3 yêu cầu sau:

  • Mở rộng
  • WPF với MVVM
  • Ví dụ tương thích GPL

Tất cả những gì tôi tìm thấy là bit và miếng, vì vậy tôi mới bắt đầu viết nó tốt nhất có thể. Sau khi tôi hiểu được một chút, tôi nhận ra rằng có thể có những người khác (như mình) có thể sử dụng một ứng dụng tham chiếu, vì vậy tôi đã cấu trúc lại những thứ chung chung vào khung ứng dụng WPF / MVVM và phát hành nó theo LGPL. Tôi đặt tên nó là SoapBox Core . Nếu bạn truy cập trang tải xuống, bạn sẽ thấy nó đi kèm với một ứng dụng demo nhỏ và mã nguồn cho ứng dụng demo đó cũng có sẵn để tải xuống. Hy vọng bạn thấy rằng hữu ích. Ngoài ra, gửi email cho tôi tại scott {at} Soapboxautomation.com nếu bạn muốn biết thêm thông tin.

EDIT : Cũng đã đăng một bài viết CodeProject giải thích cách nó hoạt động.


2

Tôi đã viết một ví dụ MVVM đơn giản từ đầu về dự án mã ở đây là liên kết MVVM WPF từng bước . Nó bắt đầu từ một kiến ​​trúc 3 lớp đơn giản và tốt nghiệp bạn sử dụng một số khung như PRISM.

nhập mô tả hình ảnh ở đây


1

Ngay cả tôi cũng chia sẻ sự thất vọng cho đến khi tôi đưa vấn đề vào tay mình. Tôi bắt đầu IncEditor.

IncEditor ( http://inceditor.codeplex.com ) là một trình soạn thảo cố gắng giới thiệu các nhà phát triển cho WPF, MVVM & MEF. Tôi đã khởi động nó và quản lý để có được một số chức năng như hỗ trợ 'theme'. Tôi không phải là chuyên gia về WPF hoặc MVVM hoặc MEF vì vậy tôi không thể đặt nhiều chức năng trong đó. Tôi đưa ra một yêu cầu chân thành với các bạn để làm cho nó tốt hơn để những người chặt chẽ như tôi có thể hiểu nó tốt hơn.

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.