c#中winform的MVP模式的簡單實現


MVP模式是類似於MVC模式的一種設計模式,最近在做項目學習過程中遇到,弄了很久終於有一些眉目,這是學習過程中的一些筆記。
MVP指的是實體對象Model、視圖Viw和業務處理Presenter。MVP的作用是解耦UI渲染、業務邏輯和數據實體的關系。在普通的winform中,業務和界面是寫在一起的,一般都是同一個Load或Click方法中,使View和Controller緊密聯系。在MVP中,我們將界面渲染放在View里面,也就是winfrom的窗體應用類;將業務關系放在Presenter類中,這就是MVP中的業務數據類;最后的數據實體與數據庫的交互放在Model中,是三者各司其職。
一般的MVP中,我們是在Presenter中主動使用View,也就是界面控件形態都是由Presenter去主動控制的。而建立這兩者之間的聯系,就是在Presenter中注冊View的事件,當界面發生由用戶觸發事件時,這個事件會通過View傳遞到Presenter中,並在Presenter中調用Model的數據方法,最后Presenter調用在類中引用的View的實例去改變界面形態,下面是一些方法的實現,這里着重說明Presenter和View的關系。
首先,我們定義View的接口類IView,里面就一個數據實體的引用:

1 public interface IView<T>:IView
2 {
3     T Model { get; set; }
4 }
public interface IView:IView

 

接下來,定義View的下一級接口,這里是定義視圖一些控件和事件:

1 public interface IMainForm<T> : IView<T>
2 {
3     Button TestButton { get;}    //定義MainFrom的按鈕引用
4     TextBox TestTextBox { get; }    //定義MianForm的文本框引用
5     event EventHandler ViewLoadEvent;    //定義窗體加載完畢執行事件
6     event EventHandler ButtonSubmitEvent;    //定義按鈕事件
7     void ShowSubmitDialog();    //定義自定義的事件
8 }
public interface IMainForm : IView

 

最后就是View的實現類,里面是實現的接口方法和屬性,包含一個按鈕及一個文本框,這里有一個繼承了的MvpForm類和PresenterBinding的特性,一會再說:

 1 [PresenterBinding(typeof(MainFormPresenter))]
 2 public partial class MainForm : MvpForm , IMainForm<MainFormModel>
 3 {
 4     public MainForm()
 5     {
 6         InitializeComponent();
 7     }
 8 
 9     public MainFormModel Model { get; set; }
10     public TextBox TestTextBox { get { return txtText; } }
11     public Button TestButton { get { return btnSubmit; } }
12 
13     public event EventHandler ViewLoadEvent;
14     public event EventHandler ButtonSubmitEvent;
15 
16     private void MainForm_Load(object sender, EventArgs e)
17     {
18         if (ViewLoadEvent != null) ViewLoadEvent(sender, e);
19     }
20 
21     public void ShowSubmitDialog()
22     {
23         MessageBox.Show("to submit?");
24     }
25 
26     private void btnSubmit_Click(object sender, EventArgs e)
27     {
28         if (ButtonSubmitEvent != null) ButtonSubmitEvent(sender , e);
29     }
30 }
public partial class MainForm : MvpForm , IMainForm

 

定義完View的內容,就可以看一下Presenter,同樣,先有接口,再有實現,先定義Presenter的接口:

1 public interface IPresenter<T>:IPresenter where T : class, View.IView
2 {
3     T View { get; }
4 }
public interface IPresenter:IPresenter where T : class, View.IView

 

這里再定義一個Presenter的抽象類,用於統一各個不同View對應的Presenter類,其定義如下:

 1 public abstract class Presenter<T> : IPresenter<T> where T : class, View.IView
 2 {
 3     private readonly T view;
 4 
 5     //這里的view作為引用,用於在presenter中獲取View的實例
 6     protected Presenter(T view)
 7     {
 8     this.view = view;
 9     }
10 
11     public T View { get { return view; } }
12 }
public abstract class Presenter : IPresenter where T : class, View.IView

 

