Answered by:
Binding a WPF Tree View to a DataSet having multiple relations

Question
-
I have a dataSet that has multiple relations i.e there are multiple tables inside the DataSet. DataTable1 is parent of DataTable2 which is parent of DataTable3 ...
i want to bind this to a TreeView so that I get nested nodes i.e multiple levels (one beneath the other according to the relations). I know how to dothis in case there is one master child relation.(By using hierarchical DataTemplate)How can I do this .
Thanks and Regards
Abhinav
Wednesday, September 12, 2007 4:28 AM
Answers
-
Hi Abhinav
The main point in binding dataset with treeview is that specifying the relation name as the binding source of treeview sub nodes. The following example shows how to do this. In the example, I use a strong typed dataset as the data source. Per customer has multiple orders, and per order has multiple order details. The relation name of the dataset between customer and order is Customer_Order. The relation name of the dataset between order and order details is Order_OrderDetail.
The structure of the dataset is,
Customer:
CustomerId, Primary Key
CustomerName
Order:
OrderId, Primary Key
OrderDate
CustomerId, Foreign key (Customer_Order)
OrderDetail:
OrderDetailId, Primary Key
OrderId, Foreign key (Order_OrderDetail)
Product
Code Snippet<Window.Resources>
<local:TestDataSet x:Key="DataSet"/> <DataTemplate x:Key="OrderDetailTemplate"> <TextBlock Text="{Binding Product}"/> </DataTemplate> <HierarchicalDataTemplate x:Key="OrderTemplate" ItemsSource="{Binding Order_OrderDetail}" ItemTemplate="{StaticResource OrderDetailTemplate}"> <TextBlock Text="{Binding OrderDate}"/> </HierarchicalDataTemplate> <HierarchicalDataTemplate x:Key="CustomerTemplate" ItemsSource="{Binding Customer_Order}" ItemTemplate="{StaticResource OrderTemplate}"> <TextBlock Text="{Binding CustomerName}"/> </HierarchicalDataTemplate> </Window.Resources> <TreeView ItemsSource="{Binding Source={StaticResource DataSet}, Path=Customer}" ItemTemplate="{StaticResource CustomerTemplate}"/> public partial class MainWindow : Window{
public MainWindow(){
InitializeComponent();
TestDataSet ds = (TestDataSet)this.Resources["DataSet"];ds.Customer.AddCustomerRow(1,
"Customer1");ds.Customer.AddCustomerRow(2,
"Customer2");ds.Order.AddOrderRow(1,
new DateTime(2007, 10, 1), ds.Customer[0]);ds.Order.AddOrderRow(2,
new DateTime(2007, 10, 2), ds.Customer[0]);ds.Order.AddOrderRow(3,
new DateTime(2007, 10, 3), ds.Customer[1]);ds.Order.AddOrderRow(4,
new DateTime(2007, 10, 4), ds.Customer[1]);ds.Order.AddOrderRow(5,
new DateTime(2007, 10, 5), ds.Customer[1]);ds.OrderDetail.AddOrderDetailRow(1, ds.Order[0],
"ProductA");ds.OrderDetail.AddOrderDetailRow(2, ds.Order[0],
"ProductB");ds.OrderDetail.AddOrderDetailRow(3, ds.Order[1],
"ProductC");ds.OrderDetail.AddOrderDetailRow(4, ds.Order[1],
"ProductD");ds.OrderDetail.AddOrderDetailRow(5, ds.Order[2],
"ProductE");ds.OrderDetail.AddOrderDetailRow(6, ds.Order[2],
"ProductF");ds.OrderDetail.AddOrderDetailRow(7, ds.Order[3],
"ProductG");ds.OrderDetail.AddOrderDetailRow(8, ds.Order[3],
"ProductH");ds.OrderDetail.AddOrderDetailRow(9, ds.Order[4],
"ProductI");}
}
Best Regards
Wei Zhou
Friday, September 14, 2007 8:49 AM
All replies
-
Hi Abhinav
The main point in binding dataset with treeview is that specifying the relation name as the binding source of treeview sub nodes. The following example shows how to do this. In the example, I use a strong typed dataset as the data source. Per customer has multiple orders, and per order has multiple order details. The relation name of the dataset between customer and order is Customer_Order. The relation name of the dataset between order and order details is Order_OrderDetail.
The structure of the dataset is,
Customer:
CustomerId, Primary Key
CustomerName
Order:
OrderId, Primary Key
OrderDate
CustomerId, Foreign key (Customer_Order)
OrderDetail:
OrderDetailId, Primary Key
OrderId, Foreign key (Order_OrderDetail)
Product
Code Snippet<Window.Resources>
<local:TestDataSet x:Key="DataSet"/> <DataTemplate x:Key="OrderDetailTemplate"> <TextBlock Text="{Binding Product}"/> </DataTemplate> <HierarchicalDataTemplate x:Key="OrderTemplate" ItemsSource="{Binding Order_OrderDetail}" ItemTemplate="{StaticResource OrderDetailTemplate}"> <TextBlock Text="{Binding OrderDate}"/> </HierarchicalDataTemplate> <HierarchicalDataTemplate x:Key="CustomerTemplate" ItemsSource="{Binding Customer_Order}" ItemTemplate="{StaticResource OrderTemplate}"> <TextBlock Text="{Binding CustomerName}"/> </HierarchicalDataTemplate> </Window.Resources> <TreeView ItemsSource="{Binding Source={StaticResource DataSet}, Path=Customer}" ItemTemplate="{StaticResource CustomerTemplate}"/> public partial class MainWindow : Window{
public MainWindow(){
InitializeComponent();
TestDataSet ds = (TestDataSet)this.Resources["DataSet"];ds.Customer.AddCustomerRow(1,
"Customer1");ds.Customer.AddCustomerRow(2,
"Customer2");ds.Order.AddOrderRow(1,
new DateTime(2007, 10, 1), ds.Customer[0]);ds.Order.AddOrderRow(2,
new DateTime(2007, 10, 2), ds.Customer[0]);ds.Order.AddOrderRow(3,
new DateTime(2007, 10, 3), ds.Customer[1]);ds.Order.AddOrderRow(4,
new DateTime(2007, 10, 4), ds.Customer[1]);ds.Order.AddOrderRow(5,
new DateTime(2007, 10, 5), ds.Customer[1]);ds.OrderDetail.AddOrderDetailRow(1, ds.Order[0],
"ProductA");ds.OrderDetail.AddOrderDetailRow(2, ds.Order[0],
"ProductB");ds.OrderDetail.AddOrderDetailRow(3, ds.Order[1],
"ProductC");ds.OrderDetail.AddOrderDetailRow(4, ds.Order[1],
"ProductD");ds.OrderDetail.AddOrderDetailRow(5, ds.Order[2],
"ProductE");ds.OrderDetail.AddOrderDetailRow(6, ds.Order[2],
"ProductF");ds.OrderDetail.AddOrderDetailRow(7, ds.Order[3],
"ProductG");ds.OrderDetail.AddOrderDetailRow(8, ds.Order[3],
"ProductH");ds.OrderDetail.AddOrderDetailRow(9, ds.Order[4],
"ProductI");}
}
Best Regards
Wei Zhou
Friday, September 14, 2007 8:49 AM -
Hi Wei ,
Thank you for the reply. Th post was really helpful especially the code snippet.So the concept is simple: Using Heirarachical Data Template for all the non leaf nodes and Data Template for the leaf Node and using DataRelation . Pretty useful.
Thanks again buddy!!!
Best Regards
AbhinavSaturday, September 15, 2007 6:07 AM -
Hi Wei,
I have a similar situation with multiple relations, but I'm trying to bind to combo boxes instead of tree view.
I have 3 tables:
Table 1
tableOneID (PK)
displayString
Table 2
tableTwoID (PK)
displayString
tableOneID (FK)
Table 3
tableThreeID (PK)
displayString
tableTwoID (FK)
I want to be able to display the information in 3 combo boxes, filtered by the selection the 'upper' combo boxes. I have a dataset containing 3 datatables and have created relationships between the tables. It all works great for the first two combo boxes (cboTable_2's data is filtered correctly by selection in cboTable_1) but not for the next combo box - I want cboTable_3's data to be populated based on the selection in cboTable_2.Code SnippetOleDbDataAdapter da = new OleDbDataAdapter("SELECT * FROM Table_1", conn);
da.Fill(ds, "Table_1");
da = new OleDbDataAdapter("SELECT * FROM Table_2", conn);
da.Fill(ds, "Table_2");
da = new OleDbDataAdapter("SELECT * FROM Table_3", conn);
da.Fill(ds, "Table_3");
DataColumn masterOne = ds.Tables["Table_1"].Columns["tableOneID"];
DataColumn childOne = ds.Tables["Table_2"].Columns["tableOneID"];
DataRelation relation = new DataRelation("RelationMasterChild", masterOne, childOne);
ds.Relations.Add(relation);
cboTable_1.DataSource = ds;
cboTable_1.DisplayMember = "Table_1.displayString";
cboTable_1.ValueMember = "Table_1.tableOneID";
cboTable_2.Datasource = ds;
cboTable_2.DisplayMember = "Table_1.RelationMasterChild.displayString";
cboTable_2.ValueMember = "Table_1.RelationMasterChild.tableTwoID";
// Now I would assume that I can connect tables 2 and 3 in the same way
DataColumn masterTwo = ds.Tables["Table_2"].Columns["tableTwoID"];
DataColumn childTwo = ds.Tables["Table_3"].Columns["tableTwoID"];
relation = new DataRelation("RelationChildChild", masterTwo, childTwo);
ds.Relations.Add(relation);
cboTable_3.Datasource = ds;
cboTable_3.DisplayMember = "Table_2.RelationChildChild.displayString";
cboTable_3.ValueMember = "Table_2.RelationChildChild.tableThreeID";
cboTable_1 filters data in cboTable_2 which in turn filters data in cboTable_3
but when cboTable_1 and/or cboTable_2 selection is changed, cboTable_3 is not updated
Thanks for any input.Sunday, March 2, 2008 4:33 PM -
For anyone else searching, the solution to my problem can be found at
http://forums.microsoft.com/forums/ShowPost.aspx?PostID=2951342&SiteID=1
Cheers,
AnnaWednesday, March 5, 2008 9:42 PM -
Wei,
I tried to find the solution to display a parent table information from a strongly typed dataset. Here is a XAML code snip I modified from yours to illustrate what I try to do. Some people in the forum suggested using DataRowView's Row property to bind the parent table. But I seems can not get it to work. Thanks.
George
<Window.Resources>
<HierarchicalDataTemplate x:Key="OrderTemplate"
<local:TestDataSet x:Key="DataSet"/>
<DataTemplate x:Key="OrderDetailTemplate">
<TextBlock Text="{Binding Product}"/>
</DataTemplate>
ItemsSource="{Binding Order_OrderDetail}"
ItemTemplate="{StaticResource OrderDetailTemplate}"> <TextBlock Text="{Binding OrderDate}"/>
<!-- Question: how to bind the parent table -->
<ContentControl Content="Binding ....." ContentTemplate="{StaticResource CustomerTemplate}" />
</HierarchicalDataTemplate> <DataTemplate x:Key="CustomerTemplate" >
<TextBlock Text="{Binding CustomerName}"/>
</DataTemplate>
</Window.Resources> <TreeView ItemsSource="{Binding Source={StaticResource DataSet}, Path=Order}"
ItemTemplate="{StaticResource OrderTemplate}"/>
I did solve my own problem:
http://forums.msdn.microsoft.com/en-US/wpf/thread/ff17915c-76c5-442f-837b-470f1919a752- Edited by George50 Friday, June 27, 2008 7:53 PM problem solved
Friday, June 27, 2008 2:30 PM