2011-05-06 18 views
16

Tôi đã bối rối vì điều này một thời gian. Tôi đang viết một ứng dụng WPF RibbonWindow WPF lớn bằng cách sử dụng mẫu MVVM. Màn hình có một menu RibbonBar dọc theo đầu và phần còn lại của nó hiển thị các Chế độ xem khác nhau. Một số Chế độ xem có chứa các Chế độ xem khác và một số trong số đó có các nút khởi chạy Windows con.Sử dụng MVVM trong WPF, tôi có nên khởi chạy cửa sổ con từ Xem mã phía sau hoặc ViewModel không?

Cho đến giờ, tôi đã thực hiện việc này từ mã Xem phía sau tệp nhưng tôi biết rằng các tệp này được cho là trống khi sử dụng MVVM. Tôi có thể di chuyển mã khởi động cửa sổ con đến ViewModel, nhưng sau đó tôi sẽ cần một tham chiếu đến chính RibbonWindow (để đặt làm chủ sở hữu cửa sổ con) và điều đó có vẻ không đúng.

Bất kỳ lời khuyên hoặc mẹo nào về cách thức này thường đạt được bằng cách sử dụng MVVM sẽ được đánh giá cao.

+4

Tôi không đồng ý rằng Xem mã phía sau tệp "phải trống". Mặc dù có rất nhiều điều KHÔNG nên ở trong mã đằng sau nó vẫn có giá trị. Tôi sử dụng nó cho bất cứ điều gì cụ thể cho lớp Xem, chẳng hạn như quản lý Focus điều khiển. Tôi cũng sử dụng nó để mở Windows tiếp theo trong WPF. –

+1

+1 cho Joel. Triển khai MVVM có nghĩa là mã VIEW SPECIFIC là mã CHỈ phải nằm trong mã phía sau. ViewModel của bạn không nên xử lý những thứ như thay đổi trạng thái của VSM (trừ khi, có lẽ, những thay đổi này được điều khiển dữ liệu, trong trường hợp này tôi sẽ bọc nó trong một hành vi hoặc trình kích hoạt tiếp xúc ở cấp VM) –

+0

Cảm ơn ý kiến ​​của bạn. .. họ đã thực sự xóa một số thứ cho tôi. – Sheridan

Trả lời

19

Tôi thường xử lý việc này bằng cách tạo một số loại WindowViewLoaderService. Khi chương trình của bạn khởi bạn đăng ký của Window và ViewModels của bạn với mã một cái gì đó như thế này:

