代码之家  ›  专栏  ›  技术社区  ›  CJC

使用反射获取对象属性并显示在树视图上

  •  0
  • CJC  · 技术社区  · 8 年前

    我一直在寻找最好地完成这项任务的方法,并就此达成了共识。

    https://rbrundritt.wordpress.com/2012/01/30/view-object-properties-in-wpf-treeview/

    这似乎给了我希望的东西,但当我试图获取线程的对象属性时,我最终得到了stackoverflow异常。因此,objectNode类似乎以递归方式实例化了自己太多次,然后发生了导致堆栈溢出的事情?我不知道该如何解决这个问题,并使它即使在具有许多属性(如线程)的类中也能工作,任何帮助都将非常感谢。

    objectNode类如下所示

    using System;
    using System.Collections;
    using System.Collections.ObjectModel;
    using System.Reflection;
    
    namespace Server.Host
    {
        public class ObjectNode 
        {
            #region Private Properties
            private string _name;
            private object _value;
            private Type _type;
            #endregion
    
            #region Constructor
            public ObjectNode(object value) 
            {
                ParseObjectTree("root", value, value.GetType());
            }
    
            public ObjectNode(string name, object value)
            {
                ParseObjectTree(name, value, value.GetType());
            }
    
            public ObjectNode(object value, Type t)
            {
                ParseObjectTree("root", value, t);
            }
    
            public ObjectNode(string name, object value, Type t)
            {
                ParseObjectTree(name, value, t);
            }
            #endregion
    
            #region Public Properties
            public string Name
            {
                get { return _name; }
            }
    
            public object Value
            {
                get { return _value; }
            }
    
            public Type Type
            {
                get { return _type; }
            }
    
            public ObservableCollection<ObjectNode> Children { get; set; }
            #endregion
    
            #region Private Methods
            private void ParseObjectTree(string name, object value, Type type)
            {
                Children = new ObservableCollection<ObjectNode>();
    
                _type = type;
                _name = name;
    
                if (value != null)
                {
                    if (value is string && type != typeof(object))
                    {
                        if (value != null)
                        {
                            _value = "\"" + value + "\"";
                        }
                    }
                    else if (value is double || value is bool || value is int || value is float || value is long || value is decimal)
                    {
                        _value = value;
                    }
                    else
                    {
                        _value = "{" + value.ToString() + "}";
                    }
                }
    
                PropertyInfo[] props = type.GetProperties();
    
                if (props.Length == 0 && type.IsClass && value is IEnumerable && !(value is string))
                {
                    IEnumerable arr = value as IEnumerable;
    
                    if (arr != null)
                    {
                        int i = 0;
                        foreach (object element in arr)
                        {
                            Children.Add(new ObjectNode("[" + i + "]", element, element.GetType()));
                            i++;
                        }
                    }
                }
    
                foreach (PropertyInfo p in props)
                {
                    if (p.PropertyType.IsPublic)
                    {
                        if (p.PropertyType.IsClass || p.PropertyType.IsArray || p.PropertyType.IsInterface)
                        {
                            if (p.PropertyType.IsArray)
                            {
                                try
                                {
                                    object v = p.GetValue(value, null);
                                    IEnumerable arr = v as IEnumerable;
    
                                    ObjectNode arrayNode = new ObjectNode(p.Name, arr.ToString(), typeof(object));
    
                                    if (arr != null)
                                    {
                                        int i = 0, k = 0;
                                        ObjectNode arrayNode2;
    
                                        foreach (object element in arr)
                                        {
                                            //Handle 2D arrays
                                            if (element is IEnumerable && !(element is string))
                                            {
                                                arrayNode2 = new ObjectNode("[" + i + "]", element.ToString(), typeof(object));
    
                                                IEnumerable arr2 = element as IEnumerable;
                                                k = 0;
    
                                                foreach (object e in arr2)
                                                {
                                                    arrayNode2.Children.Add(new ObjectNode("[" + k + "]", e, e.GetType()));
                                                    k++;
                                                }
    
                                                arrayNode.Children.Add(arrayNode2);
                                            }
                                            else
                                            {
                                                arrayNode.Children.Add(new ObjectNode("[" + i + "]", element, element.GetType()));
                                            }
                                            i++;
                                        }
    
                                    }
    
                                    Children.Add(arrayNode);
                                }
                                catch { }
                            }
                            else
                            {
                                object v = p.GetValue(value, null);
    
                                if (v != null)
                                {
                                    Children.Add(new ObjectNode(p.Name, v, p.PropertyType));
                                }
                            }
                        }
                        else if (p.PropertyType.IsValueType && !(value is string))
                        {
                            try
                            {
                                object v = p.GetValue(value, null);
    
                                if (v != null)
                                {
                                    Children.Add(new ObjectNode(p.Name, v, p.PropertyType));
                                }
                            }
                            catch { }
                        }
                    }
                }
            }
    
            #endregion
        }
    }
    

    因此,可以将TreeView添加到WPF中,如下所示

    <TreeView Name="ResultTreeView" BorderThickness="0">
                    <TreeView.Resources>
                        <HierarchicalDataTemplate DataType="{x:Type local:ObjectNode}" 
                                                  ItemsSource="{Binding Path=Children}">
                            <TreeViewItem>
                                <TreeViewItem.Header>
                                    <StackPanel Orientation="Horizontal" Margin="-10,0,0,0">
                                        <TextBlock Text="{Binding Path=Name}"/>
                                        <TextBlock Text=" : "/>
                                        <TextBlock Text="{Binding Path=Value}"/>
                                    </StackPanel>
                                </TreeViewItem.Header>
                            </TreeViewItem>
                        </HierarchicalDataTemplate>
                    </TreeView.Resources>
                </TreeView>
    

    然后在我的代码中,我简单地写

    private Foo foo = new Foo();
    ObservableCollection<ObjectNode> nodes = new ObservableCollection<ObjectNode>();
    nodes.Add(new ObjectNode("result", foo));
    ResultTreeView.ItemsSource = nodes;
    

    其中Foo可以是任何类。在大多数情况下,它运行良好。但如果我在类中有一个线程,它会抛出一个异常。例如,一个简单的

    public class Foo
    {
        public Foo()
        {
            Bar = new Thread(Baz);
        }
    
        public Thread Bar { get; set; }
    
        private static void Baz()
        {
        }
    }
    

    引发的错误是 “mscorlib.dll中出现类型为“System.StackOverflowException”的未处理异常”

    再次,我们非常欢迎任何建议。

    1 回复  |  直到 8 年前
        1
  •  1
  •   emoacht    8 年前

    从ObjectNode类的构造函数调用的ParseObjectTree方法似乎递归且无休止地实例化了该类的其他实例。这是StackOverflowException的原因。您需要一个算法来限制递归,可能是通过计算生成次数。