winform实现mvvm双向绑定的案例,实战亲身可用

1.双向绑定的核心逻辑

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

 
///双向绑定参照的是:Vue的双向绑定思路

namespace liyyyy
{

    /// <summary>
    /// 统一监听接口 
    /// </summary>
    public interface IWatcher
    {
        void Update();
    }
    /// <summary>
    /// 监听者
    /// </summary>
    public class Watcher : IWatcher
    {
        /// <summary>
        /// 实体类型
        /// </summary>
        private Type type = null;
        /// <summary>
        /// 属性变化触发的委托
        /// </summary>
        private Action<object> Action = null;
        /// <summary>
        /// 属性名称
        /// </summary>
        private string propertyName = null;
        /// <summary>
        /// 父控件
        /// </summary>
        private System.Windows.Forms.Control ParentControl = null;
        /// <summary>
        /// 实体
        /// </summary>
        private object model = null;
        /// <summary>
        /// 初始化监听者
        /// </summary>
        /// <param name="ParentControl">父控件</param>
        /// <param name="type">实体类型</param>
        /// <param name="model">实体</param>
        /// <param name="propertyName">要监听的属性名称</param>
        /// <param name="action">属性变化触发的委托</param>
        public Watcher(System.Windows.Forms.Control ParentControl, Type type, object model, string propertyName, Action<object> action)
        {
            this.type = type;
            this.Action = action;
            this.propertyName = propertyName;
            this.ParentControl = ParentControl;
            this.model = model;
            this.AddToDep();
        }
        /// <summary>
        /// 添加监听者到属性的订阅者列表(Dep)
        /// </summary>
        private void AddToDep()
        {
            PropertyInfo property = this.type.GetProperty(this.propertyName);
            if (property == null) return;
            Dep.Target = this;
            object value = property.GetValue(this.model, null);
            Dep.Target = null;
        }
        /// <summary>
        /// 更新数据(监听触发的方法)
        /// </summary>
        public void Update()
        {
            this.ParentControl.Invoke(new Action(delegate
            {
                this.Action(this.model);
            }));
        }
    }
    public class Dep
    {
        /// <summary>
        /// 全局变量,用户将指定属性的订阅者放入通知列表
        /// </summary>
        public static IWatcher Target = null;
        /// <summary>
        /// 保存属性的值,属性的get set将是对该值的操作
        /// </summary>
        private object oValue;
        /// <summary>
        /// 订阅者列表
        /// </summary>
        private List<IWatcher> lsWatcher = null;



        public Dep()
        {
            this.lsWatcher = new List<IWatcher>();
        }
        /// <summary>
        /// 添加订阅者
        /// </summary>
        /// <param name="watcher"></param>
        private void PushWatcher(IWatcher watcher)
        {
            this.lsWatcher.Add(watcher);
        }
        /// <summary>
        /// 通知
        /// </summary>
        public void Notify()
        {
            List<IWatcher> watchers = this.lsWatcher;
            watchers.ForEach(watcher =>
            {
                watcher.Update();
            });
        }
        /// <summary>
        /// 返回属性的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T Get<T>()
        {
            // Dep.Target 不为空时,标识指向这个属性的一个订阅者,需要将它加入到订阅列表
            bool flag = Dep.Target != null;
            if (flag)
            {
                this.PushWatcher(Dep.Target);
            }
            return this.oValue == null ? default(T) : (T)this.oValue;
        }
        /// <summary>
        /// 设置属性值
        /// </summary>
        /// <param name="oValue"></param>
        public void Set(object oValue)
        {
            bool flag = this.oValue == null || !this.oValue.Equals(oValue);
            if (flag)
            {
                this.oValue = oValue;
                this.Notify();
            }
        }
        /// <summary>
        /// 初始化队列,分配给每个属性
        /// </summary>
        /// <param name="count"></param>
        /// <returns></returns>
        public static List<Dep> InitDeps(int count)
        {
            if (count < 1) throw new Exception("wrong number! count must biger than 0");
            var lsDep = new List<Dep>();
            for (var i = 0; i < count; i++)
            {
                lsDep.Add(new Dep());
            }
            return lsDep;
        }
    }

