- 軟件再工程:優化現有軟件系統的方法與最佳實踐
- (美)Bradley Irby
- 1401字
- 2020-11-04 16:44:59
2.4 處理UI事件
另一種觀點認為這三個模式的不同之處在于如何處理UI事件。例如,一個按鈕推送事件。在嚴格MVC模式中,視圖的代碼隱藏文件不會包含任何UI事件邏輯。所有的處理發生于控制器內。這意味著視圖必須要把“按下按鈕”這個事件和其他的UI事件完全地暴露給控制器,以便控制器進行下一步處理??刂破鳛槊總€重要的事件附加事件處理句柄,用以合理處理該事件。
在MVP模式中,在把UI事件傳遞給控制器進行處理之前,視圖的代碼隱藏會預處理UI事件。如果當前的事件請求與業務邏輯無關,只和UI相關,那么視圖可以在不涉及表示器的情況下直接處理請求并返回。
在MVVM模式中,同樣的問題也被巧妙地回避了?;赬AML的應用程序可以直接把處理邏輯綁定到視圖模型所提供的命令上。
我們看一下MVC和MVP的區別。假設你的應用程序正常運行并顯示網格數據。某個用戶想具體查看某一行的數據,所以他按了“顯示細節”(Show Details)這個按鈕,打開了一個具有更多細節數據的對話框。在我們的UI里,用戶也可以通過右鍵單擊上下文菜單來顯示更多細節。代碼清單2.4顯示了MVC實現的一個例子。
代碼清單2.4 暴露事件給控制器的MVC視圖
using System; using System.Windows.Forms; namespace CodeSamples.Ch02_ApplicationArchitecture.Listing04 { public class SampleForm : Form { private DataGrid Grid; private Button showDetailsBtn; private Button maximizeWindowBtn; private ContextMenu mnu; public event EventHandler ShowDetailsButtonClicked; public event EventHandler MaximizeWindowButtonClicked; public event EventHandler ContextMenuItemClicked; public SampleForm() { Grid= new DataGrid(); showDetailsBtn = new Button(); maximizeWindowBtn = new Button(); mnu = new ContextMenu(); showDetailsBtn.Click += showDetailsBtn_Click; maximizeWindowBtn.Click += maximizeWindowBtn_Click; var mnuItem = mnu.MenuItems.Add("Details"); mnuItem.Click += mnuItem_Click; } void maximizeWindowBtn_Click(object sender, EventArgs e) { if (MaximizeWindowButtonClicked != null) MaximizeWindowButtonClicked(this, e); } void mnuItem_Click(object sender, EventArgs e) { if (ContextMenuItemClicked != null) ContextMenuItemClicked(this, e); } void showDetailsBtn_Click(object sender, EventArgs e) { if (ShowDetailsButtonClicked != null) ShowDetailsButtonClicked(this, e); } public void Maximize() { //maximize window } } public class SampleFormController { private SampleForm _form; public SampleFormController() { _form = new SampleForm(); _form.ShowDetailsButtonClicked += _form_ShowDetailsButtonClicked; _form.ContextMenuItemClicked += _form_ContextMenuItemClicked; _form.MaximizeWindowButtonClicked += _form_MaximizeWindowButtonClicked; } void _form_MaximizeWindowButtonClicked(object sender, EventArgs e) { _form.Maximize(); } void _form_ContextMenuItemClicked(object sender, EventArgs e) { ShowDetailsForm(); } void _form_ShowDetailsButtonClicked(object sender, EventArgs e) { ShowDetailsForm(); } private void ShowDetailsForm() { } } }
在我們的MVC實現中,控制器直接接收“按下按鈕”這個事件并執行合理的邏輯處理。它同時也添加了一個獨立句柄,用以處理上下文菜單事件。事實上,所有這些事件處理句柄可以調用同一個事件處理方法,來實現真正意義上的事件處理。但是有時候仍然需要多個事件句柄來處理不同的事件。如果需要增加另一種UI方法(比如熱鍵),用以查看細節,那么視圖是需要更新的。視圖需要把這個新增加的事件處理句柄暴露給控制器,而且控制器也需要做相應的更新以處理該事件。請注意,與此同時,用戶可能有新的事件請求發送給控制器,比如說,最大化當前對話框窗口,控制器會調用窗體中合適的方法來處理。
現在我們考慮同樣的例子在MVP實現下的情況,如代碼清單2.5所示。
代碼清單2.5 暴露事件給表示器的MVP視圖
using System; using System.Windows.Forms; namespace CodeSamples.Ch02_ApplicationArchitecture.Listing05 { public class SampleForm : Form { private DataGrid Grid; private Button showDetailsBtn; private Button maximizeWindowBtn; private ContextMenu mnu; public event EventHandler ViewDetailsRequested; public event EventHandler MaximizeWindowButtonClicked; public SampleForm() { Grid= new DataGrid(); showDetailsBtn = new Button(); maximizeWindowBtn = new Button(); mnu = new ContextMenu(); showDetailsBtn.Click += showDetailsBtn_Click; maximizeWindowBtn.Click += maximizeWindowBtn_Click; var mnuItem = mnu.MenuItems.Add("Details"); mnuItem.Click += mnuItem_Click; } void maximizeWindowBtn_Click(object sender, EventArgs e) { //maximize window } void mnuItem_Click(object sender, EventArgs e) { if (ViewDetailsRequested != null) ViewDetailsRequested(this, e); } void showDetailsBtn_Click(object sender, EventArgs e) { if (ViewDetailsRequested != null) ViewDetailsRequested(this, e); } } public class SampleFormPresenter { private SampleForm _form; public SampleFormPresenter() { _form = new SampleForm(); _form.ViewDetailsRequested += _form_ShowDetailsButtonClicked; } void _form_ShowDetailsButtonClicked(object sender, EventArgs e) { ShowDetailsForm(); } private void ShowDetailsForm() { } } }
這個MVP示例實現了視圖中的事件篩選過程,用于過濾用戶不同方式的請求。這個示例通過視圖的代碼隱藏(而不是表示器),來給按鈕和上下文菜單事件添加事件句柄。在視圖中又定義了一個新的事件ViewDetailsRequested。表示器為視圖中的每個ViewDetailsRequested事件創建一個句柄,所有的事件句柄都處理同一個ViewDetailsRequested事件表示器。視圖將單個UI請求篩選為一般操作事件,交由表示器處理。使用這個結構,如果我們增加熱鍵只顯示細節,那么視圖需要做相應更新以處理額外的功能。接口和表示器保持不變。
請注意,在這個實現中,視圖本身已經處理了窗口最大化的請求。由于不要求業務邏輯完成這個請求,因此視圖無須借助表示器,它自己就執行請求的動作。如果由于一些原因表示器需要知道這個請求,那么我們可以通過重構來把請求消息發送給表示器。
- 多媒體CAI課件設計與制作導論(第二版)
- C++ Primer習題集(第5版)
- LabVIEW 2018 虛擬儀器程序設計
- 自己動手寫搜索引擎
- Interactive Data Visualization with Python
- Python Tools for Visual Studio
- 網頁設計與制作教程(HTML+CSS+JavaScript)(第2版)
- Learning Python Design Patterns(Second Edition)
- 鋒利的SQL(第2版)
- HTML5 and CSS3 Transition,Transformation,and Animation
- 利用Python進行數據分析(原書第3版)
- Python深度學習原理、算法與案例
- Mastering Leap Motion
- Android 游戲開發大全(第二版)
- 3ds Max 2018從入門到精通