Model-View-Presenter trong WinForms


90

Tôi đang cố gắng triển khai phương pháp MVP lần đầu tiên bằng WinForms.

Tôi đang cố gắng hiểu chức năng của từng lớp.

Trong chương trình của tôi, tôi có một nút GUI mà khi nhấp vào sẽ mở ra một cửa sổ openfiledialog.

Vì vậy, bằng cách sử dụng MVP, GUI xử lý sự kiện nhấp vào nút và sau đó gọi Presenter.openfile ();

Trong presenter.openfile (), sau đó có nên ủy quyền việc mở tệp đó cho lớp mô hình hay không, hoặc vì không có dữ liệu hoặc logic nào để xử lý, nó có nên chỉ hành động theo yêu cầu và mở cửa sổ openfiledialog không?

Cập nhật: Tôi đã quyết định đưa ra một khoản tiền thưởng vì tôi cảm thấy mình cần hỗ trợ thêm về vấn đề này và tốt nhất là phù hợp với các điểm cụ thể của tôi bên dưới, để tôi có ngữ cảnh.

Được rồi, sau khi đọc MVP, tôi đã quyết định triển khai Chế độ xem thụ động. Một cách hiệu quả, tôi sẽ có một loạt các điều khiển trên Winform sẽ do Người trình bày xử lý và sau đó là các nhiệm vụ được ủy quyền cho (các) Model. Những điểm cụ thể của tôi như sau:

  1. Khi winform tải, nó phải có được dạng cây. Tôi có đúng khi nghĩ rằng dạng xem do đó nên gọi một phương thức chẳng hạn như: presenter.gettree (), điều này đến lượt nó sẽ ủy quyền cho mô hình, sẽ lấy dữ liệu cho chế độ xem dạng cây, tạo nó và cấu hình nó, trả về người thuyết trình, đến lượt nó sẽ chuyển đến chế độ xem mà sau đó sẽ chỉ định nó cho một bảng điều khiển?

  2. Điều này có giống nhau đối với bất kỳ điều khiển dữ liệu nào trên Winform không, vì tôi cũng có một chế độ xem dữ liệu?

  3. Ứng dụng của tôi, có một số lớp mô hình với cùng một lắp ráp. Nó cũng hỗ trợ kiến ​​trúc plugin với các plugin cần được tải khi khởi động. Chế độ xem có chỉ đơn giản gọi một phương thức trình bày, mà sau đó sẽ gọi một phương thức tải các plugin và hiển thị thông tin trong khung nhìn? Sau đó, cấp nào sẽ kiểm soát các tham chiếu plugin. Chế độ xem sẽ giữ các tham chiếu đến họ hoặc người trình bày?

  4. Tôi có đúng khi nghĩ rằng chế độ xem phải xử lý mọi thứ về bản trình bày, từ màu nút của chế độ xem dạng cây, đến kích thước lưới dữ liệu, v.v.?

Tôi nghĩ rằng chúng là mối quan tâm chính của tôi và nếu tôi hiểu dòng chảy nên làm như thế nào đối với những điều này, tôi nghĩ tôi sẽ ổn.


Liên kết này lostechies.com/derekgreer/2008/11/23/… giải thích một số phong cách của MVP. Nó có thể hữu ích ngoài câu trả lời xuất sắc của Johann.
ak3nat0n

Câu trả lời:


123

Đây là lời khiêm tốn của tôi về MVP và các vấn đề cụ thể của bạn.

Đầu tiên , bất kỳ thứ gì mà người dùng có thể tương tác hoặc chỉ được hiển thị đều là một chế độ xem . Các luật, hành vi và đặc điểm của dạng xem như vậy được mô tả bằng một giao diện . Giao diện đó có thể được triển khai bằng cách sử dụng giao diện người dùng WinForms, giao diện người dùng bảng điều khiển, giao diện người dùng web hoặc thậm chí không có giao diện người dùng nào (thường là khi thử nghiệm người thuyết trình) - việc triển khai cụ thể không quan trọng miễn là nó tuân theo luật của giao diện xem của nó .

Thứ hai , một chế độ xem luôn được kiểm soát bởi người trình bày . Luật, hành vi và đặc điểm của một người thuyết trình như vậy cũng được mô tả bằng một giao diện . Giao diện đó không quan tâm đến việc triển khai chế độ xem cụ thể miễn là nó tuân theo luật của giao diện chế độ xem của nó.

Thứ ba , vì người thuyết trình kiểm soát chế độ xem của nó, nên để giảm thiểu sự phụ thuộc, thực sự không có lợi gì khi chế độ xem biết bất cứ điều gì về người thuyết trình của nó. Có một hợp đồng đã đồng ý giữa người trình bày và chế độ xem và điều đó được nêu trong giao diện chế độ xem.

