1. 程式人生 > 實用技巧 >c# /WinForms中的模型-檢視-控制器(MVC)模式

c# /WinForms中的模型-檢視-控制器(MVC)模式

介紹 本文使用c# /WinForm演示了。net中的MVC模式。 這是一個簡單的“使用者資訊管理器”應用程式,它根據 模型-檢視-控制器(MVC)模式。 該應用程式顯示聯絡人列表,並允許您新增、修改和刪除 現有的聯絡人。其思想是將使用者介面分離到檢視(建立)中 顯示,在需要時呼叫模型來獲取資訊)和控制器 (響應使用者請求,必要時與檢視和控制器互動)。 MVC模式的主要優點是鬆散耦合。所有的層都是分開的 有自己的功能。用其他型別替換層很容易 的層。換句話說,MVC模式將UI行為分解為不同的部分 為了增加重用的可能性和可測試性。我用的是Visual Studio 2010年的終極版。net 4.0用於建立這個應用程式。 背景 模型-檢視-控制器,顧名思義,考慮三個方面: 模型:它應該負責應用程式域檢視的資料:它在使用者介面控制器中顯示模型:它是MVC的核心,是將模型和檢視聯絡在一起的中介,也就是說,它接收使用者輸入,操作模型和檢視。導致檢視更新 ,,,,,,,,,,,,,,,,, 有關MVC的更多資訊,請參閱維基百科下面的文章 解決方案 使用者資訊管理器是一個應用程式,可以在其中儲存客戶的聯絡方式 資訊。應用程式顯示聯絡人列表和 允許您新增、修改和刪除現有的聯絡人。首先,所有客戶都有一個ID 名字,姓和性。這個應用程式的操作員用來維護他的列表的螢幕 顧客可能會是這樣的: ,,,,,, 客戶列表可以檢視,新增,刪除和更新(目前是隻包含vipP成員, 但如果你想成為俱樂部的一員,只需問" src="http://www.codeproject.com/script/Forums/Images/smiley_smile.gif" />…沒有問題,它是免費的)。 新增新使用者後,他的ID不能再更改了。 類圖 在系統的設計中,許多類被識別並組合在一個類圖中,這有助於確定物件之間的關係。 元件的描述 控制器的一部分 為了將邏輯從檢視中分離出來,我們必須讓檢視儘可能地感到無能為力,因此我們寧願讓控制器來完成所有艱苦的工作,而只給檢視一些不需要進一步處理的簡單命令。 根據我們的設計,我們通過定義一個介面IUsersView來做到這一點,檢視必須實現這個介面。 這個介面只包含我們需要使用的屬性/方法的簽名。 隱藏,複製Code

using System;
using WinFormMVC.Model;

namespace WinFormMVC.Controller
{
    public interface IUsersView
    {
        void SetController(UsersController controller);
        void ClearGrid();
        void AddUserToGrid(User user);
        void UpdateGridWithChangedUser(User user);
        void RemoveUserFromGrid(User user);
        string
GetIdOfSelectedUserInGrid(); void SetSelectedUserInGrid(User user); string FirstName { get; set; } string LastName { get; set; } string ID { get; set; } string Department { get; set; } User.SexOfPerson Sex { get; set; } bool CanModifyID { set
; } } }

現在我們有了一個相當不錯的介面,其中有許多方法。 即使MVC模式正式宣告控制器應該接收事件並對檢視採取行動,讓檢視訂閱事件並將處理委託給控制器通常更實際、更容易。 最後,我將展示控制器的實際實現(參見UsersController類)。他將模型(使用者類)與檢視(UserView類)掛鉤。 隱藏,收縮,複製Code

public class UsersController
{
    //Notice we only use the interfaces. This makes the test more 
    //robust to changes in the system.
    IUsersView _view;
    IList      _users;
    User       _selectedUser;

    //The UsersController depends on abstractions(interfaces).
    //It's easier than ever to change the behavior of a concrete class. 
    //Instead of creating concrete objects in UsersController class, 
    //we pass the objects to the constructor of UsersController
    public UsersController(IUsersView view, IList users)
    {
       _view = view;
       _users = users;
       view.SetController(this);
    }

    public IList Users
    {
       get { return ArrayList.ReadOnly(_users); }
    }

    private void updateViewDetailValues(User usr)
    {
       _view.FirstName   =  usr.FirstName;
       _view.LastName    =  usr.LastName;
       _view.ID  =  usr.ID;
       _view.Department  =  usr.Department;
       _view.Sex =  usr.Sex;
    }

    private void updateUserWithViewValues(User usr)
    {
       usr.FirstName     =  _view.FirstName;
       usr.LastName      =  _view.LastName;
       usr.ID    =  _view.ID;
       usr.Department    =  _view.Department;
       usr.Sex   =  _view.Sex;
    }

    public void LoadView()
    {
       _view.ClearGrid();
       foreach (User usr in _users)
       _view.AddUserToGrid(usr);

       _view.SetSelectedUserInGrid((User)_users[0]);
    }

