winform 里使用MVVM模式


MVVM最早是在WPF開發中了解到的,現在流行的web前端框架Vue也借鑒了這種思路:Viewmodel Binder View,我個人的話說就是:視圖就是數據,數據就是視圖。

 在web端使用Vue.js能很方便使數據與element進行雙向綁定,使得前后端的耦合度大大的降低;

重新回到winform,使用MVVM來做項目,順便記錄下,注意:只是viewModel與view的雙向綁定,viewmodel與Model轉換自己想方法。

 

先來2個Viewmodel,操作重點是Student,繼承INotifyPropertyChanged,當ViewModel的屬性發生改變,即執行了set訪問器時,觸發PropertyChanged事件,通知前端控件即時更新綁定的屬性值;

 public class Room
    {
        public int Id { get; set; }
        string _number;
        string _building;
        int _max;
        public string Number { get; set; }
        public string Building { get; set; }
        public string Address
        {
            get
            {
                if (Number != null && Building != null)
                {
                    return Building + Number;
                }
                return "";
            }
        }
        public int Max { get; set; }
    }

  

    public class Student : INotifyPropertyChanged
    {
     
        private string _name = string.Empty;
        private DateTime _brithday = DateTime.Parse("1753-01-01 00:00:00.000");
        private double _high;
        private decimal _money;
        private bool _enable = true;
        private int? _roomId;
        private Room _room;
        private double _qty;
        private decimal _price;

        public int Id { get; set; }
        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
                OnPropertyChanged("Name");
            }
        }
        public DateTime Brithday
        {
            get
            {
                return _brithday;
            }
            set
            {
                _brithday = value;
                OnPropertyChanged("Brithday");
            }
        }
        
        public double High
        {
            get
            {
                return _high;
            }
            set
            {
                _high = value;
                OnPropertyChanged("High");
            }
        }
       
        public decimal Money
        {
            get
            {
                return _money;
            }
            set
            {
                _money = value;
                OnPropertyChanged("Money");
            }
        }
       
        public bool Enable
        {
            get
            {
                return _enable;
            }
            set
            {
                _enable = value;
                OnPropertyChanged("Enable");
            }
        }
       
        public int? RoomId
        {
            get
            {
                if (Room != null)
                {
                    _roomId = Room.Id;
                }
                return _roomId;
            }
            set { }
        }

        public Room Room
        {
            get
            {
                return _room;
            }
            set
            {
                _room = value;
                OnPropertyChanged("Room");
            }
        }
        public double Qty
        {
            get
            {
                return _qty;
            }
            set
            {
                _qty = value;
                OnPropertyChanged("Qty");
                OnPropertyChanged("Account");
            }
        }
     
        public decimal Price
        {
            get
            {
                return _price;
            }
            set
            {
                _price = value;
                OnPropertyChanged("Price");
                OnPropertyChanged("Account");
            }
        }
        public decimal Account
        {
            get
            {
                if (_qty != 0 && _price != 0)
                {
                    var s = decimal.Parse(_qty.ToString()) * _price;
                    return s;
                }
                return 0;
            }
        }


        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string proName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(proName));
        }
    }

  

然后是winform界面,要對student對象操作,把這些textbox,checkbox,combobox的tag設置為對應student對象的屬性名

 

 

思路:通過找到窗體內所有控件,如果tag屬性與studnet的屬性相同,則把控件與student對象屬性綁定;