Ý nghĩa của Thứ ba là:

  • Người trình bày không có bất kỳ phương thức nào mà chế độ xem có thể gọi, nhưng chế độ xem có các sự kiện mà người trình bày có thể đăng ký.
  • Người thuyết trình biết quan điểm của nó. Tôi thích thực hiện điều này với phương pháp tiêm chất xây dựng trên người trình bày bê tông.
  • Chế độ xem không có ý tưởng gì về người trình bày đang kiểm soát nó; nó sẽ không bao giờ được cung cấp cho bất kỳ người thuyết trình nào.

Đối với vấn đề của bạn, phần trên có thể trông giống như thế này trong mã được đơn giản hóa một chút:

interface IConfigurationView
{
    event EventHandler SelectConfigurationFile;

    void SetConfigurationFile(string fullPath);
    void Show();
}

class ConfigurationView : IConfigurationView
{
    Form form;
    Button selectConfigurationFileButton;
    Label fullPathLabel;

    public event EventHandler SelectConfigurationFile;

    public ConfigurationView()
    {
        // UI initialization.

        this.selectConfigurationFileButton.Click += delegate
        {
            var Handler = this.SelectConfigurationFile;

            if (Handler != null)
            {
                Handler(this, EventArgs.Empty);
            }
        };
    }

    public void SetConfigurationFile(string fullPath)
    {
        this.fullPathLabel.Text = fullPath;
    }

    public void Show()
    {
        this.form.ShowDialog();        
    }
}

interface IConfigurationPresenter
{
    void ShowView();
}

class ConfigurationPresenter : IConfigurationPresenter
{
    Configuration configuration = new Configuration();
    IConfigurationView view;

    public ConfigurationPresenter(IConfigurationView view)
    {
        this.view = view;            
        this.view.SelectConfigurationFile += delegate
        {
            // The ISelectFilePresenter and ISelectFileView behaviors
            // are implicit here, but in a WinForms case, a call to
            // OpenFileDialog wouldn't be too far fetched...
            var selectFilePresenter = Gimme.The<ISelectFilePresenter>();
            selectFilePresenter.ShowView();
            this.configuration.FullPath = selectFilePresenter.FullPath;
            this.view.SetConfigurationFile(this.configuration.FullPath);
        };
    }

    public void ShowView()
    {
        this.view.SetConfigurationFile(this.configuration.FullPath);
        this.view.Show();
    }
}

Ngoài những điều trên, tôi thường có một IViewgiao diện cơ sở nơi tôi lưu trữ Show()và bất kỳ chế độ xem chủ sở hữu hoặc chế độ xem nào mà các chế độ xem của tôi thường được hưởng lợi.

Đối với câu hỏi của bạn:

1. Khi winform tải, nó phải có được dạng cây. Tôi có đúng khi nghĩ rằng do đó chế độ xem nên gọi một phương thức như: presenter.gettree (), điều này đến lượt nó sẽ ủy quyền cho mô hình, sẽ lấy dữ liệu cho chế độ xem dạng cây, tạo nó và định cấu hình nó, trả về người thuyết trình, đến lượt nó sẽ chuyển đến chế độ xem mà sau đó sẽ chỉ định nó cho một bảng điều khiển?

Tôi sẽ gọi IConfigurationView.SetTreeData(...)từ IConfigurationPresenter.ShowView(), ngay trước cuộc gọi tớiIConfigurationView.Show()

2. Điều này có giống nhau đối với bất kỳ điều khiển dữ liệu nào trên Winform không, vì tôi cũng có một datagridview?

Vâng, tôi sẽ gọi IConfigurationView.SetTableData(...)cho điều đó. Tùy thuộc vào chế độ xem để định dạng dữ liệu được cung cấp cho nó. Người trình bày chỉ cần tuân theo hợp đồng của chế độ xem rằng nó muốn dữ liệu dạng bảng.

3. Ứng dụng của tôi, có một số lớp mô hình với cùng một lắp ráp. Nó cũng hỗ trợ kiến ​​trúc plugin với các plugin cần được tải khi khởi động. Chế độ xem có chỉ đơn giản gọi một phương thức trình bày, mà sau đó sẽ gọi một phương thức tải các plugin và hiển thị thông tin trong chế độ xem? Sau đó, cấp nào sẽ kiểm soát các tham chiếu plugin. Chế độ xem sẽ giữ các tham chiếu đến họ hoặc người trình bày?