最后就是對應的View的Presenter類了:

 1 class MainFormPresenter:Presenter<View.IMainForm<Model.MainFormModel>>
 2 {
 3     public MainFormPresenter(View.IMainForm<Model.MainFormModel> view)
 4 : base(view)
 5     {
 6     view.Model = new Model.MainFormModel();
 7 
 8     view.ViewLoadEvent += On_ViewLoad;
 9     view.ButtonSubmitEvent += On_ButtonSubmitClick;
10     init();
11     }
12 
13     public void init()
14     {
15         //To Do something...
16     }
17 
18     public void On_ViewLoad(object sender, EventArgs e)
19     {
20         //To Do something...
21     }
22 
23     public void On_ButtonSubmitClick(object sender, EventArgs e)
24     {
25         View.ShowSubmitDialog();//通過view的實例調用view的方法來改變控件形態
26     }
27 }
class MainFormPresenter:Presenter<View.IMainForm>

 

這里定義了Presenter和View的接口和實現,下面就是如何將這兩個不同的模塊聯合在一起,這里,使用的是.net的特性和反射。
首先,先建立特性類PresenterBindingAttribute,通過在View的實現類標記該特性類和指定對應的Presenter類,就可以獲取View和Presenter的對應關系了,該類同樣要標注特性AttributeUsage和繼承Attribute類,同時定義兩個屬性參數:

 1 [AttributeUsage(AttributeTargets.Class,AllowMultiple = true)]
 2 public sealed class PresenterBindingAttribute : Attribute
 3 {
 4     public Type PresenterType { get;private set; }
 5 
 6     public Type ViewType { get; set; }
 7 
 8     public PresenterBindingAttribute(Type presenterType)
 9     {
10         PresenterType = presenterType;
11         ViewType = null;
12     }
13 }
public sealed class PresenterBindingAttribute : Attribute

 

接下來,就是通過反射去建立view和presenter的關系,這里建立PerformBinding類:

 1 public IPresenter PerformBinding(IView viewInstance)
 2 {
 3     IPresenter presenter = null;
 4     Type t = viewInstance.GetType();    //獲取該視圖的類類型
 5     object[] attrs = t.GetCustomAttributes(typeof(PresenterBindingAttribute), false);    //獲取該類上的附加特性集合
 6     //遍歷特性集合,找到Presenter類型附加的特性,通過該特性建立實例
 7     foreach (PresenterBindingAttribute pba in attrs)
 8     {
 9         Type newt = pba.PresenterType;    //獲取Presenter類類型
10         //建立Presenter實例,這里的構造參數是View的對象,這樣就使兩者建立了聯系
11         Object obj = Activator.CreateInstance(pba.PresenterType, viewInstance);
12         presenter = obj as IPresenter;
13     }
14     return presenter;
15 }
public IPresenter PerformBinding(IView viewInstance)

 

那么,這個類PerformBinding在哪里使用,一般是在應用View啟動是就要注冊實例,這里為了解除類間的強耦合,就添加一個中間類。在前面的View的實現類中,是繼承自一個MvpForm的類,這個MvpForm就使注冊View和Presenter關系的類,接下來看MvpForm的實現:

1 public partial class MvpForm : Form,IView
2 {
3     private readonly PresenterBinder presenterBinder = new PresenterBinder();
4     public MvpForm()
5     {
6         presenterBinder.PerformBinding(this);    //注冊關系
7     }
8 }
public partial class MvpForm : Form,IView

 

這樣,就建立了View與Presenter之間的關系,每次View頁面啟動,就先執行父類MvpForm的構造函數,注冊View和Presenter的關系,相應的邏輯可以寫在Presenter中,View的作用就是作為UI的渲染。以后添加View和Presenter實現類時,只需要繼承和實現相應的類和接口,並在View實現類添加相應的對應類特性,就可實現MVP的設計關系。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM