ViewModelLocator là gì và ưu / nhược điểm của nó so với DataTemplates là gì?


112

Ai đó có thể cung cấp cho tôi bản tóm tắt nhanh về ViewModelLocator là gì, nó hoạt động như thế nào và ưu / nhược điểm của việc sử dụng nó so với DataTemplates được không?

Tôi đã thử tìm kiếm thông tin trên Google nhưng có vẻ như có nhiều cách triển khai khác nhau và không có danh sách chi tiết nào về nó là gì và ưu / nhược điểm của việc sử dụng nó.

Câu trả lời:


204

Giới thiệu

Trong MVVM, cách thực hành thông thường là để các View tìm thấy các ViewModels của chúng bằng cách phân giải chúng từ vùng chứa phụ thuộc (DI). Điều này xảy ra tự động khi vùng chứa được yêu cầu cung cấp (giải quyết) một thể hiện của lớp View. Vùng chứa đưa ViewModel vào View bằng cách gọi một hàm tạo của View chấp nhận tham số ViewModel; lược đồ này được gọi là nghịch đảo điều khiển (IoC).

Lợi ích của DI

Lợi ích chính ở đây là vùng chứa có thể được định cấu hình tại thời điểm chạy với hướng dẫn về cách giải quyết các loại mà chúng tôi yêu cầu từ nó. Điều này cho phép khả năng kiểm tra cao hơn bằng cách hướng dẫn nó giải quyết các loại (Chế độ xem và Mô hình xem) mà chúng tôi sử dụng khi ứng dụng của chúng tôi thực sự chạy, nhưng hướng dẫn nó khác khi chạy các bài kiểm tra đơn vị cho ứng dụng. Trong trường hợp thứ hai, ứng dụng thậm chí sẽ không có giao diện người dùng (nó không chạy; chỉ là các bài kiểm tra) vì vậy vùng chứa sẽ giải quyết các mô phỏng thay cho các loại "bình thường" được sử dụng khi ứng dụng chạy.

Các vấn đề bắt nguồn từ DI

Cho đến nay, chúng tôi đã thấy rằng phương pháp DI cho phép dễ dàng kiểm tra ứng dụng bằng cách thêm một lớp trừu tượng lên trên việc tạo các thành phần ứng dụng. Có một vấn đề với cách tiếp cận này: nó không hoạt động tốt với các nhà thiết kế trực quan như Microsoft Expression Blend.

Vấn đề là trong cả chạy ứng dụng bình thường và chạy thử nghiệm đơn vị, ai đó phải thiết lập vùng chứa với hướng dẫn về những loại cần giải quyết; ngoài ra, ai đó phải yêu cầu vùng chứa phân giải Chế độ xem để các Mô hình xem có thể được đưa vào chúng.

Tuy nhiên, trong thời gian thiết kế không có mã của chúng tôi đang chạy . Nhà thiết kế cố gắng sử dụng phản chiếu để tạo các bản sao của Chế độ xem của chúng tôi, có nghĩa là:

  • Nếu phương thức khởi tạo View yêu cầu thể hiện ViewModel, nhà thiết kế sẽ không thể khởi tạo View - nó sẽ xảy ra lỗi theo một số cách được kiểm soát
  • Nếu Chế độ xem có một hàm tạo không tham số thì Chế độ xem sẽ được khởi tạo, nhưng nó DataContextsẽ nullnhư vậy, vì vậy chúng ta sẽ nhận được một chế độ xem "trống" trong trình thiết kế - điều này không hữu ích lắm

Nhập ViewModelLocator

ViewModelLocator là một phần trừu tượng bổ sung được sử dụng như sau:

  • Bản thân View khởi tạo ViewModelLocator như một phần tài nguyên của nó và liên kết dữ liệu DataContext của nó với thuộc tính ViewModel của bộ định vị
  • Bộ định vị bằng cách nào đó phát hiện nếu chúng ta đang ở chế độ thiết kế
  • Nếu không ở chế độ thiết kế, bộ định vị trả về một ViewModel mà nó phân giải từ vùng chứa DI, như đã giải thích ở trên
  • Nếu ở chế độ thiết kế, bộ định vị trả về một ViewModel "giả" cố định bằng cách sử dụng logic riêng của nó (hãy nhớ: không có vùng chứa trong thời gian thiết kế!); ViewModel này thường đi kèm với dữ liệu giả

Tất nhiên, điều này có nghĩa là View phải có một hàm tạo không tham số để bắt đầu (nếu không nhà thiết kế sẽ không thể khởi tạo nó).

Tóm lược

ViewModelLocator là một thành ngữ cho phép bạn giữ lợi ích của DI trong ứng dụng MVVM của mình đồng thời cho phép mã của bạn hoạt động tốt với các nhà thiết kế trực quan. Điều này đôi khi được gọi là "khả năng hòa trộn" của ứng dụng của bạn (đề cập đến Expression Blend).

Sau khi hiểu rõ những điều trên, hãy xem một ví dụ thực tế tại đây .

Cuối cùng, sử dụng các mẫu dữ liệu không phải là một giải pháp thay thế cho việc sử dụng ViewModelLocator, mà là một giải pháp thay thế cho việc sử dụng các cặp View / ViewModel rõ ràng cho các phần của giao diện người dùng của bạn. Thông thường, bạn có thể thấy rằng không cần xác định Chế độ xem cho Mô hình xem vì bạn có thể sử dụng mẫu dữ liệu thay thế.


4
+1 cho một lời giải thích tuyệt vời. Bạn có thể mở rộng thêm về Chế độ xem và Tài nguyên của nó không? Theo Tài nguyên, bạn có nghĩa là thuộc tính của Chế độ xem? Hoặc là? Bạn có liên kết với một ví dụ cụ thể cho mẫu này không?
Metro Smurf

