如何在WPF应用程序中将GridView设置为TreeView的子元素

3

我正在尝试从数据库中获取数据并将其作为树视图的子元素填充到数据网格(或网格视图)中。我能够在树中从数据库中获取数据,但似乎对于数据网格无效。以下是我的XAML代码:

<Window x:Class="AttemptUsingHirarchichalData.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:data="clr-namespace:AttemptUsingHirarchichalData"
    xmlns:my="http://schemas.microsoft.com/wpf/2008/toolkit"
    Title="Window1" Height="300" Width="300">
<Window.Resources>
    <HierarchicalDataTemplate DataType="{x:Type data:Root}"
                              ItemsSource="{Binding Path=RootList}">
        <TextBlock Text="{Binding RootNode}"/>
        
    </HierarchicalDataTemplate>
    <HierarchicalDataTemplate DataType="{x:Type data:Nodes}"
                              ItemsSource="{Binding Path=ChildList}">
        
        <TextBlock Text="{Binding ChildNode}"/>
    </HierarchicalDataTemplate>
</Window.Resources>

<Grid>
    <TreeView Name="TreeView1">
        <TreeViewItem ItemsSource="{Binding Path=RootList}"
                      Header="{Binding RootNode}"/>
        <TreeViewItem ItemsSource="{Binding Path=dt_Age}"
                      Header="{Binding dt_Age}"/>
    </TreeView>
   
</Grid>

我的代码后端类似这样:

InitializeComponent();

Root obj_Root = new Root();
obj_Root.RootNode = "RootNode";
obj_Root.RootList = new List<Nodes>();

Class1 obj_Class1 = new Class1();
DataTable dt_Age = obj_Class1.GetAgeInComboBox();

for (int i = 0; i < dt_Age.Rows.Count; i++)
{
    Nodes obj_AgeNode = new Nodes();
    obj_AgeNode.ChildNode = dt_Age.Rows[i][0].ToString();
    obj_Root.RootList.Add(obj_AgeNode);

    Class1 obj_class = new Class1();
    DataTable dt_name = new DataTable();
    dt_name = obj_class.GetName(Convert.ToInt32(dt_Age.Rows[i][0]));
    obj_AgeNode.ChildList = new List<Nodes>();
    //gridv
    for (int j = 0; j < dt_name.Rows.Count; j++)
    {
        Nodes obj_NameNode = new Nodes();
        obj_NameNode.ChildNode = dt_name.Rows[j][0].ToString();
        obj_AgeNode.ChildList.Add(obj_NameNode);
    }
}

TreeView1.DataContext = obj_Root;

我的Class文件中有这样的一部分:

public class Nodes
{
    public string ChildNode { get; set; }
    public List<Nodes> ChildList { get; set; }
}

public class Root
{
    public string RootNode { get; set; }
    public List<Nodes> RootList { get; set; }
}

 public DataTable GetAgeInComboBox()
 {
     SqlDataAdapter da_Age = new SqlDataAdapter("select distinct Age from myfrstattemt", conn1);
     DataTable dt_Age = new DataTable();
     da_Age.Fill(dt_Age);
     return dt_Age;
 }

请告诉我如何实现它。我是新手,请原谅我的愚蠢错误,并尽量用简单的语言解释。谢谢。
这就是我实际需要做的。

2个回答

11
好消息是你在这里做的工作比你实际上需要做的要多得多,这可能是你遇到问题的原因。
坏消息是你应该更多地学习关于 WPF 的知识,以便透彻理解并提出干净简洁的好方法。我将尝试指引你朝正确的方向前进。
首先,你应该了解 ItemsControl。它是一个非常强大的类,是许多日常控件的基类,你会在 WPF 应用程序中使用它们。你应该明白如何将任何集合 (IEnumerable、IList、IBindingList 等) 绑定到 ItemsControl 的 ItemsSource 属性上,从而创建子项。
然后,你应该了解 (如果你还没有) 数据类型如何通过 DataTemplates 转换为 UI 元素。这是一个简单但强大的概念。
接下来,你应该尝试对以上内容进行小小的扩展,即 HeaderedItemsControl 和 HierarchicalDataTemplate。这将为你提供使用 TreeView 所需的所有工具。
在任何时候,你都不需要在 C# 代码中创建任何 TreeViewItem。如果你可以让底层数据对象反映出你想要显示的层次结构(无论每个节点是一个简单的文本标签还是一个数据网格),那么你可以为所有层级创建分层数据模板,并让 WPF 处理所有绑定和创建 TreeViewItem 的工作。
编辑:
我有一些问题要问你的修改后的问题:
1. Root 和 Nodes 之间有什么区别?
2. 你是否有一个类层次结构来模拟节点之间的关系?如果是这样,请使用它而不是将对象复制到 Root 和 Nodes 的实例中。我会给你举个虚构的例子。
假设你有客户 (Customers) 下订单 (Orders),每个订单都有物品 (Items)。
public class Customer
{
    public string Name { get; set; }
    public IEnumerable<Order> Orders { get; set; }
}

