将对象绑定到WPF TreeView

时间:2010-05-20 20:52:50

标签: c# wpf data-binding treeview

我想知道如何将自定义数据类型绑定到TreeView

数据类型基本上是包含其他arraylists的对象的arraylist。访问看起来像这样:

foreach (DeviceGroup dg in system.deviceGroups)
    {
        foreach (DeviceType dt in dg.deviceTypes)
        {
            foreach (DeviceInstance di in dt.deviceInstances)
            {

            }
        }
    }

我希望TreeView看起来像这样:

DeviceGroup1

 --> DeviceType1
      --DeviceInstance1
      --DeviceInstance2
 --> DeviceType2
      --DeviceInstance1

DeviceGroup2

 --> DeviceType1
      --DeviceInstance1
 --> DeviceType2

2 个答案:

答案 0 :(得分:7)

好的,这是HierarchicalDataTemplate将拯救你的地方。诀窍是你需要使用两个不同的分层模板,因为你在这里有一个三级层次结构。我构建了一个简单的UserControl来说明。首先,这里有一些代码隐藏创建类似于你的模型数据:

public partial class ThreeLevelTreeView : UserControl
{
    public ArrayList DeviceGroups { get; private set; }

    public ThreeLevelTreeView()
    {
        DeviceInstance inst1 = new DeviceInstance() { Name = "Instance1" };
        DeviceInstance inst2 = new DeviceInstance() { Name = "Instance2" };
        DeviceInstance inst3 = new DeviceInstance() { Name = "Instance3" };
        DeviceInstance inst4 = new DeviceInstance() { Name = "Instance4" };

        DeviceType type1 = new DeviceType() { Name = "Type1", DeviceInstances = new ArrayList() { inst1, inst2 } };
        DeviceType type2 = new DeviceType() { Name = "Type2", DeviceInstances = new ArrayList() { inst3 } };
        DeviceType type3 = new DeviceType() { Name = "Type3", DeviceInstances = new ArrayList() { inst4 } };
        DeviceType type4 = new DeviceType() { Name = "Type4" };

        DeviceGroup group1 = new DeviceGroup() { Name = "Group1", DeviceTypes = new ArrayList() { type1, type2 } };
        DeviceGroup group2 = new DeviceGroup() { Name = "Group2", DeviceTypes = new ArrayList() { type3, type4 } };

        DeviceGroups = new ArrayList() { group1, group2 };

        InitializeComponent();
    }
}

public class DeviceGroup
{
    public string Name { get; set; }
    public ArrayList DeviceTypes { get; set; }
}

public class DeviceType
{
    public string Name { get; set; }
    public ArrayList DeviceInstances { get; set; }
}

public class DeviceInstance
{
    public string Name { get; set; }
}

此处没有什么困难,但请注意,如果要动态添加和删除集合,则应使用ObservableCollection而不是ArrayList。现在让我们看看这个控件的XAML:

<UserControl x:Class="TestWpfApplication.ThreeLevelTreeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestWpfApplication"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<TreeView ItemsSource="{Binding DeviceGroups}">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding DeviceTypes}">
            <HierarchicalDataTemplate.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding DeviceInstances}">
                    <TextBlock Text="{Binding Name}"/>
                </HierarchicalDataTemplate>
            </HierarchicalDataTemplate.ItemTemplate>
            <TextBlock Text="{Binding Name}"/>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

结果如下:

alt text http://img684.imageshack.us/img684/6281/threeleveltreeview.png

答案 1 :(得分:0)

我最近不得不处理一个类似的问题,经过大量的研究才能够找到一个好的通用解决方案。我的问题有点普通:在树状视图中可视化.NET对象的属性。 所以给这个班 ```

class Person
{
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public List<Person> Children { get; set; }
}

I should see a tree like for an example instance:

- root
  - FirstName: John
  - LastName: Smith
  - Children:
    - [0]
      - FirstName: Ann
      - LastName: Smith

``` 使用反射并遍历对象的属性等相当困难。幸运的是,我们已经有了一个做到这一点的库-Ne​​wtonsoft.Json。 我的技巧是使用Newtonsoft.Json序列化对象,然后使用System.Web.Script.Serialization.JavaScriptSerializer反序列化。

JavaScriptSerializer返回ArrayLists和Dictionary,它们很容易遍历并添加到树中。

感谢this article给了我一些概念上的想法。

无论如何,这是完整的代码:

在XAML中:

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

在ViewModel中:

public IEnumerable<TreeNode> TreeItemsSource
{
    get
    {
        TreeNode tree = TreeNode.CreateTree(SelectedSession);
        return new List<TreeNode>() { tree };
    }
}

还有TreeNode类

public class TreeNode
{
    public string Name { get; set; }
    public string Value { get; set; }
    public List<TreeNode> Children { get; set; } = new List<TreeNode>();

    public static TreeNode CreateTree(object obj)
    {
        JavaScriptSerializer jss = new JavaScriptSerializer();
        var serialized = Newtonsoft.Json.JsonConvert.SerializeObject(obj);
        Dictionary<string, object> dic = jss.Deserialize<Dictionary<string, object>>(serialized);
        var root = new TreeNode();
        root.Name = "session";
        BuildTree2(dic, root);
        return root;
    }

    private static void BuildTree2(object item, TreeNode node)
    {
        if (item is KeyValuePair<string, object>)
        {
            KeyValuePair<string, object> kv = (KeyValuePair<string, object>)item;
            TreeNode keyValueNode = new TreeNode();
            keyValueNode.Name = kv.Key;
            keyValueNode.Value = GetValueAsString(kv.Value);
            node.Children.Add(keyValueNode);
            BuildTree2(kv.Value, keyValueNode);
        }
        else if (item is ArrayList)
        {
            ArrayList list = (ArrayList)item;
            int index = 0;
            foreach (object value in list)
            {
                TreeNode arrayItem = new TreeNode();
                arrayItem.Name = $"[{index}]";
                arrayItem.Value = "";
                node.Children.Add(arrayItem);
                BuildTree2(value, arrayItem);
                index++;
            }
        }
        else if (item is Dictionary<string, object>)
        {
            Dictionary<string, object> dictionary = (Dictionary<string, object>)item;
            foreach (KeyValuePair<string, object> d in dictionary)
            {
                BuildTree2(d, node);
            }
        }
    }

    private static string GetValueAsString(object value)
    {
        if (value == null)
            return "null";
        var type = value.GetType();
        if (type.IsArray)
        {
            return "[]";
        }

        if (value is ArrayList)
        {
            var arr = value as ArrayList;
            return $"[{arr.Count}]";
        }

        if (type.IsGenericType)
        {
            return "{}";
        }

        return value.ToString();
    }

}