I am trying to populate a datagrid (or gridview) as a child elment of a treeview from the database. I am able to get data from the DB in the tree, however, it doesnt seem to work for the datagrid. Here is my xaml code:
<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>
My codebehind is something like this:
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;
My Class file has this as a part of it:
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;
}
Please tell me how to implement it. I am new to this, so please excuse my stupid errors, and please try to explain in simple terms. Thank you.
This is what I actually need to do
The good news is that you're doing a lot more work here than you need to, which is probably why you're having trouble.
The bad news is that you should really study a little more about WPF to properly grok this and come up with a good approach that's clean and concise. I'll try and point you in the right direction.
Firstly, you should get your head around ItemsControl. It's a really powerful class and is the base class of many of the everyday controls you would use in a WPF application. You should understand how binding any collection (IEnumerable, IList, IBindingList etc) to the ItemsSource property of ItemsControl will cause child items to be created.
You should then understand (if you don't already) how data types are converted into UI elements via DataTemplates. This is a simple but powerful concept.
Then you should experiment with a small extension to the above, namely HeaderedItemsControl and HierarchicalDataTemplate. This will give you all the tools you need to use the TreeView in the way you want to.
At no point would you need to create any TreeViewItems in C# code. If you can get the underlying data objects to reflect the hierarchy you want to display (irrespective of whether each node is a simple text label or a data grid) then you can create hierarchical data templates for all levels and have WPF take care of binding everything and creating the TreeViewItems for you.
EDIT
I have some questions for your edited question:
Root
and Nodes
?Root
and Nodes
. I'll give you a made up example.Let's assume you have Customer
s who place Order
s, and each order has Item
s.
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; }
}
The above types represent a hierarchy. If you have a structure like this, then you can bind it directly to the UI. You don't need to create any Root
or Node
objects. This is the WPF way :)
(Note that if you don't have the above class hierarchy, you might set about creating one specifically for use in the UI. Read more about the MVVM pattern if you're interested.)
In your XAML you would define the TreeView as:
<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>
And in code-behind, you'd do something like this:
_treeView.DataContext = customers; // eg. IEnumerable<Customer>