    public class ViewBind
    {
        /// <summary>
        /// 默认绑定事件
        /// </summary>
        private string DefaultEvents = "CollectionChange|SelectedValueChanged|ValueChanged|TextChanged";
        /// <summary>
        /// 默认绑定的属性,从左往右,能找到则赋值
        /// </summary>
        private string DefaultProperty = "DataSource|Value|Text";


        /// <summary>
        /// 绑定视图
        /// </summary>
        /// <param name="ParentControl">父控件</param>
        /// <param name="model">模型(对象)</param>
        public ViewBind(System.Windows.Forms.Control ParentControl, object model)
        {
            this.BindingParentControl(ParentControl, model);
        }
        /// <summary>
        /// 绑定控件
        /// </summary>
        /// <param name="ParentControl">父控件</param>
        /// <param name="model">实体</param>
        private void BindingParentControl(System.Windows.Forms.Control ParentControl, object model)
        {
            this.BindControl(ParentControl, model, ParentControl.Controls);
        }
        /// <summary>
        /// 绑定控件
        /// </summary>
        /// <param name="ParentControl">父控件</param>
        /// <param name="model">实体</param>
        /// <param name="Controls">子控件列表</param>
        private void BindControl(System.Windows.Forms.Control ParentControl, object model, System.Windows.Forms.Control.ControlCollection Controls)
        {
            foreach (System.Windows.Forms.Control control in Controls)
            {
                var tag = control.Tag;

                if (tag == null) continue;
                foreach (var tagInfo in tag.ToString().Split('|'))
                {
                    var tagInfoArr = tagInfo.Split('-');
                    //属性绑定 如:V-WHName
                    if (tagInfoArr[0].Equals("dt") || tagInfoArr[0].Equals("v"))
                    {
                        var bindProperty = string.Empty;
                        if (tagInfoArr.Length == 2)
                        {

                            foreach (var property in DefaultProperty.Split('|'))
                            {
                                if (control.GetType().GetProperty(property) != null)
                                {
                                    bindProperty = property;
                                    break;
                                }
                            }
                        }
                        else if (tagInfoArr.Length == 3)
                        {
                            bindProperty = tagInfoArr[1];
                        }
                        else continue;

                        string propertyName = tagInfoArr[tagInfoArr.Length - 1];
                        this.BindingProperty(ParentControl, control, model, propertyName, bindProperty);
                        this.BindListener(control, model, propertyName, bindProperty);
                    }
                    else if (tagInfoArr[0].Equals("ev") && tagInfoArr.Length == 3)
                    {
                        //事件绑定
                        BindEvent(ParentControl, control, model, tagInfoArr[1], tagInfoArr[2]);
                    }
                    else
                    {
                        if (control.Controls.Count > 0)
                        {
                            this.BindControl(ParentControl, model, control.Controls);
                        }
                    }
                }

            }
        }
        /// <summary>
        /// 绑定事件
        /// </summary>
        /// <param name="ParentControl">父控件</param>
        /// <param name="control">要绑定事件的控件</param>
        /// <param name="model">实体</param>
        /// <param name="eventName">事件名称</param>
        /// <param name="methodName">绑定到的方法</param>
        private void BindEvent(System.Windows.Forms.Control ParentControl, System.Windows.Forms.Control control, object model, string eventName, string methodName)
        {
            var Event = control.GetType().GetEvent(eventName);
            if (Event != null)
            {
                var methodInfo = model.GetType().GetMethod(methodName);
                if (methodInfo != null)
                {
                    Event.AddEventHandler(control, new EventHandler((s, e) =>
                    {
                        ParentControl.Invoke(new Action(() =>
                        {
                            switch (methodInfo.GetParameters().Count())
                            {
                                case 0: methodInfo.Invoke(model, null); break;
                                case 1: methodInfo.Invoke(model, new object[] { new { s = s, e = e } }); break;
                                case 2: methodInfo.Invoke(model, new object[] { s, e }); break;
                                default: break;
                            }
                        }));
                    }));
                }
            }
        }
        /// <summary>
        /// 添加监听事件
        /// </summary>
        /// <param name="control">要监听的控件</param>
        /// <param name="model">实体</param>
        /// <param name="mPropertyName">变化的实体属性</param>
        /// <param name="controlPropertyName">对应变化的控件属性</param>
        private void BindListener(System.Windows.Forms.Control control, object model, string mPropertyName, string controlPropertyName)
        {
            var property = model.GetType().GetProperty(mPropertyName);

            var events = this.DefaultEvents.Split('|');
            foreach (var ev in events)
            {
                var Event = control.GetType().GetEvent(ev);
                if (Event != null)
                {
                    Event.AddEventHandler(control, new EventHandler((s, e) =>
                    {
                        try
                        {
                            var controlProperty = control.GetType().GetProperty(controlPropertyName);
                            if (controlProperty != null)
                            {
                                property.SetValue(model, Convert.ChangeType(controlProperty.GetValue(control, null), property.PropertyType), null);

                            }
                        }
                        catch (Exception ex)
                        {
                            //TPDO
                        }
                    }));
                }
            }
        }
        /// <summary>
        /// 绑定属性
        /// </summary>
        /// <param name="ParentControl">父控件</param>
        /// <param name="control">绑定属性的控件</param>
        /// <param name="model">实体</param>
        /// <param name="mPropertyName">绑定的实体属性名称</param>
        /// <param name="controlPropertyName">绑定到的控件的属性名称</param>
        private void BindingProperty(System.Windows.Forms.Control ParentControl, System.Windows.Forms.Control control, object model, string mPropertyName, string controlPropertyName)
        {

            Action<object> action = m =>
            {
                try
                {
                    var controlType = control.GetType();
                    var mType = m.GetType().GetProperty(mPropertyName);
                    var controlProperty = controlType.GetProperty(controlPropertyName);
                    if (controlProperty != null)
                    {
                        switch (controlPropertyName)
                        {
                            case "DataSource":
                                controlProperty.SetValue(control, mType.GetValue(m, null), null);
                                break;
                            default:
                                var val = Convert.ChangeType(mType.GetValue(m, null), controlProperty.PropertyType);
                                if (controlProperty.Name == "Text")
                                {
                                    control.Text = val.ToStr();break;
                                }

                                controlProperty.SetValue(control, val, null);
                                break;
                        }

                    }

                }
                catch (Exception ex)
                {
                    //TODO
                }
            };
            //添加到监听
            new Watcher(ParentControl, model.GetType(), model, mPropertyName, action);
            //初始化数据(将实体数据赋给控件属性)
            action(model);
        }
    }

}

