分享一個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);
            }


免責聲明!

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



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