WindowViewLoaderService.Register(TypeOf(MainWindowView), TypeOf(MainWindowViewModel); 
WindowViewLoaderService.Register(TypeOf(MyWindowView), TypeOf(MyWindowViewModel); 

Sau đó, khi bạn có thể ví dụ gọi vào dịch vụ này từ ViewModel của bạn và tất cả các bạn phải tham khảo là ViewModel khác của bạn. Ví dụ, nếu bạn đang ở trong MainWindowViewModel của bạn, bạn có thể có mã như thế này:

var myChildWindowVM = new MyWindowViewModel(); 
WindowViewLoaderService.ShowWindow(myChildWindowVM) 

Các WindowViewLoaderService sau đó sẽ tìm kiếm những gì Xem được kết hợp với ViewModel định bạn thông qua nó. Nó sẽ tạo ra View đó, thiết lập DataContext của nó tới ViewModel mà bạn đã truyền vào, và sau đó hiển thị View.

Bằng cách này, Chế độ xem của bạn không bao giờ biết về bất kỳ Chế độ xem nào.

Bạn có thể cuộn một trong các dịch vụ của riêng mình một cách dễ dàng. Tất cả những gì cần làm là giữ một từ điển với khóa là ViewModelType của bạn và giá trị là ViewType của bạn. Phương thức Register bổ sung vào từ điển của bạn và phương thức ShowWindow tra cứu khung nhìn chính xác dựa trên ViewModel được truyền vào, tạo khung nhìn, thiết lập DataContext, và sau đó gọi Show trên đó.

Hầu hết các khung MVVM cung cấp một cái gì đó như thế này cho bạn ra khỏi hộp. Ví dụ, Caliburn có một cái slick chỉ sử dụng quy ước đặt tên được gọi là ViewLocator trong khung công tác này. Dưới đây là một liên kết mà tóm tắt: http://devlicio.us/blogs/rob_eisenberg/archive/2010/07/04/mvvm-study-segue-introducing-caliburn-micro.aspx

Cinch mặt khác gọi đó là một WPFUIVisualizerService mà bạn có thể nhìn thấy trong hành động ở đây: http://www.codeproject.com/KB/WPF/CinchIII.aspx

Những sẽ giúp bạn có được lăn.

+1

+1 Cảm ơn phản hồi chi tiết của bạn. Mặc dù tôi thấy cách tiếp cận này thú vị, ứng dụng của tôi đã khá phát triển. Các khung nhìn được liên kết với các ViewModels bằng cách sử dụng 'DataTemplate'' Resources' và 'ContentControl' có chứa các thuộc tính 'Content' của chúng được liên kết với các thuộc tính ViewModel trong các ViewModels khác. Nó sẽ là rất nhiều công việc để thay đổi điều này, nhưng nó không nằm ngoài câu hỏi ... nếu chỉ có nhiều thời gian hơn trong một ngày! – Sheridan

+0

Chỉ để bạn biết nó không phải là một hoặc cách tiếp cận khác thường. Tôi hầu như luôn luôn sử dụng DataTemplates để làm điều này là tốt. Tuy nhiên, như bạn đã chỉ ra - điều này không hiệu quả khi bạn cần mở một cửa sổ mới (hoặc Hộp thoại cho vấn đề đó). Khi bạn nghĩ về những gì bạn đang làm với một DataTemplate là điều tương tự bạn làm với một ViewLocator. Bạn về cơ bản "đăng ký" một ViewModel để xem dựa trên DataType của nó ... anyways chỉ muốn bạn biết tôi nghĩ rằng bạn đang làm nó một cách chính xác vấn đề duy nhất là khi DataTemplates không thể được sử dụng. –

+0

Cảm ơn nhận xét bổ sung đó - Tôi nghĩ rằng tôi chắc chắn sẽ xem xét thêm điều này. – Sheridan

0

Trong trường hợp này, Chế độ xem sẽ xử lý việc mở cửa sổ con. Tuy nhiên, ViewModel có thể thúc đẩy việc tạo các cửa sổ, nhưng gọi vào Chế độ xem để tạo Windows mới. Điều này sẽ tiết kiệm được logic của mẫu MVVM: ViewModel có "bộ não" nhưng không liên quan đến việc tạo cửa sổ cụ thể.

+0

Nhưng chế độ xem mở một cửa sổ 'cửa sổ' mới như thế nào? – Sheridan

5

Vâng, một nhận xét để bắt đầu là, "Không có mã AT TẤT CẢ trong mã-đằng sau" thực sự là một "huyền thoại". Nếu bạn muốn thực dụng, và bạn thấy rằng có một số mã (càng ít càng tốt sẽ tốt hơn), sẽ làm cho cuộc sống của bạn dễ dàng hơn và giải quyết vấn đề của bạn, sau đó bạn nên đi với điều đó.

Tuy nhiên, trong tình huống này, thực sự có một số cách kết hợp lỏng lẻo để thực hiện việc này. Bạn có thể có một dịch vụ tương tác với bạn.Bạn bắt đầu tương tác với người dùng từ ViewModel, dịch vụ sẽ xử lý điều đó (bằng cách hiển thị ChildWindow chẳng hạn) và cung cấp cho bạn trở lại phản hồi của người dùng. Dịch vụ đó có thể được chế nhạo để thử nghiệm dễ dàng. Và nó có thể được kiểm tra một cách riêng biệt.

Tức là, nếu bạn muốn tự mình làm mọi thứ. Nếu bạn muốn một khung làm việc nâng hạng nặng cho bạn, bạn có thể kiểm tra chức năng InteractionRequest được cung cấp bởi Prism. Đây là bài viết MSDN nói về adanced MVVM scenarios bao gồm một phần trên User Interaction Patterns. Đó là cách tôi làm điều đó, và nó khá đơn giản, thanh lịch và đơn giản.

Hy vọng điều này sẽ giúp ích:

+1

+1 Cảm ơn nhận xét và liên kết hữu ích của bạn. Tôi thực sự điều tra Prism một thời gian trước và thấy rằng tôi không cần những gì nó cung cấp và quyết định viết một khung nhẹ tùy chỉnh thay vì ... vẫn cố gắng để có được nó mặc dù. – Sheridan

+0

Rất vui được trợ giúp. Chúc may mắn với khung của bạn;) – AbdouMoumen

3

Để nhận câu trả lời của Matt thêm một bước nữa, bạn có thể có tất cả chế độ xem là điều khiển người dùng. Sau đó tạo một ViewContainer, một cửa sổ với các mẫu dữ liệu của bạn (như bạn đã mô tả).

Sau đó, bạn chỉ chuyển chế độ xem bạn muốn mở sang dịch vụ cửa sổ, thiết lập DataContext. Sau đó, dịch vụ sẽ mở cửa sổ và bộ kiểm soát nội dung sẽ giải quyết chế độ xem chính xác cho chế độ xem.

Điều này có nghĩa là tất cả đăng ký được thực hiện trong XAML và dịch vụ cửa sổ chỉ biết cách thực hiện điều đó ... cửa sổ mở và đóng.

+0

+1 Cảm ơn bạn đã làm rõ điều đó. – Sheridan

1

Đây là một bài đăng cũ, nhưng có thể điều này sẽ giúp ai đó trên đường đi: Tôi sử dụng MVVM và tăng sự kiện để mở cửa sổ con từ ViewModel quay lại Chế độ xem. Mã duy nhất phía sau là xử lý sự kiện, mở cửa sổ, thiết lập chủ sở hữu của cửa sổ con và đó là khá nhiều nó. Trong viewmodel, nếu eventhandler là null, thì nó không được đăng ký bởi view và không kích hoạt. VM không biết về khung nhìn. Mã này khá đơn giản và chỉ mất một vài dòng.

0

Chế độ xemMô hình chỉ được sử dụng để trình bày trạng thái hệ thống và logic giao diện người dùng. Một chế độ xem có thể được tham chiếu bởi nhiều chế độ xem. Nó không có kiến ​​thức về mã UI cụ thể như mối quan hệ cha mẹ/con, vị trí, bố trí, kích thước, vv Vì vậy, tốt hơn là bật cửa sổ con trong mã của khung nhìn phía sau với sự kiện hoặc sự kiện lệnh và sự kiện đối số của ViewModel đã thay đổi. Bằng cách này, bạn có thể chỉ định cái nào là chế độ xem gốc trong lớp Giao diện người dùng.

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