先上后台代碼:

  1     public partial class MVVM : Form
  2     {
  3         private Student VModel;
  4         private List<Room> Rooms = new List<Room>() {
  5             new Room {Id=0, Building="",Number="請選擇..." }
  6         };
  7         public MVVM()
  8         {
  9             InitializeComponent();
 10             #region 模擬數據
 11             VModel = new Student
 12             {
 13                 //屬性賦值表示以修改模式打開這個頁面,如果是新增模式,把屬性都注釋掉
 14                 //已測試,修改、新增模式都可通過
 15                 Id = 1,
 16                 Name = "Jack",
 17                 Brithday = DateTime.Now.AddYears(-22),
 18                 Enable = true,
 19                 High = 175.4,
 20                 Money = 10000000000.5m,
 21                 Room = new Room { Id = 2, Building = "A棟", Number = "102", Max = 8 },
 22                 RoomId = 2
 23             };
 24             if (VModel.Room != null) Rooms.Add(VModel.Room);
 25             #endregion
 26         }
 27         /// <summary>
 28         /// 遞歸獲取所有控件
 29         /// </summary>
 30         /// <param name="ctl"></param>
 31         /// <returns></returns>
 32         private List<Control> GetAllControl(Control ctl)
 33         {
 34             List<Control> result = new List<Control>();
 35             if (ctl.HasChildren)
 36             {
 37                 if (!(ctl is Form)) result.Add(ctl);
 38                 foreach (Control item in ctl.Controls)
 39                 {
 40                     result.AddRange(GetAllControl(item));
 41                 }
 42             }
 43             else
 44             {
 45                 result.Add(ctl);
 46             }
 47 
 48             return result;
 49         }
 50         protected override void OnLoad(EventArgs e)
 51         {
 52             base.OnLoad(e);
 53 
 54             this.cbxRoom.DisplayMember = "Address";
 55             this.cbxRoom.ValueMember = "Id";
 56           
 57             this.cbxRoom.DataSource = Rooms;
 58 
 59             List<Control> list = GetAllControl(this);
 60             var propes = VModel.GetType().GetProperties();
 61             try
 62             {
 63                 foreach (Control item in list)
 64                 {
 65                     var prop = propes.FirstOrDefault(a => item.Tag != null && a.Name == item.Tag.ToString());
 66                     if (prop != null)
 67                     {
 68                         if (item is TextBox) item.DataBindings.Add(new Binding("Text", VModel, prop.Name));
 69                         if (item is CheckBox) item.DataBindings.Add(new Binding("Checked", VModel, prop.Name));
 70                         if (item is ComboBox) item.DataBindings.Add(new Binding("SelectedItem", VModel, prop.Name));
 71 
 72                     }
 73                 }
 74             }
 75             catch (Exception)
 76             {
 77 
 78                 throw;
 79             }
 80         }
 81 
 82       /// <summary>
 83       /// 查看 button
 84       /// </summary>
 85       /// <param name="sender"></param>
 86       /// <param name="e"></param>
 87         private void button1_Click(object sender, EventArgs e)
 88         {
 89             MessageBox.Show(Newtonsoft.Json.JsonConvert.SerializeObject(VModel));
 90         }
 91         /// <summary>
 92         /// 更改屬性 button
 93         /// </summary>
 94         /// <param name="sender"></param>
 95         /// <param name="e"></param>
 96         private void button2_Click(object sender, EventArgs e)
 97         {
 98             #region 測試更改viewmodel屬性,視圖是否會更新
 99             VModel.Name = "Bob";
100             Room r6 = Rooms.FirstOrDefault(a => a.Id == 6);
101             if (r6 != null) VModel.Room = r6;
102             VModel.Qty = 120;
103             VModel.Price = 12;
104             #endregion
105         }
106         /// <summary>
107         /// 標識是否已從服務器獲取到數據
108         /// </summary>
109         private bool IsLoadRooms = false;
110         /// <summary>
111         /// room combobox DropDown事件處理,第一次從服務器獲取數據
112         /// </summary>
113         /// <param name="sender"></param>
114         /// <param name="e"></param>
115         private void cbxRoom_DropDown(object sender, EventArgs e)
116         {
117             if (!IsLoadRooms)
118             {
119                 #region 模擬請求服務器得到數據
120                 for (int i = 0; i < 10; i++)
121                 {
122                     Room r = new Room { Building = "A棟", Max = 8, Number = "10" + (i + 1), Id = i + 1 };
123                     if (!Rooms.Exists(a => a.Id == r.Id))
124                     {
125                         Rooms.Add(r);
126                     }
127                 }
128                 #endregion
129                 //重新綁定數據源
130                 this.cbxRoom.DataSource = null;
131                 this.cbxRoom.DisplayMember = "Address";
132                 this.cbxRoom.ValueMember = "Id";
133                 this.cbxRoom.DataSource = Rooms;
134                 IsLoadRooms = true;
135 
136             }
137         }
138     }

說明:

1、GetAllControl 方法獲取所有控件,toolstrip里 的toolstripButton是不能獲取到的,還有其他的一些控件,這里不談論;

2、當前頁面是進行對象進行新增、修改、參看等操作的頁面

3、VModel的Room屬性類型為其他對象,需要對其進行操作時,第一次從服務器端請求數據源,保存到當前的Rooms List里;

4、不同控件綁定的屬性是不同的,如name屬性類型為string,可用放到textbox里綁定,即textbox.text=name,同理,checkbox綁定checked 對象類型為bool,combobox是數據源選擇,默認給一個提示選擇item,然后讓他綁定數據源rooms,新增操作時,vmodel.Room是null,所有當前combobox.selecteditem還是默認第一個;以修改模式打開時vmodel.Room有值時,經過binding后,selecteditem就是當前vmodel.Room,當然前提是把Room屬性值放到rooms中;

 

現在運行試試

 

效果還不錯,對了,binding還有一個好處就是可用驗證輸入數據合理性

( ̄▽ ̄)"

 


免責聲明!

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



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