Ai nên kiểm soát điều hướng trong ứng dụng MVVM?


33

Ví dụ # 1: Tôi có chế độ xem được hiển thị trong ứng dụng MVVM của mình (hãy sử dụng Silverlight cho mục đích thảo luận) và tôi nhấp vào nút sẽ đưa tôi đến một trang mới.

Ví dụ # 2: Cùng một chế độ xem có một nút khác, khi được nhấp, sẽ mở ra một chế độ xem chi tiết trong cửa sổ con (hộp thoại).

Chúng tôi biết rằng sẽ có các đối tượng Lệnh được hiển thị bởi ViewModel của chúng tôi được liên kết với các nút bằng các phương thức đáp ứng với nhấp chuột của người dùng. Nhưng, sau đó thì sao? Làm thế nào để chúng ta hoàn thành hành động? Ngay cả khi chúng ta sử dụng cái gọi là NavigationService, chúng ta sẽ nói gì với nó?

Cụ thể hơn, trong một mô hình Chế độ xem đầu tiên truyền thống (như các lược đồ điều hướng dựa trên URL như trên web hoặc khung điều hướng tích hợp SL), các đối tượng Lệnh sẽ phải biết Chế độ xem nào sẽ hiển thị tiếp theo. Điều đó dường như vượt qua ranh giới khi nói đến sự tách biệt các mối quan tâm được thúc đẩy bởi mô hình.

Mặt khác, nếu nút không được nối với đối tượng Command và hoạt động như một siêu liên kết, các quy tắc điều hướng có thể được xác định trong đánh dấu. Nhưng chúng tôi có muốn Chế độ xem kiểm soát luồng ứng dụng và không điều hướng chỉ là một loại logic kinh doanh khác? (Tôi có thể nói có trong một số trường hợp và không trong những trường hợp khác.)

Đối với tôi, việc triển khai mô hình MVVM không tưởng (và tôi đã nghe người khác tuyên bố điều này) sẽ có ViewModel có dây theo cách mà ứng dụng có thể chạy không đầu (tức là không có Chế độ xem). Điều này cung cấp diện tích bề mặt nhất để kiểm tra dựa trên mã và làm cho Chế độ xem thực sự trên ứng dụng. Và ViewModel của tôi không nên quan tâm nếu nó hiển thị trong cửa sổ chính, bảng điều khiển nổi hoặc cửa sổ con, phải không?

Theo apprach này, tùy thuộc vào một số cơ chế khác trong thời gian chạy để 'liên kết' những gì View sẽ được hiển thị cho mỗi ViewModel. Nhưng nếu chúng ta muốn chia sẻ View với nhiều ViewModels hoặc ngược lại thì sao?

Vì vậy, cần phải quản lý mối quan hệ View-ViewModel để chúng tôi biết phải hiển thị gì khi cùng với nhu cầu điều hướng giữa các khung nhìn, bao gồm hiển thị các cửa sổ / hộp thoại con, làm thế nào để chúng tôi thực sự thực hiện điều này trong mẫu MVVM?

Câu trả lời:


21

Điều hướng phải luôn được xử lý trong ViewModel.

Bạn đang đi đúng hướng với suy nghĩ rằng việc triển khai hoàn hảo mẫu thiết kế MVVM có nghĩa là bạn có thể chạy ứng dụng của mình hoàn toàn mà không cần Chế độ xem và bạn không thể làm điều đó nếu Chế độ xem của bạn kiểm soát Điều hướng của bạn.

Tôi thường có một ApplicationViewModel, hoặc ShellViewModel, xử lý trạng thái chung của ứng dụng của tôi. Điều này bao gồm CurrentPage(đó là ViewModel) và mã để xử lý ChangePageEvents. (Nó cũng thường được sử dụng cho các đối tượng toàn ứng dụng khác, chẳng hạn như CurrentUser hoặc ErrorMessages)

Vì vậy, nếu bất kỳ ViewModel, bất cứ nơi nào, phát sóng a ChangePageEvent(new SomePageViewModel), ShellViewModelsẽ lấy thông báo đó và chuyển sang CurrentPagebất kỳ trang nào được chỉ định trong tin nhắn.