@MetroSmurf: Liên kết của bạn nằm trong phần Tóm tắt.
Jon

1
Cảm ơn. Có bất kỳ hạn chế nào khi sử dụng ViewModelLocator không? Tôi có một số lo lắng về thực tế là nó tham chiếu đến một tài nguyên tĩnh - ViewModels có thể được tạo động trong thời gian chạy không? Và có rất nhiều mã bổ sung liên quan đến việc nối một mã không?
Rachel

@Rachel: Chính liên kết đó trong Tóm tắt sẽ trả lời những câu hỏi này bằng các ví dụ thực tế.
Jon

2
Câu trả lời cực kỳ sai lầm. Mục đích chính của View Model Locator không phải là cung cấp dữ liệu giả cho nhà thiết kế. Bạn có thể dễ dàng làm điều này bằng cách chỉ định d:DataContext="{d:DesignInstance MockViewModels:MockMainWindowModel, IsDesignTimeCreatable=True}". Mục đích của Bộ định vị là thực sự bật DI trên Chế độ xem, bởi vì WPF cung cấp nó rất tệ. Ví dụ: bạn có một Cửa sổ Chính mở một số Cửa sổ Hộp thoại. Để giải quyết DI trên Cửa sổ hộp thoại theo cách thông thường, bạn sẽ cần chuyển nó như một phần phụ thuộc vào Cửa sổ chính! Điều này tránh được với View Locator.
hyankov,

10

Một ví dụ về triển khai câu trả lời của @ Jon

Tôi có một lớp định vị mô hình chế độ xem. Mỗi thuộc tính sẽ là một thể hiện của mô hình chế độ xem mà tôi sẽ phân bổ trên chế độ xem của mình. Tôi có thể kiểm tra xem mã đang chạy ở chế độ thiết kế hay không sử dụng DesignerProperties.GetIsInDesignMode. Điều này cho phép tôi sử dụng mô hình giả trong thời gian thiết kế và đối tượng thực khi tôi đang chạy ứng dụng.

public class ViewModelLocator
{
    private DependencyObject dummy = new DependencyObject();

    public IMainViewModel MainViewModel
    {
        get
        {
            if (IsInDesignMode())
            {
                return new MockMainViewModel();
            }

            return MyIoC.Container.GetExportedValue<IMainViewModel>();
        }
    }

    // returns true if editing .xaml file in VS for example
    private bool IsInDesignMode()
    {
        return DesignerProperties.GetIsInDesignMode(dummy);
    }
}

Và để sử dụng nó, tôi có thể thêm công cụ định vị của mình vào App.xamltài nguyên:

xmlns:core="clr-namespace:MyViewModelLocatorNamespace"

<Application.Resources>
    <core:ViewModelLocator x:Key="ViewModelLocator" />
</Application.Resources>

Và sau đó để kết nối chế độ xem của bạn (ví dụ: MainView.xaml) vào mô hình xem của bạn:

<Window ...
  DataContext="{Binding Path=MainViewModel, Source={StaticResource ViewModelLocator}}">

có sự khác biệt nào trong việc sử dụng thisthay vì dummy?
Sebastian Xawery Wiśniowiecki

5

Tôi không hiểu tại sao các câu trả lời khác của câu hỏi này lại xoay quanh Nhà thiết kế.

Mục đích của View Model Locator là cho phép View của bạn khởi tạo điều này (vâng, View Model Locator = View First):

public void MyWindowViewModel(IService someService)
{
}

thay vì chỉ cái này:

public void MyWindowViewModel()
{
}

bằng cách khai báo điều này:

DataContext="{Binding MainWindowModel, Source={StaticResource ViewModelLocator}}"

Trường ViewModelLocatorlớp, là tài liệu tham khảo mà một IoC và đó là cách nó giải quyết các MainWindowModeltài sản đó cho thấy.

Nó không liên quan gì đến việc cung cấp các mô hình Mock view cho chế độ xem của bạn. Nếu bạn muốn điều đó, chỉ cần làm

d:DataContext="{d:DesignInstance MockViewModels:MockMainWindowModel, IsDesignTimeCreatable=True}"

Bộ định vị mô hình dạng xem là một trình bao bọc xung quanh một số (bất kỳ) vùng chứa Inversion of Control, chẳng hạn như Unity.

Tham khảo:


Bộ định vị mô hình chế độ xem không yêu cầu vùng chứa, người dùng quyết định cách mô hình chế độ xem được giải quyết thông qua cấu hình và bạn có thể sử dụng vùng chứa hoặc chỉ tự mình tạo mới một loại. Vì vậy, bạn có thể thực hiện vị trí mô hình chế độ xem dựa trên quy ước, chẳng hạn như thay vì đăng ký trước tất cả các chế độ xem và chế độ xem của bạn trong một số vùng chứa.
Chris Bordeman

Bạn đúng khi nói " Tôi không hiểu tại sao các câu trả lời khác [...] lại quấn quanh Nhà thiết kế " +1, nhưng quan điểm của bộ định vị là xóa khỏi chế độ xem mọi kiến ​​thức về cách thức của mô hình chế độ xem. được tạo ra, làm cho chế độ xem độc lập với sự khởi tạo này, để lại điều đó cho bộ định vị. Bộ định vị sẽ có thể cung cấp các hương vị khác nhau của mô hình chế độ xem, có thể một số tùy chỉnh được thêm vào thông qua các plugin mà bộ định vị sẽ quản lý (và một số cụ thể cho thời gian thiết kế). Chế độ xem sẽ không có bất kỳ quá trình nào trong quá trình định vị phiên bản chính xác của mô hình chế độ xem này, điều đó thực sự tốt cho SoC.
phút
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.