一种利用C# Attribute实现数据的绑定

Posted on 周二 15 五月 2018 in 编程语言

一种利用C# Attribute实现数据的绑定

在日常开发中,经常会有数据和UI绑定的需求,即数据发生改变时,UI要随之改变。这里提供一个简单的思路,目的是尽量减少代码的编写。

ModelBase 数据存储基类

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

[AttributeUsage(AttributeTargets.Property, Inherited = false)]
public class ObservableName : Attribute
{
    public string name = String.Empty;

    public ObservableName(string bindName)
    {
        name = bindName;
    }
}

public class ModelBase
{
    public class ModelBindingInfo
    {
        public PropertyInfo propertyInfo = null;
        public ArrayList callbacks = new ArrayList();
    }

    private Dictionary<string, ModelBase.ModelBindingInfo> _bindingTable = new Dictionary<string, ModelBase.ModelBindingInfo>();

    public ModelBase()
    {
        collectObservableProperty();
    }

    private void collectObservableProperty()
    {
        _bindingTable.Clear();

        Type type = this.GetType();
        PropertyInfo[] propertyInfos = type.GetProperties();
        for (int i = 0; i < propertyInfos.Length; i++)
        {
            object[] obs = propertyInfos[i].GetCustomAttributes(false);
            for (int j = 0; j < obs.Length; j++)
            {
                ObservableName obName = obs[j] as ObservableName;
                if (obName != null && !_bindingTable.ContainsKey(obName.name))
                {
                    ModelBase.ModelBindingInfo bindingInfo = new ModelBase.ModelBindingInfo();
                    bindingInfo.propertyInfo = propertyInfos[i];
                    _bindingTable[obName.name] = bindingInfo;
                }
            }
        }
    }

    public void addObserverBinding<T>(string obName, Action<T> cb)
    {
        if (_bindingTable.ContainsKey(obName))
        {
            _bindingTable[obName].callbacks.Add(cb);
        }
    }

    public void removeObserverBinding<T>(string obName, Action<T> cb)
    {
        if (_bindingTable.ContainsKey(obName))
        {
            ArrayList callbacks = _bindingTable[obName].callbacks;
            callbacks.Remove(cb);
        }
    }

    public void setObservableData<T>(string obName, T data)
    {
        if (!_bindingTable.ContainsKey(obName))
        {
            return;
        }

        ModelBindingInfo bindingInfo = _bindingTable[obName];
        bindingInfo.propertyInfo.SetValue(this, data, null);

        T newData = (T)bindingInfo.propertyInfo.GetValue(this, null);

        //通知
        ArrayList callbacks = _bindingTable[obName].callbacks;
        for (int j = 0; j < callbacks.Count; j++)
        {
            Action<T> cb = (Action<T>)callbacks[j];
            cb(newData);
        }
    }
}

使用: 如果model中的某个property要被绑定,那么就加上ObservableName的属性,指定绑定的key, 然后就可以通过addObserverBinding来绑定行为了。

    class Person: ModelBase
    {
        [ObservableName("address")]
        public string address { get; set; }
    }

    class Test
    {
        public void testAttribute()
        {
            Person zhangwen = new Person();
            zhangwen.addObserverBinding<string>("address", onZhangwenAddrChange);

            Person shazi = new Person();
            shazi.addObserverBinding<string>("address", onShaziAddrChange);

            zhangwen.setObservableData("address", "caifugang");
            shazi.setObservableData("address", "baijin");
        }

        private void onShaziAddrChange(string obj)
        {
            Console.WriteLine("shazi's addr changed, new addr: " + obj);
        }

        private void onZhangwenAddrChange(string obj)
        {
            Console.WriteLine("zhangwen's addr changed, new addr: " + obj);
        }

        static void Main(string[] args)
        {
            TestAttribute test = new TestAttribute();
            test.testAttribute();
            Console.ReadKey();
        }
    }