Tôi thực sự đã viết một bài đăng blog về Điều hướng với MVVM nếu bạn quan tâm


2
Cách tiếp cận thú vị. Bốn nhận xét: 1) Silverlight không hỗ trợ thuộc tính DataType trên DataTemplate nên việc ánh xạ DataTemplate sang ViewModel là không thể trong SL. 2) Điều này không giải quyết các khả năng nhiều-nhiều giữa Chế độ xem và Chế độ xem. 3) Nó không xử lý các cửa sổ con (hoặc ít nhất là tôi không thấy cách nào). 4) Nó đòi hỏi sự kết hợp chặt chẽ giữa Ứng dụng / Shell ViewModel của bạn và đó là con cái (cháu, v.v.) Nếu tôi có 40 trang trong ứng dụng của mình, ViewModel này sẽ rất khó quản lý.
SonOfPirate

Điều đó nói rằng, nó chắc chắn là một cái gì đó để xem xét.
SonOfPirate

@SonOfPirate 1) Silverlight không hỗ trợ ánh xạ ẩn DataTemplate ẩn (tuy nhiên), tuy nhiên, nó hỗ trợ a DataTemplateSelector, đó là những gì tôi thường sử dụng cho các ứng dụng Silverlight. 2) Tôi đã sử dụng điều này trong nhiều tình huống trước đây. Ví dụ: một ViewModel có thể có nhiều Chế độ xem hoặc một Chế độ xem có thể được liên kết với nhiều ViewModels. Để biết ví dụ về cái trước, xem rachel53461.wordpress.com/2011/05/28/ . Để sau này, bạn chỉ cần xác định rằng nhiều bản đồ ViewModels cho cùng một chế độ xem trong DataTemplateSelector của bạn.
Rachel

3) Đó chỉ là một ví dụ cơ bản. Nếu bạn biết ứng dụng của mình sẽ có nhiều cửa sổ, rõ ràng bạn sẽ thay đổi ShellViewModel để xử lý nhiều CurrentPages4) Một lần nữa, đó chỉ là một ví dụ cơ bản. Trong thực tế, PageViewModels của tôi đều dựa trên một số lớp cơ sở, vì vậy ShellViewModel của tôi chỉ hoạt động với lớp cơ sở hoặc giao diện, chẳng hạn như IPageViewModel. Phần thực sự của bản đồ lộn xộn lớn nhất là DataTemplateSelector sẽ phải ánh xạ 40 Lượt xem thành 40 ViewModels.
Rachel

@SonOfPirate Tôi hy vọng rằng đã trả lời một số câu hỏi của bạn. Vui lòng tìm tôi trong Trò chuyện nếu bạn có người khác :)
Rachel

6

Vì lợi ích của việc đóng cửa, tôi nghĩ rằng tôi sẽ đăng hướng mà cuối cùng tôi đã chọn để giải quyết vấn đề này.

Quyết định đầu tiên là tận dụng khung Điều hướng Trang Silverlight được cung cấp ngoài luồng. Quyết định này dựa trên một số yếu tố bao gồm kiến ​​thức rằng loại điều hướng này đang được Microsoft chuyển sang ứng dụng Windows 8 Metro và phù hợp với điều hướng trong ứng dụng Điện thoại 7.

Để làm cho nó hoạt động, tiếp theo tôi đã xem xét công việc mà ASP.NET MVC đã thực hiện với điều hướng dựa trên quy ước. Điều khiển khung sử dụng URI để định vị 'trang' để hiển thị. Sự giống nhau này tạo cơ hội sử dụng cách tiếp cận dựa trên quy ước tương tự trong ứng dụng Silverlight. Thủ thuật là làm cho tất cả hoạt động cùng nhau theo cách MVVM.

Giải pháp là Dịch vụ Điều hướng. Dịch vụ này hiển thị một số phương thức, chẳng hạn như NavigateTo và Back, mà ViewModels có thể sử dụng để bắt đầu thay đổi trang. Khi một trang mới được yêu cầu, NavigationService sẽ gửi CurrentPageChangedMessage bằng tính năng MVVMLight Messenger.

