MVVM mode is used in winform

MVVM was first learned in the development of WPF. Now the popular web front-end framework Vue also draws lessons from this idea: Viewmodel Binder View. In my personal words, view is data and data is view.

Using Vue. Com on the web side JS can easily bind data and element in both directions, which greatly reduces the coupling between the front and back ends;

Go back to winform and use MVVM to do the project. Note: it's just the two-way binding between ViewModel and view, and the conversion between ViewModel and Model is based on their own methods.

 

Let's start with two viewmodels. The operation focuses on Student and inherits INotifyPropertyChanged. When the property of ViewModel changes, that is, when the set accessor is executed, the PropertyChanged event will be triggered to notify the front-end control to update the bound property value immediately;

 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));
        }
    }

  

Then there is the winform interface. To operate on student objects, set the tag s of these textboxes, checkboxes and comboboxes to the attribute names of the corresponding student objects

 

 

Idea: by finding all the controls in the form, if the tag attribute is the same as the studnet attribute, bind the control to the student object attribute;

Background code first:

  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="Please select..." }
  6         };
  7         public MVVM()
  8         {
  9             InitializeComponent();
 10             #region Analog data
 11             VModel = new Student
 12             {
 13                 //Attribute assignment means to open this page in modification mode. If it is a new mode, comment out all the attributes
 14                 //Tested, modified and added modes can pass
 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 Building", Number = "102", Max = 8 },
 22                 RoomId = 2
 23             };
 24             if (VModel.Room != null) Rooms.Add(VModel.Room);
 25             #endregion
 26         }
 27         /// <summary>
 28         /// Get all controls recursively
 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       /// see 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         /// change attributes 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 Change test viewmodel Property, whether the view will be updated
 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         /// Identifies whether data has been obtained from the server
108         /// </summary>
109         private bool IsLoadRooms = false;
110         /// <summary>
111         /// room combobox DropDown Event processing, obtaining data from the server for the first time
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 Simulate request server to get data
120                 for (int i = 0; i < 10; i++)
121                 {
122                     Room r = new Room { Building = "A Building", 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                 //Rebind data source
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     }

explain:

1. GetAllControl method obtains all controls. The tooltripbutton in tooltrip cannot be obtained. There are other controls, which are not discussed here;

2. The current page is a page for adding, modifying, and viewing objects

3. The Room attribute type of VModel is other objects. When you need to operate on it, request the data source from the server for the first time and save it to the current Rooms List;

4. The binding properties of different controls are different. For example, if the name property type is string, it can be bound in textbox, that is, textbox Text = name, similarly, the checked object type of checkbox binding is bool, and combobox is the data source selection. By default, a prompt is given to select item, and then let him bind the data source rooms. When adding an operation, Vmodel Room is null, all current ComboBox selecteditem is still the first one by default; When opened in modify mode, Vmodel When the room has a value, after binding, the selecteditem is the current Vmodel Room. Of course, the premise is to put the room attribute value into rooms;

 

Now run and try

 

The effect is pretty good. By the way, another advantage of binding is that it can be used to verify the rationality of the input data

( ̄▽ ̄)"

 

Posted by kidestranged on Tue, 10 May 2022 00:23:18 +0300