官术网_书友最值得收藏!

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請求篩選為一般操作事件,交由表示器處理。使用這個結構,如果我們增加熱鍵只顯示細節,那么視圖需要做相應更新以處理額外的功能。接口和表示器保持不變。

請注意,在這個實現中,視圖本身已經處理了窗口最大化的請求。由于不要求業務邏輯完成這個請求,因此視圖無須借助表示器,它自己就執行請求的動作。如果由于一些原因表示器需要知道這個請求,那么我們可以通過重構來把請求消息發送給表示器。

主站蜘蛛池模板: 辛集市| 景谷| 开鲁县| 桓台县| 重庆市| 潜江市| 乳山市| 奉新县| 怀化市| 侯马市| 建昌县| 康平县| 潜江市| 兰西县| 香港| 汪清县| 小金县| 应用必备| 当阳市| 永康市| 肃南| 克什克腾旗| 嘉定区| 独山县| 龙口市| 宣城市| 康马县| 屏东市| 浦江县| 水城县| 罗源县| 古浪县| 沙湾县| 清苑县| 云霄县| 郓城县| 昌邑市| 沿河| 白朗县| 山阳县| 泰州市|