Nếu các plugin có liên quan đến chế độ xem, thì các chế độ xem phải biết về chúng chứ không phải người trình bày. Nếu tất cả đều là về dữ liệu và mô hình, thì chế độ xem sẽ không liên quan gì đến chúng.

4. Tôi có đúng khi nghĩ rằng dạng xem nên xử lý mọi thứ về bản trình bày, từ màu của nút dạng cây, đến kích thước lưới dữ liệu, v.v.?

Đúng. Hãy nghĩ về nó như người trình bày cung cấp XML mô tả dữ liệu và dạng xem lấy dữ liệu và áp dụng biểu định kiểu CSS cho nó. Nói một cách cụ thể, người thuyết trình có thể gọi IRoadMapView.SetRoadCondition(RoadCondition.Slippery)và chế độ xem sau đó hiển thị đường bằng màu đỏ.

Còn về dữ liệu cho các nút được nhấp?

5. Nếu khi tôi nhấp vào các sơ đồ hình cây, tôi có nên chuyển qua nút cụ thể cho người trình bày và sau đó từ đó người trình bày sẽ tìm ra dữ liệu mà nó cần và sau đó hỏi mô hình cho dữ liệu đó, trước khi trình bày trở lại khung nhìn?

Nếu có thể, tôi sẽ chuyển tất cả dữ liệu cần thiết để trình bày cái cây trong một khung cảnh trong một lần chụp. Nhưng nếu một số dữ liệu quá lớn để được chuyển ngay từ đầu hoặc nếu dữ liệu đó tự động và cần "ảnh chụp nhanh mới nhất" từ mô hình (thông qua trình trình bày), thì tôi sẽ thêm một cái gì đó tương tự event LoadNodeDetailsEventHandler LoadNodeDetailsvào giao diện xem, để Người trình bày có thể đăng ký nó, tìm nạp chi tiết của nút trong LoadNodeDetailsEventArgs.Node(có thể thông qua ID của nó ở một số loại) từ mô hình, để chế độ xem có thể cập nhật chi tiết nút được hiển thị của nó khi người ủy quyền trình xử lý sự kiện trả về. Lưu ý rằng có thể cần các mẫu không đồng bộ của điều này nếu việc tìm nạp dữ liệu có thể quá chậm đối với trải nghiệm người dùng tốt.


3
Tôi không nghĩ rằng bạn nhất thiết phải tách người xem và người trình bày. Tôi thường tách riêng mô hình và người trình bày, để người trình bày lắng nghe các sự kiện mô hình và hành động theo đó (cập nhật chế độ xem). Có người trình bày trong chế độ xem giúp giảm bớt sự giao tiếp giữa người xem và người thuyết trình.
kasperhj

11
@lejon: Bạn nói rằng Có một người dẫn chương trình trong giao diện giúp giảm bớt các thông tin liên lạc giữa view và người dẫn chương trình , nhưng tôi mạnh mẽ không đồng ý. Quan điểm của tôi là: Khi chế độ xem biết về người trình bày, thì đối với mỗi sự kiện chế độ xem, chế độ xem phải quyết định phương thức trình bày nàophương thức thích hợp để gọi. Đó là "2 điểm phức tạp", vì chế độ xem không thực sự biết sự kiện chế độ xem nào tương ứng với phương thức trình bày nào . Hợp đồng không ghi rõ điều đó.
Johann Gerell

5
@lejon: Mặt khác, nếu chế độ xem chỉ hiển thị sự kiện thực tế, thì bản thân người trình bày (người biết họ muốn làm gì khi một sự kiện chế độ xem xảy ra) chỉ cần đăng ký với nó để làm điều chính xác. Đó chỉ là "1 điểm phức tạp", mà trong cuốn sách của tôi hay gấp đôi "2 điểm phức tạp". Nói chung, ít khớp nối hơn có nghĩa là chi phí bảo trì ít hơn trong quá trình chạy của một dự án.
Johann Gerell

9
Tôi cũng có xu hướng sử dụng trình diễn đóng gói như được giải thích trong liên kết này lostechies.com/derekgreer/2008/11/23/… trong đó chế độ xem là chủ sở hữu duy nhất của người trình bày.
ak3nat0n

3
@ ak3nat0n: Đối với ba phong cách MVP được giải thích trong liên kết mà bạn cung cấp, tôi tin rằng câu trả lời này của Johann có thể phù hợp nhất với kiểu thứ ba có tên là Phong cách Người trình bày quan sát : "Lợi ích của phong cách Người trình bày quan sát là nó tách biệt hoàn toàn kiến ​​thức về Người trình bày khỏi Chế độ xem làm cho Chế độ xem ít bị ảnh hưởng bởi những thay đổi trong Người trình bày. "
DavidRR

