2016-03-10 3 views
0

Я искал способы наилучшего достижения этой задачи и остановился на этом.Использование Reflection для получения свойств объекта и отображения на Treeview

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

Это, кажется, дает мне то, что я надеялся, но когда я пытаюсь получить свойство объекта волоска, я в конечном итоге получить StackOverflow исключения. Похоже, что класс objectNode слишком много времени повторяется в рекурсивной манере, а затем происходит что-то, что вызывает stackoverflow? Я не уверен, как решить эту проблему и заставить ее работать даже для класса со многими свойствами (например, потоки), и любая помощь будет принята с благодарностью.

Класс 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() 
    { 
    } 
} 

Ошибка, которая выбрасывается в Еще раз «Необработанное исключение типа„System.StackOverflowException“произошло в mscorlib.dll»

, любой совет очень приветствуется.

ответ

1

Метод ParseObjectTree, вызываемый конструктором класса ObjectNode, как представляется, создает экземпляр других экземпляров этого класса рекурсивно и бесконечно. Это является причиной исключения StackOverflowException. Вам нужен алгоритм ограничения рекурсии, вероятно, путем подсчета числа поколений.

+0

Его не бесконечно, его просто потому, что класс Thread имеет много свойств. Таким образом, создание системы предполагает, что слишком много экземпляров. Как мне сказать, чтобы увеличить количество, которое он может рекурсивно назвать самим собой? – CJC

+0

Спасибо. Вы заставили меня подумать о том, чтобы ограничить количество вызовов рекурсии и глубину рекурсии, что заставило меня понять, что получение класса Thread растягивается бесконечно. – CJC

Смежные вопросы