locked
Binding a WPF Tree View to a DataSet having multiple relations RRS feed

  • 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
    Abhinav



    Saturday, 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 Snippet
    OleDbDataAdapter 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";

     

     

    The problem: On load this data is displayed correctly
    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,

    Anna
    Wednesday, 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>
            <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}"/>
                    <!-- 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