2.调用方法

 //model 与控件实现双向绑定:
//使用方法:1.控件设置绑定的属性,对应控件的Tag属性:v-model的属性名  如v-WHName (仓库)
2. vm = new ViewBind(this.tableLayoutPanel2, 对象model);
var vm = new ViewBind(this.tableLayoutPanel2, 对象model);

3.属性绑定  要在tag里配置属性名;v-开头

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WinForms 中,ListBox 控件本身并没有直接提供双向绑定的功能。但是,你可以通过自己实现绑定机制来实现类似的效果。 一种常见的方法是使用数据绑定和 INotifyPropertyChanged 接口来实现双向绑定。以下是一个示例: 首先,创建一个数据模型类,该类包含要绑定到 ListBoxItem 的属性。例如: ```csharp public class ItemModel : INotifyPropertyChanged { private string _image; public string Image { get { return _image; } set { _image = value; OnPropertyChanged("Image"); } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } ``` 然后,在你的 WinForms 窗体中,将 ListBox 控件的 DataSource 属性设置为一个绑定的数据源,并将 DisplayMember 属性设置为要显示的属性名称。例如: ```csharp List<ItemModel> itemList = new List<ItemModel>(); // 添加数据项到 itemList listBox.DataSource = itemList; listBox.DisplayMember = "Image"; ``` 接下来,当你修改数据模型的属性时,界面不会自动更新。为了实现双向绑定,你可以在 ListBox 控件的 SelectedValueChanged 事件中更新数据模型的属性值。例如: ```csharp private void listBox_SelectedValueChanged(object sender, EventArgs e) { ItemModel selectedItem = listBox.SelectedItem as ItemModel; if (selectedItem != null) { selectedItem.Image = "path/to/new/image.png"; } } ``` 通过监听 SelectedValueChanged 事件并更新数据模型的属性,你可以实现在修改 ListBoxItem 的同时更新数据模型的属性值。 请注意,这只是一种基本的实现方式。如果你需要更复杂的绑定功能,可能需要使用第三方库或自定义控件来实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值