    public void SelectedUserChanged(string selectedUserId)
    {
       foreach (User usr in this._users)
       {
           if (usr.ID == selectedUserId)
           {
               _selectedUser = usr;
               updateViewDetailValues(usr);
               _view.SetSelectedUserInGrid(usr);
               this._view.CanModifyID = false;
               break;
           }
       }
    }

    public void AddNewUser()
    {
       _selectedUser = new User(""   /*firstname*/, 
       ""  /*lastname*/, 
       "" /*id*/, 
       ""/*department*/,
       User.SexOfPerson.Male/*sex*/);
     
       this.updateViewDetailValues(_selectedUser);
       this._view.CanModifyID = true;
    }

    public void RemoveUser()
    {
       string id = this._view.GetIdOfSelectedUserInGrid();
       User userToRemove = null;

        if (id != "")
        {
            foreach (User usr in this._users)
            {
                if (usr.ID == id)
                {
                    userToRemove = usr;
                break;
                }
            }

            if (userToRemove != null)
            {
                int newSelectedIndex = this._users.IndexOf(userToRemove);
                this._users.Remove(userToRemove);
                this._view.RemoveUserFromGrid(userToRemove);

            if (newSelectedIndex > -1 && newSelectedIndex < _users.Count)
            {
                this._view.SetSelectedUserInGrid((User)_users[newSelectedIndex]);
            }
        }
    }
}

public void Save()
{
   updateUserWithViewValues(_selectedUser);
   if (!this._users.Contains(_selectedUser))
   {
       //Add new user
       this._users.Add(_selectedUser);
       this._view.AddUserToGrid(_selectedUser);
   }
   else
   {
       //Update existing user
       this._view.UpdateGridWithChangedUser(_selectedUser);
   }
   _view.SetSelectedUserInGrid(_selectedUser);
   this._view.CanModifyID = false;

}
}

控制器類非常重要,並且是應用程式的中心。保持它的輕便、敏捷和與程式的其他元件鬆散耦合是非常重要的。 一部分的觀點 本節將重點討論載入帶有使用者列表的檢視的場景。 如前所述,我們的檢視必須實現IUsersView介面。實現的一個子集如下面的程式碼所示: 隱藏,複製Code

namespace WinFormMVC.View
{
    public partial class UsersView : Form, IUsersView
    {

UsersView的SetController()成員函式允許我們告訴檢視它必須將事件轉發給哪個控制器例項,所有的事件處理程式只需呼叫控制器上相應的“event”方法。正如你在這裡看到的,UsersView也依賴於抽象… 隱藏,複製Code

public void SetController(UsersController controller)
{
    _controller = controller;
}

我們也使用幾個方法實現從IUsersView介面使用使用者物件: 隱藏,收縮,複製Code

public void AddUserToGrid(User usr)
{
    ListViewItem parent;
    parent = this.grdUsers.Items.Add(usr.ID);
    parent.SubItems.Add(usr.FirstName);
    parent.SubItems.Add(usr.LastName);
    parent.SubItems.Add(usr.Department);
    parent.SubItems.Add(Enum.GetName(typeof(User.SexOfPerson), usr.Sex));
}

public void UpdateGridWithChangedUser(User usr)
{
    ListViewItem rowToUpdate = null;

    foreach (ListViewItem row in this.grdUsers.Items)
    {
        if (row.Text == usr.ID)
        {
            rowToUpdate = row;
        }
    }

    if (rowToUpdate != null)
    {
        rowToUpdate.Text = usr.ID;
        rowToUpdate.SubItems[1].Text = usr.FirstName;
        rowToUpdate.SubItems[2].Text = usr.LastName;
        rowToUpdate.SubItems[3].Text = usr.Department;
        rowToUpdate.SubItems[4].Text = Enum.GetName(typeof(User.SexOfPerson), usr.Sex);
    }
}

public void RemoveUserFromGrid(User usr)
{

    ListViewItem rowToRemove = null;

    foreach (ListViewItem row in this.grdUsers.Items)
    {
        if (row.Text == usr.ID)
        {
            rowToRemove = row;
        }
    }

    if (rowToRemove != null)
    {
        this.grdUsers.Items.Remove(rowToRemove);
        this.grdUsers.Focus();
    }
}

public string GetIdOfSelectedUserInGrid()
{
    if (this.grdUsers.SelectedItems.Count > 0)
        return this.grdUsers.SelectedItems[0].Text;
    else
        return "";
}

public void SetSelectedUserInGrid(User usr)
{
    foreach (ListViewItem row in this.grdUsers.Items)
    {
        if (row.Text == usr.ID)
        {
            row.Selected = true;
        }
    }
}

public string FirstName 
{
    get { return this.txtFirstName.Text; }
    set { this.txtFirstName.Text = value; }
}

public string LastName 
{
    get { return this.txtLastName.Text; }
    set { this.txtLastName.Text = value; }
}

public string ID
{
    get { return this.txtID.Text; }
    set { this.txtID.Text = value; }
}


public string Department 
{
    get { return this.txtDepartment.Text; }
    set { this.txtDepartment.Text = value; }
}

public User.SexOfPerson Sex
{
    get
    {
        if (this.rdMale.Checked)
            return User.SexOfPerson.Male;
        else
            return User.SexOfPerson.Female;
    }
    set
    {
        if (value == User.SexOfPerson.Male)
            this.rdMale.Checked = true;
        else
            this.rdFamele.Checked = true;
    }
}

public bool CanModifyID
{
    set { this.txtID.Enabled = value; }
}

