分享一个UI与业务逻辑分层的框架(二)

序言

第一篇讲解了UI与业务逻辑分层的框架(UIMediator)的使用。本篇将说明该框架的原理及代码实现。

整体结构

UI与后台类绑定主要分为UI输入->后台属性,后台属性-UI更新两部分,为符合依赖倒置原则,分别抽象出IUIToProperty和IPropertyToUI两个接口。

为了匹配WinForm的窗体事件委托方法格式(object sender, EventArgs e)两个接口方法都实现了多态。

Mediator采用了模板方法的设计模式,实现了整个绑定方法的算法框架,子类只需实现ChangeType、BindPropertyValue、BindUIValue三个抽象方法即可。

TextBoxMediator、RadioButtonMediator、CheckBoxMediator为Mediator子类,根据各个不同的WinForm控件而实现的中介类,实现了上述三个抽象方法。

ChangeType:将Control基类转换为具体的控件类;

BindPropertyValue:实现UI输入->后台属性;

BindUIValue:实现后台属性-UI更新。

UML图如下所示。接下来讲解具体代码实现。

 

依赖倒置

UI输入->后台属性接口:IUIToProperty

 public interface IUIToProperty
    {
       void BindPropertyValue(object sender, EventArgs e);
       void BindPropertyValue(PropertyInfo prop);
    }

后台属性-UI更新接口:IPropertyToUI

public interface IPropertyToUI
    {
       void BindUIValue(object sender, EventArgs e);
       void BindUIValue(PropertyInfo prop);
    }

Mediator模板类

复制代码
 public abstract class Mediator:IUIToProperty,IPropertyToUI
    {
        protected Type type;
        protected object BindInstance;
        protected string BindProperty;

        public void Bind<T>(Control control, T BindInstance, string BindProperty) where T : class ,IPropertyChange
        {
            this.BindInstance = BindInstance as T;
            this.BindProperty = BindProperty;
            type = typeof(T);
            BindInstance.PropertyChanged += new EventHandler(BindUIValue);
            ChangeType(control);
            BindPropertyValue(null, null);
        }


        public void BindPropertyValue(object sender, EventArgs e)
        {
            BindPropertyValue(GetProperty());
        }

        private PropertyInfo GetProperty()
        {
            return type.GetProperties().First(c => c.Name == BindProperty);
        }

        public void BindUIValue(object sender, EventArgs e)
        {
            BindUIValue(GetProperty());
        }
        
        public abstract void BindPropertyValue(PropertyInfo prop);
        protected abstract void ChangeType(Control control);
        public abstract void BindUIValue(PropertyInfo propertyInfo);
复制代码

 TextBoxMediator类

复制代码
public class TextBoxMediator:Mediator
    {

       private TextBox tb;
       public override void BindPropertyValue(System.Reflection.PropertyInfo prop)
       {
           if (prop.PropertyType.IsValueType && string.IsNullOrEmpty(tb.Text))
           {
               prop.SetValue(BindInstance, 0, null);
               return;
           }
           try
           {
               object value = Convert.ChangeType(tb.Text, prop.PropertyType);
               prop.SetValue(BindInstance, value, null);
           }
           catch (FormatException fex)
           {
               throw fex;
           }
           catch (Exception ex)
           {
               throw ex;
           }
       }

       protected override void ChangeType(Control control)
       {
           tb = control as TextBox;
           tb.TextChanged+=new EventHandler(BindPropertyValue);
       }

       public override void BindUIValue(System.Reflection.PropertyInfo prop)
       {
           tb.Text = prop.GetValue(BindInstance, null).ToString();
       }
    }
复制代码

CheckBoxMediator类

复制代码
public class CheckBoxMediator:Mediator
    {

       private CheckBox cb;
       public override void BindPropertyValue(PropertyInfo prop)
       {
           prop.SetValue(BindInstance, cb.Checked, null);
       }

       protected override void ChangeType(Control control)
       {
           cb = control as CheckBox;
           cb.CheckedChanged += new EventHandler(BindPropertyValue);
       }

       public override void BindUIValue(PropertyInfo prop)
       {
           cb.Checked = Convert.ToBoolean(prop.GetValue(BindInstance, null));
       }

    }
复制代码

RadioButtonMediator类

复制代码
public class RadioButtonMediator:Mediator
    {
       RadioButton rb;
       public override void BindPropertyValue(System.Reflection.PropertyInfo prop)
        {
            prop.SetValue(BindInstance, rb.Checked, null);

        }
        protected override void ChangeType(System.Windows.Forms.Control control)
        {
            rb = control as RadioButton;
            rb.CheckedChanged += new EventHandler(BindPropertyValue);
        }
public override void BindUIValue(System.Reflection.PropertyInfo prop) { rb.Checked = Convert.ToBoolean(prop.GetValue(BindInstance, null)); } }
复制代码

 关于后台属性-UI更新的说明

分析下Mediator类中的Bind方法

复制代码
 public void Bind<T>(Control control, T BindInstance, string BindProperty) where T : class ,IPropertyChange
        {
            this.BindInstance = BindInstance as T;
            this.BindProperty = BindProperty;
            type = typeof(T);
            BindInstance.PropertyChanged += new EventHandler(BindUIValue);
            ChangeType(control);
            BindPropertyValue(null, null);
        }
复制代码

泛型T有一个IPropertyChange的约束,具有PropertyChanged事件,用来注册绑定BindUIValue方法。

IPropertyChange的代码如下

public interface IPropertyChange
    {
        event EventHandler PropertyChanged;
        void UpdateUI();
    }

由于.NET只支持类的单继承,为避免框架对代码的侵入性选择了接口继承。

后台类通过继承IPropertyChange,在UpdateUI实现方法中调用PropertyChanged事件。

在需要后台驱动UI更新时调用UpdateUI方法即可。

 public void UpdateUI()
            {
                PropertyChanged(null, null);
            }
posted @   蜡笔小黄  阅读(2336)  评论(3编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
点击右上角即可分享
微信分享提示