11

Người trình bày, chứa tất cả logic trong chế độ xem, sẽ phản hồi với nút được nhấp như @JochemKempe nói . Trong điều kiện thực tế, trình xử lý sự kiện nhấp vào nút gọi presenter.OpenFile(). Người thuyết trình sau đó có thể xác định những gì nên làm.

Nếu nó quyết định rằng người dùng phải chọn một tệp, nó sẽ gọi trở lại chế độ xem (thông qua giao diện chế độ xem) và để chế độ xem, chứa tất cả các kỹ thuật giao diện người dùng, hiển thị OpenFileDialog. Đây là một điểm khác biệt rất quan trọng mà người thuyết trình không được phép thực hiện các thao tác gắn liền với công nghệ UI đang được sử dụng.

Sau đó, tệp đã chọn sẽ được trả lại cho người trình bày và tiếp tục logic của nó. Điều này có thể liên quan đến bất kỳ mô hình hoặc dịch vụ nào sẽ xử lý việc xử lý tệp.

Lý do chính để sử dụng mẫu MVP, imo là để tách công nghệ giao diện người dùng khỏi logic chế độ xem. Do đó, người trình bày sắp xếp tất cả logic trong khi khung nhìn giữ nó tách biệt khỏi logic giao diện người dùng. Điều này có tác dụng phụ rất tốt là làm cho người thuyết trình hoàn toàn có thể kiểm tra được đơn vị.

Cập nhật: vì người trình bày là hiện thân của logic được tìm thấy trong một chế độ xem cụ thể , mối quan hệ người trình bày - người trình bày IMO là mối quan hệ một đối một. Và đối với tất cả các mục đích thực tế, một thể hiện dạng xem (ví dụ như Biểu mẫu) tương tác với một thể hiện người trình bày và một thể hiện người trình bày chỉ tương tác với một thể hiện dạng xem.

Điều đó nói rằng, trong quá trình triển khai MVP của tôi với WinForms, người thuyết trình luôn tương tác với chế độ xem thông qua một giao diện đại diện cho các khả năng giao diện người dùng của chế độ xem. Không có giới hạn về chế độ xem nào triển khai giao diện này, do đó các "vật dụng" khác nhau có thể triển khai cùng một giao diện chế độ xem và sử dụng lại lớp trình bày.


Cảm ơn. Vì vậy, trong phương thức presenter.OpenFile (), nó không nên có mã để hiển thị openfiledialog? Thay vào đó, nó phải quay lại chế độ xem để hiển thị cửa sổ đó?
Darren Young

4
Đúng vậy, tôi sẽ không bao giờ để người thuyết trình mở hộp thoại trực tiếp, vì điều đó sẽ phá vỡ các bài kiểm tra của bạn. Giảm tải nó xuống dạng xem hoặc, như tôi đã làm trong một số trường hợp, có một lớp "FileOpenService" riêng xử lý tương tác hộp thoại thực tế. Bằng cách đó, bạn có thể giả mạo dịch vụ mở tệp trong quá trình kiểm tra. Đặt mã như vậy trong một dịch vụ riêng biệt có thể cung cấp cho bạn các phản ứng phụ lại khả năng sử dụng thoải mái :)
Peter Lillevold

2

Người trình bày nên hành động khi kết thúc yêu cầu hiển thị cửa sổ openfiledialog như bạn đã đề xuất. Vì không cần dữ liệu nào từ mô hình nên người trình bày có thể và nên xử lý yêu cầu.

Giả sử bạn cần dữ liệu để tạo một số thực thể trong mô hình của mình. Bạn có thể chuyển rãnh luồng đến lớp truy cập nơi bạn có phương thức để tạo các thực thể từ luồng, nhưng tôi khuyên bạn nên xử lý việc phân tích cú pháp tệp trong trình trình bày của mình và sử dụng phương thức khởi tạo hoặc phương thức Tạo cho mỗi thực thể trong mô hình của bạn.


1
Cảm ơn vì sự trả lời. Ngoài ra, bạn sẽ có một người thuyết trình duy nhất cho buổi xem? Và người trình bày đó xử lý yêu cầu hoặc nếu dữ liệu được yêu cầu, thì nó ủy quyền cho bất kỳ số lớp mô hình nào hoạt động theo các yêu cầu cụ thể? Đó có phải là cách chính xác? Cảm ơn một lần nữa.
Darren Young

3
Một Chế độ xem có một người trình bày nhưng một người trình bày có thể có nhiều chế độ xem.
JochemKempe
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.