        ...
}

模型的一部分 這個使用者類是一個模型類。在這個例子中,User是一個沒有行為的極其簡單的域類,而在一個真實的域模型中,您可能擁有更多的功能域類。 模型獨立於使用者介面。它不知道它是通過文字、圖形還是網路介面使用的。 模型僅以結構化格式儲存記憶體中的狀態。如您所見,該類只包含私有資料成員和客戶端程式碼可用的公共介面(屬性) 隱藏,收縮,複製Code

using System;

namespace WinFormMVC.Model
{
 public class User
 {
   public enum SexOfPerson
   {
      Male   = 1,
      Female = 2
   }

   private string    _FirstName;
   public string FirstName 
   {
    get { return _FirstName; } 
    set 
    { 
     if (value.Length > 50)
      Console.WriteLine("Error! FirstName must be less than 51 characters!"); 
     else
      _FirstName = value; 
    } 
   }

   private string _LastName;
   public string LastName
   {
     get { return _LastName; }
     set
     {
      if (value.Length > 50)
       Console.WriteLine("Error! LastName must be less than 51 characters!");
      else
       _LastName = value;
    }
   }

   private string _ID;
   public string ID
   {
    get { return _ID; }
    set
    {
      if (value.Length > 9)
        Console.WriteLine("Error! ID must be less than 10 characters!");
      else
       _ID = value;
    }
   }

   private string _Department;
   public string Department
   {
       get { return _Department; }
       set { _Department = value; }
   }

   private SexOfPerson _Sex;
   public SexOfPerson Sex
   {
       get { return _Sex; }
       set { _Sex = value; }
   }


   public User(string firstname, string lastname, string id, string department, SexOfPerson sex)
   {
       FirstName   = firstname;
       LastName    = lastname;
       ID  = id;
       Department  = department;
       Sex = sex;
   }
 } 

}

的一部分客戶 現在是展示如何有效使用MVC範例的好時機,也就是MVC架構的程式碼元件(請參見usemvcappe .csproj) 隱藏,收縮,複製Code

using System.Collections;
using  WinFormMVC.Model;
using  WinFormMVC.View;
using  WinFormMVC.Controller;

namespace UseMVCApplication
{
static class Program
{
    /// The main entry point for the application.
    [STAThread]
    static void Main()
    {
        //Here we are creating a View
        UsersView view = new UsersView();
        view.Visible = false;

        //Here we are creating a list of users
        IList users = new ArrayList();
    
        //Here we are add our "commoners" in the list of users
        users.Add(new User("Vladimir",   "Putin",     
     "122",    "Government of Russia",
            User.SexOfPerson.Male));
        users.Add(new User("Barack",     "Obama",
             "123",    "Government of USA",      
             User.SexOfPerson.Male));
        users.Add(new User("Stephen",    "Harper",    
            "124",    "Government of Canada",      
            User.SexOfPerson.Male));
        users.Add(new User("Jean",       "Charest", 
            "125",    "Government of Quebec",    
             User.SexOfPerson.Male));
        users.Add(new User("David",      "Cameron",
            "126",    "Government of United Kingdom",
            User.SexOfPerson.Male));
        users.Add(new User("Angela",     "Merkel",
            "127",    "Government of Germany",
            User.SexOfPerson.Female));
        users.Add(new User("Nikolas",    "Sarkozy",\
            "128",    "Government of France",
            User.SexOfPerson.Male));
        users.Add(new User("Silvio",     "Berlusconi",
            "129",    "Government of Italy",
            User.SexOfPerson.Male));
        users.Add(new User("Yoshihiko",  "Noda",
            "130",    "Government of Japan",
            User.SexOfPerson.Male));
     
        //Here we are creating a Controller and passing two
        //parameters: View and list of users (models)
        UsersController controller = new UsersController(view, users);
        controller.LoadView();
        view.ShowDialog();
        }
    }
}

為什麼它是好的? 使用MVC模式的主要優點是,它使得使用者介面的可測試性的程式碼是一個結構化的方法在設計使用者介面的過程中,它本身有助於編寫乾淨、可測試的程式碼,易於維護和擴充套件 模型-檢視-控制器是一種經過良好驗證的設計模式 解決資料(模型)與使用者介面(檢視)分離的問題 使用者介面的變化不會影響資料處理, 資料可以在不影響/改變UI的情況下進行更改。MVC 通過將資料訪問和業務邏輯層與UI分離來解決這個問題 和使用者互動,通過引入中間元件:控制器。 該MVC體系結構允許在元件中建立可重用元件 靈活的程式設計(元件修改容易) 歷史 2012年5月10日:入職 本文轉載於:http://www.diyabc.com/frontweb/news5051.html