public class Order
{
    public DateTime PurchaseDate { get; set; }
    public IEnumerable<OrderItem> Items { get; set; }
}

public class OrderItem
{
    public string ProductName { get; set; }
    public int Quantity { get; set; }
    public double UnitPrice { get; set; }
    public double TotalPrice { get; set; }
}
上述类型表示一种层次结构。如果你有这样的一个结构,那么你可以直接将它绑定到用户界面(UI)上,不需要创建任何RootNode对象。这就是WPF方式 :) (请注意,如果你没有上述类层次结构,你可能会着手创建一个特定用于UI的层次结构。如果感兴趣,可以阅读更多关于MVVM模式的内容。) 在你的XAML中,你可以定义TreeView如下:
<TreeView x:Name="_treeView" ItemsSource="{Binding}">
  <TreeView.Resources>
    <HierarchicalDataTemplate DataType="{x:Type data:Customer}"
                              ItemsSource="{Binding Path=Orders}">
      <TextBlock Text="{Binding Name}"/>
    </HierarchicalDataTemplate>
    <DataTemplate DataType="{x:Type data:Order}">
      <StackPanel>
        <TextBlock Text="{Binding PurchaseDate}"/>
        <ListView ItemsSource="{Binding Items}">
          <ListView.View>
            <GridView>
              <GridViewColumn DisplayMemberBinding="{Binding ProductName}" />
              <GridViewColumn DisplayMemberBinding="{Binding Quantity}" />
              <GridViewColumn DisplayMemberBinding="{Binding UnitPrice}" />
              <GridViewColumn DisplayMemberBinding="{Binding TotalPrice}" />
            </GridView>
          </ListView.View>
        </ListView>
      </StackPanel>
    </DataTemplate>
  </TreeView.Resources>
</TreeView>

在代码后台,你需要这样做:

 _treeView.DataContext = customers; // eg. IEnumerable<Customer>

嘿,Drew,感谢你提供的又一个简单易懂的答案。在阅读了你写的内容后,我重新设计了我的代码,现在,在C#代码中不再定义任何treeviewitem。但是我仍然无法理解如何将gridview变成treeview的子节点。你能帮我解决这个问题吗?我正在编辑我的问题上面的代码以反映我所做的更改。请尽快回复我,我真的很依赖你... - Gagan
嗨,Gagan。看起来你已经取得了一些不错的进展。这里已经很晚了,所以我明天早上再看看这个。 - Drew Noakes
嗨,Drew,你的评论给了我信心和希望!我真的很指望你。此外,我想告诉你,我进行了一些研究,发现有一个名为DataGrid的类,位于Microsoft.Windows.Controls命名空间中。所以,我创建了这个类的对象(DataGrid obj_dgv=new DataGrid),并将其与数据表绑定(obj_dgv.ItemsSource=dt.DefaultView)。然后将这个对象作为树的子节点(obj_tree.RootList.Add(obj_dgv))。但是,这返回了一个错误...所以我又陷入了无助的境地。请帮忙!!! - Gagan
嗨,德鲁,感谢您所有的出色解释。我尝试了您告诉我的一切,它按照应该的方式工作。然而,对于我来说仍然非常复杂(我是非常新手,希望您知道)。所以,我在摸索着我所知道的一点东西,突然想到了这个: DataGrid dgobj=new DataGrid(); dgobj=DataTableObj.DefaultView; treeobj.Items.Add(dgobj); 就这样!我把数据网格作为树的子节点得到了!!!:) :) - Gagan

0

我无法理解你所提到的帖子......你能否给我推荐一篇更简单的帖子......适合业余爱好者的那种???拜托了!!! - Gagan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接