了解WPF数据将List <objects>绑定到TreeView

时间:2016-03-09 08:34:54

标签: c# .net wpf xaml treeview

我正在努力学习和理解XAML中的WPF TreeView和数据绑定。我似乎无法掌握数据绑定的概念,非常感谢您的帮助。

ISSUE 在TreeView中不显示任何内容。我最感兴趣的是了解如何将WPF中的数据正确绑定到对象以实现树视图。

概念:考虑具有一组主题的SubjectList。为了这个例子,每个主题只有一个学生

TreeView中的预期输出

Maths
    Student 1
Science
    Student 2
Arts
    Student 3

我当前的XAML尝试基于此处阅读的教程http://blogs.microsoft.co.il/pavely/2014/07/12/data-binding-for-a-wpf-treeview/

在此之后,我有以下XAML:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApplication1"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<StackPanel>
    <TreeView x:Name="treeView" HorizontalAlignment="Left"
              Height="284" 
              Margin="18,10,0,0" 
              VerticalAlignment="Top" 
              Width="115"
              ItemsSource="{Binding SubjectList}">
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding SubjectList}" 
                                      DataType="{x:Type local:Subject}">
                <TreeViewItem Header="{Binding SubjectName}"/>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>
</StackPanel>

MainWindow函数将Student对象添加到StudentList中:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        Student s1 = new Student("Alex", 1);
        Student s2 = new Student("Kevin", 2);
        Student s3 = new Student("Sina", 3);
        Student s4 = new Student("Evan", 4);

        Subject a1 = new Subject("Maths", 1);
        Subject a2 = new Subject("Science", 2);
        Subject a3 = new Subject("Arts", 3);

        a1.setStudent(s1);
        a2.setStudent(s2);
        a3.setStudent(s3);

        Subjects list = new Subjects();
        list.AddSubjects(a1);
        list.AddSubjects(a2);
        list.AddSubjects(a3);
        DataContext = list;
    }
}

class Subjects
    {
        private List<Subject> subjectList;
        public List<Subject> SubjectList { get; set;}


        public Subjects()
        {
            SubjectList = new List<Subject>();
        }

        public void AddSubjects(Subject s)
        {
            SubjectList.Add(s);
        }
    }

     class Subject
    {
        private String subjectName;
        private List<Student> studentList;
        //accessor methods
        public String SubjectName { get; set; }
        public List<Student> StudentList { get; }
        public Subject()
        {
        }

        public Subject(string name, int id)
        {
            SubjectName = name;
            StudentList = new List<Student>();

        }

        public void setStudent(Student aStudent)
            {
                StudentList.Add(aStudent);
            }
    }

    class Student
    {
        public Student()
        {
        }

        public Student(string name, int id)
        {
            StudentName = name;
            StudentID = id;
        }

        private String studentName;
        private int studentID;

        //accessor methods
        public String StudentName { get; set;}
        public int StudentID { get; set; }

    }

}

我做错了什么?任何能指出我正确方向的人都能更好地理解WPF中数据绑定的概念到一个对象列表,这将是我自学的一个巨大帮助!

更新1 :设置DataContext = list;并删除XAML中的DataContext引用解决了定义两个View的问题。

问题2::我仍然对View感到困惑。我添加了一个List作为Subject Class的属性。

如何从XAML中主题对象内的Student对象列表中检索学生名称?对于希望在TreeView中显示的任何/每个集合,您是否需要View?我希望了解这些作品如何协同工作。任何进一步的材料或协助非常感谢。

2 个答案:

答案 0 :(得分:1)

您正在创建Subjects视图模型的两个实例,一个在XAML中

<Window.DataContext>
     <local:Subjects/>
</Window.DataContext>

和代码中的一个

Subjects list = new Subjects();

在后面的代码中向list实例添加项目不会将它们添加到DataContext中的实例。

更改您的代码:

var list = (Subjects)DataContext;
list.AddSubjects(a1);
...

或者从XAML中删除DataContext赋值并将代码写在后面:

var list = new Subjects();
list.AddSubjects(a1);
...
DataContext = list;

也就是说,使用ObservableCollection代替List来通知收集更改可能是有意义的,例如在添加或删除主题时。

答案 1 :(得分:0)

所以我相信你的困惑植根于绑定的概念,所以我会试着为你澄清一下。

使用您发布的代码:

    <Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApplication1"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<StackPanel>
    <TreeView x:Name="treeView" HorizontalAlignment="Left"
              Height="284" 
              Margin="18,10,0,0" 
              VerticalAlignment="Top" 
              Width="115"
              ItemsSource="{Binding SubjectList}">
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding SubjectList}" 
                                      DataType="{x:Type local:Subject}">
                <TreeViewItem Header="{Binding SubjectName}"/>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>
</StackPanel>

在您的代码中,您将datacontext设置为Subjects实例。这意味着窗口的datacontext是Subjects。

现在,当你深入到xaml时,你会到达stackpanel。这会继承相同的datacontext,因此stackpanel的datacontext仍然是Subjects。

现在进入树视图。 treeview的datacontext仍然是Subjects,这就是为什么你能够将ItemsSource属性绑定到SubjectList类上的属性SubjectList的原因。

现在,当你到达TreeView.ItemTemplate时,datacontext是来自SubjectList的单个项目,也就是Subject的实例。

HierachicalDataTemplate仍然使用Subject实例的相同上下文。您不能将HierarchicalDataTemplate的ItemsSource绑定到SubjectList,因为Subject类没有该属性。

您可以绑定到StudentList,因为Subject类确实具有该属性。

如果您要将ItemsSource绑定到StudentList,那么您可以在HierarchicalDataTemplate内部放置一个TextBox,其绑定到主题名称,因为HierachicalDataTemplate内部具有单个StudentItem的DataContext

所以最后工作代码看起来像这样:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApplication1"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<StackPanel>
    <TreeView x:Name="treeView" HorizontalAlignment="Left"
              Height="284" 
              Margin="18,10,0,0" 
              VerticalAlignment="Top" 
              Width="115"
              ItemsSource="{Binding SubjectList}">
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding StudentList}">
                <TextBox Text="{Binding StudentName}"/>
                <TextBox Text=" "/>
                <TextBox Text="{Binding ID}"/>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>
</StackPanel>

所以总的来说你非常接近,但是我希望这可以帮助你理解当你深入研究绑定时会发生什么。如果你对任何事情感到困惑,请发表评论,我会尽量让它更清楚