Khung nhìn chứa điều khiển Khung có ViewModel riêng được đặt là DataContext đang lắng nghe thông báo này. Khi nhận được, tên của chế độ xem mới được đặt thông qua chức năng ánh xạ áp dụng quy tắc quy ước của chúng tôi và được đặt thành thuộc tính CurrentPage. Thuộc tính Nguồn của điều khiển Khung được liên kết với thuộc tính CurrentPage. Kết quả là, thiết lập thuộc tính cập nhật Nguồn và kích hoạt điều hướng.

Quay trở lại Dịch vụ Điều hướng. Phương thức NavigateTo chấp nhận tên của trang đích. Để đảm bảo rằng ViewModels không có mối quan tâm về UI, tên được sử dụng là tên của ViewModel để hiển thị. Tôi thực sự đã tạo ra một bảng liệt kê có một trường cho mỗi ViewModel có thể điều hướng như một người trợ giúp và để loại bỏ các chuỗi ma thuật trên tất cả các ứng dụng. Hàm ánh xạ mà tôi đã đề cập ở trên sẽ loại bỏ hậu tố "ViewModel" khỏi tên, nối "Trang" vào tên và đặt tên đầy đủ thành "Lượt xem {Tên} Trang.xaml".

Vì vậy, ví dụ, để điều hướng đến chế độ xem chi tiết khách hàng, tôi có thể gọi:

NavigationService.NavigateTo(ViewModels.CustomerDetails);

Giá trị của CustomerDetails là "CustomerDetailsViewModel" được ánh xạ tới "Views \ CustomerDetailsPage.xaml".

Cái hay của phương pháp này là UI được tách rời hoàn toàn khỏi ViewModels nhưng chúng tôi có hỗ trợ điều hướng đầy đủ. Bây giờ tôi có thể nối lại ứng dụng của mình và bất cứ khi nào tôi thấy phù hợp mà không có bất kỳ thay đổi mã nào.

Hy vọng lời giải thích giúp.


2

Tương tự như những gì Rachel nói, ứng dụng chủ yếu là MVVM của tôi có chức Presenternăng xử lý các chuyển đổi giữa các cửa sổ hoặc trang. Rachel gọi đây là một ApplicationViewModel, nhưng theo kinh nghiệm của tôi, nó thường phải làm nhiều hơn là chỉ là một mục tiêu ràng buộc (như nhận tin nhắn, tạo Windows, v.v.) để về mặt kỹ thuật giống như truyền thống Presenterhoặc Controller.

Trong ứng dụng của tôi, tôi Presenterbắt đầu với một CurrentViewModel. Các Presenterchặn tất cả các giao tiếp giữa ViewViewModel. Một trong những điều ViewModelcó thể làm trong quá trình tương tác là trả lại một trang mới ViewModel, có nghĩa là một trang mới hoặc một trang mới Windowsẽ được hiển thị. Việc Presenterchăm sóc tạo hoặc ghi đè lên Viewcái mới ViewModelvà thiết lập DataContext.

Kết quả của một hành động cũng có thể ViewModellà "hoàn thành", trong trường hợp đó Presenterphát hiện ra điều này và đóng cửa sổ, hoặc bật nó ViewModelra khỏi ngăn xếp VM và quay lại hiển thị trang trước đó.


Làm thế nào để Người thuyết trình biết Chế độ xem hiển thị?
SonOfPirate

1
@SonOfPirate - Điều này thường được thực hiện thông qua các cơ chế WPF. Chỉ Presentercần trả lại ViewModelcây trong hình ảnh trực quan và WPF lấy cái thích hợp View, móc lên DataContextvà đặt nó vào cây thị giác thay thế. Bạn có thể làm điều này bằng cách sử dụng DataTemplates khai báo ViewModelloại chúng hiển thị hoặc bạn có thể tạo bộ chọn mẫu dữ liệu tùy chỉnh. Điều đó vẫn nằm trong lĩnh vực của các tính năng WPF.
Scott Whitlock
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.