C# 实践之 基于winform的mvvm模型,使UI独立,逻辑可测
背景:在winform中可以使用databinding 达到PM模式的开发,但扩展性与可测试性还是不如WPF那样完善,我们使用nuget中第三方库,mvvm fx-winforms,达到数据、业务与UI完全分离开发,并且ui逻辑,业务逻辑完全可测。
(转载请注明来源:cnblogs coder-fang)
- 使用nuget下载 mvvm fx winforms库,并引用之。如图:
3.创建视图数据模型,代码如下:
public class PersonModel:INotifyPropertyChanged { private string _id; public String ID { get { return _id; } set { _id = value; OnPropertyChange("ID"); } } private string _name; public String Name { get { return _name; } set { _name = value; OnPropertyChange("Name"); } } private int _sex; public int Sex { get { return _sex; } set { _sex = value; OnPropertyChange("Sex"); } } public event PropertyChangedEventHandler PropertyChanged; public void OnPropertyChange(String prop) { if(PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); } } }
4.创建视图控制器在这里表示为UI逻辑模型,代码如下:
public class PersonCtrl { public MyTab mytab; public PersonModel cur_model; public List<PersonModel> lstModel = new List<PersonModel>(); public PersonCtrl() { for (int i = 0; i < 3; i++ ) { lstModel.Add(new PersonModel() { ID = i.ToString(), Name = "test" + i, Sex = i % 2}); } cur_model = lstModel[0]; } public PersonModel GenCurModel() { return cur_model; } public void ShowModel(object param=null) { Console.WriteLine("id:" + cur_model.ID + " name:" + cur_model.Name + " sex:" + cur_model.Sex); } }
注:在这里我们暂时只测试cur_model的数据绑定
5.创建UI业务逻辑的单元测试,代码如下:
using System; using Microsoft.VisualStudio.TestTools.UnitTesting; using MyTabControl; using MvvmFx.Windows.Data; using MvvmFx.Windows.Input; using MvvmFx.Windows; using MvvmFx.ComponentModel; using MvvmFx.Windows.Forms; namespace UnitTes { [TestClass] public class UnitTest1 { PersonCtrl ctrl = null; BindingManager mgr = null; CommandBindingManager cmdMgr = null; [TestInitialize] public void Setup() { ctrl = new PersonCtrl(); mgr = new BindingManager(); cmdMgr = new CommandBindingManager(); } [TestMethod] public void TestMethod1() { PersonModel model = new PersonModel() { ID = "", Name = "", Sex = -1 }; Assert.AreEqual(model.ID, ""); mgr.Bind(model, "ID").To(ctrl.cur_model, "ID").Activate(); ctrl.cur_model.ID = "13"; Assert.AreEqual(model.ID, "13"); model.ID = "1"; Assert.AreEqual(ctrl.cur_model.ID, "1"); } [TestMethod] public void TestCmd() { String click = ""; MvvmFx.Windows.Forms.UserControl btn = new MvvmFx.Windows.Forms.UserControl(); BoundCommand cmd = new BoundCommand((s) => { click = "clicked"; }, (s) => { return ctrl.cur_model.ID.Length > 2; }, null); cmdMgr.CommandBindings.Add(new CommandBinding(cmd, btn, ControlEvent.Click.ToString())); Assert.IsFalse(cmd.CanExecute(null)); ctrl.cur_model.ID = "123"; Assert.IsTrue(cmd.CanExecute(null)); cmd.Execute(null); Assert.AreEqual(click, "clicked"); } } }
注1:TestMethod1用于测试模型的绑定,cur_model表示数据模型,临时的model可以表示任意控件,即绑定的两个值可以互相联动。
注2:TestCmd用于测试命令的绑定,且包含了按钮是否可用的表达示,其中的 MvvmFx.Windows.Forms.UserControl 模拟button控件
6.运行单元测试:
7. 这里只使用了其中比较常用的数据与命令的绑定方式,mvvmfx还有其它很多绑定的方式,大家可以下载代码查看sample。