COMMON.cs 10.4 KB
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace FObjBase.Reflect
{
    static class COMMON
    {
        static bool IsPropertyPush(PropertyInfo propertyInfo)
        {
            if (propertyInfo.GetCustomAttribute<PropertyPushAttribute>() == null)
                return false;//必须是[PropertyPush]

            if (!typeof(INotifyPropertyChanged).IsAssignableFrom(propertyInfo.PropertyType))
                return false;//必须是从INotifyPropertyChanged派生的

            return true;
        }

        /// <summary>
        /// 获取全部属性, 包括父类的属性, 可能有重复的
        /// </summary>
        /// <returns></returns>
        public static List<PropertyInfo> GetAllPropertyInfos(Type interfaceType)
        {
            var interfaceTypes = new List<Type>();
            interfaceTypes.Add(interfaceType);
            interfaceTypes.AddRange(interfaceType.GetInterfaces());
            var propertyInfos = new List<PropertyInfo>();//获取全部属性, 包括父类的属性
            foreach (var ifaceType in interfaceTypes)
            {
                propertyInfos.AddRange(ifaceType.GetProperties());
            }
            return propertyInfos;
        }





        public static void InitPropertyPush(SubPropertyNode rootNode)
        {
            //处理[PropertyPush]
            var propertyInfos = GetAllPropertyInfos(rootNode.InterfaceType);

            foreach (var propertyInfo in propertyInfos)
            {
                if (propertyInfo.GetCustomAttribute<PropertyPushAttribute>() == null)
                    continue;//必须是[PropertyPush]

                SubPropertyNode node = new SubPropertyNode();
                if (ReInitPropertyPush(node, rootNode.Obj, propertyInfo, rootNode.SubPropertyChanged))
                {
                    node.Parent = rootNode;
                    rootNode.Children.Add(node);
                }
            }
        }
        public static bool ReInitPropertyPush(SubPropertyNode node, object parentObj, PropertyInfo propertyInfo, SubPropertyChangedEventHandler sub_PropertyChanged)
        {
            var propertyValue = propertyInfo.GetValue(parentObj);
            // propertyValue==null 也注册

            if (typeof(INotifyPropertyChanged).IsAssignableFrom(propertyInfo.PropertyType))
            {
                //必须是从INotifyPropertyChanged派生的
                node.Name = propertyInfo.Name;
                node.InterfaceType = propertyInfo.PropertyType;
                node.Obj = propertyValue;
                node.SubPropertyChanged = sub_PropertyChanged;

                if (node.Obj != null)
                {
                    //下级推送!!!!
                    ((INotifyPropertyChanged)(propertyValue)).PropertyChanged += node.PropertyChanged;
                    InitSubPropertyPush(propertyValue, node, sub_PropertyChanged);
                }
                return true;
            }
            else if (typeof(System.Collections.IList).IsAssignableFrom(propertyInfo.PropertyType))
            {
                //数组
                node.Name = propertyInfo.Name;
                node.InterfaceType = propertyInfo.PropertyType;
                node.Obj = propertyValue;
                node.IsArray = true;

                var list = node.Obj as System.Collections.IList;

                if (list != null && list.Count > 0)
                {
                    InitSubPropertyPushs(list, node, sub_PropertyChanged);
                }

                return true;

            }
            return false;
        }

        static void InitSubPropertyPush(object obj, SubPropertyNode node, SubPropertyChangedEventHandler sub_PropertyChanged)
        {

            //继续向下找
            var propertyInfos = obj.GetType().GetProperties();
            foreach (var propertyInfo in propertyInfos)
            {
                if (!IsPropertyPush(propertyInfo))
                    continue;//必须是[PropertyPush]

                var element = propertyInfo.GetValue(obj);

                var node_sub = new SubPropertyNode()
                {
                    Name = propertyInfo.Name,
                    InterfaceType = propertyInfo.PropertyType,
                    Obj = element,
                    Parent = node,
                    SubPropertyChanged = sub_PropertyChanged
                };
                //下级推送!!!!
                ((INotifyPropertyChanged)(element)).PropertyChanged += node_sub.PropertyChanged;
                node.Children.Add(node_sub);

                InitSubPropertyPush(element, node_sub, sub_PropertyChanged);
            }
        }
        static void InitSubPropertyPushs(System.Collections.IList list, SubPropertyNode node, SubPropertyChangedEventHandler sub_PropertyChanged)
        {
            for (int i = 0; i < list.Count; i++)
            {
                var element = list[i];
                if (element == null)
                {
                    //空的。。。
                    continue;
                }
                var elementType = element.GetType();
                if (!typeof(INotifyPropertyChanged).IsAssignableFrom(elementType))
                {
                    //异常!!!!
                    continue;
                }

                var node_sub = new SubPropertyNode()
                {
                    Name = $"[{i}]",
                    InterfaceType = elementType,
                    Obj = element,
                    Parent = node,
                    SubPropertyChanged = sub_PropertyChanged
                };
                //下级推送!!!!
                ((INotifyPropertyChanged)(element)).PropertyChanged += node_sub.PropertyChanged;

                node.Children.Add(node_sub);

                InitSubPropertyPush(element, node_sub, sub_PropertyChanged);
            }
        }


        public static string GetNodePath(SubPropertyNode node)
        {
            if (string.IsNullOrEmpty(node.Name))
            {
                //已经是最上级
                return null;
            }

            StringBuilder sb = new StringBuilder();
            sb.Append(node.Name);

            while (node.Parent != null)
            {
                node = node.Parent;
                if (string.IsNullOrEmpty(node.Name))
                {
                    //到了最上级
                    break;
                }
                sb.Insert(0, node.Name + ".");
            }
            return sb.ToString();
        }
        public static SubPropertyNode FindNode(SubPropertyNode rootNode, string path)
        {
            SubPropertyNode node = null;
            if (string.IsNullOrEmpty(path))
                return rootNode;

            var nodes = rootNode.Children;
            //分解路径
            string[] names = path.Split('.');
            foreach (string name in names)
            {
                if (string.IsNullOrEmpty(name))
                {
                    //这个不算
                    continue;
                }
                node = nodes.Find(n => n.Name == name);
                if (node == null)
                {
                    //异常
                    return null;
                }
                nodes = node.Children;
            }
            return node;
        }
        public static void NodeChildrenDispose(List<SubPropertyNode> nodes)
        {
            foreach (var node in nodes)
            {
                NodeDispose(node);
            }
        }
        public static void NodeDispose(SubPropertyNode node)
        {
            if (!node.IsArray)
            {
                if (node.Obj != null && node.Obj is INotifyPropertyChanged)
                    ((INotifyPropertyChanged)(node.Obj)).PropertyChanged -= node.PropertyChanged;
            }

            if (node.Children.Count > 0)
                NodeChildrenDispose(node.Children);

            node.Children.Clear();
            node.Obj = null;
            node.Parent = null;
        }

        /// <summary>
        /// 处理因为服务器 修改了 [PropertyPush] 的对象, 需要重新注册推送事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public static void PropertyChanged_reInitPropertyPush(SubPropertyNode node, PropertyChangedEventArgs e)
        {
            var sub_node = node.Children.Find(n => n.Name == e.PropertyName);
            if (sub_node == null)
                return;

            //这个被修改了
            //卸载它
            COMMON.NodeDispose(sub_node);

            var propertyInfo = node.Obj.GetType().GetProperty(e.PropertyName);

            //重新注册
            COMMON.ReInitPropertyPush(sub_node, node.Obj, propertyInfo, node.SubPropertyChanged);
        }
    }

    /// <summary>
    /// 子属性节点,用于注册 INotifyPropertyChanged
    /// </summary>
    class SubPropertyNode
    {
        /// <summary>
        /// 下级节点
        /// </summary>
        public List<SubPropertyNode> Children = new List<SubPropertyNode>();
        /// <summary>
        /// 上级节点
        /// </summary>
        public SubPropertyNode Parent;
        /// <summary>
        ///  节点名称;
        ///  正常情况,就是属性的Name;
        ///  但,当为数组时, 它的下级就是数组的元素。 元素不是数组的属性。 元素的name为  $"[{序号}]"
        /// </summary>
        public string Name;
        /// <summary>
        /// 节点对象
        /// </summary>
        public object Obj;
        /// <summary>
        /// 对象的模板接口。默认就是 Obj.GetType()
        /// </summary>
        public Type InterfaceType;
        /// <summary>
        /// 是数组
        /// </summary>
        public bool IsArray;

        public PropertyChangedEventHandler PropertyChanged;

        public SubPropertyChangedEventHandler SubPropertyChanged;
        public SubPropertyNode()
        {
            PropertyChanged = new PropertyChangedEventHandler(_PropertyChanged);
        }
        public void _PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            //处理[PropertyPush]重新注册问题
            COMMON.PropertyChanged_reInitPropertyPush(this, e);

            SubPropertyChanged?.Invoke(this, e);
        }
    }
    delegate void SubPropertyChangedEventHandler(SubPropertyNode node, PropertyChangedEventArgs e);
}