none
Nested Listviews in Treeview RRS feed

  • Question

  • I am trying to create a treeview with some nested listviews as its treeview items. This data is connected to a dataset which is created in code. I want only one item from the dataset in each listview, but I am not getting the proper results. I have been working based off this great example by Josh Smith
     
    Any help is greatly appreciated!

    XAML Code:
    <Window x:Class="WindowsApplication8.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WindowsApplication8"
        Title="WindowsApplication8" Height="585" Width="939"
        >
      <Window.Resources >
        <!-- Creates a DataSet with two related DataTables. -->
        <ObjectDataProvider x:Key="dataSetProvider" MethodName="CreateDataSet" ObjectType="{x:Type local:DataSetCreator}" />
       
        <!-- Displays a row in the 'Detail' table (i.e. the child table). -->
        <DataTemplate x:Key="DetailTemplate">
          <ListView DataContext="{StaticResource dataSetProvider}" ItemsSource="{Binding}">
            <ListView.View>
              <GridView >
                <GridViewColumn Header="Info" DisplayMemberBinding="{Binding Path=Detail/Info}" Width="400"/>
              </GridView>
            </ListView.View>
          </ListView>
        </DataTemplate>

        <!-- Displays a row in the 'Master' table (i.e. the parent table).
             Pulls it's child items from the 'Master2Detail' DataRelation
             in the DataSet.  Each child row is displayed via the 'DetailTemplate'. -->
        <HierarchicalDataTemplate
          x:Key="MasterTemplate"
          ItemsSource="{Binding Master2Detail}"
          ItemTemplate="{StaticResource DetailTemplate}">
          <ListView DataContext="{StaticResource dataSetProvider}" ItemsSource="{Binding}">
            <ListView.View>
              <GridView >
                <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Path=Master/Name}" Width="100"/>
              </GridView>
            </ListView.View>
          </ListView>
        </HierarchicalDataTemplate>
      </Window.Resources>

      <Grid>
        <TreeView
          DataContext="{StaticResource dataSetProvider}"
          ItemsSource="{Binding Master}"
          ItemTemplate="{StaticResource MasterTemplate}"
          />
      </Grid>
    </Window>

    C# Code:
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Data;

    namespace WindowsApplication8
    {
        public static class DataSetCreator
        {
            public static DataSet CreateDataSet()
            {
                DataSet ds = new DataSet();

                // Create the parent table.
                DataTable tbl = new DataTable("Master");
                tbl.Columns.Add("ID", typeof(int));
                tbl.Columns.Add("Name");

                for (int i = 0; i < 3; ++i)
                {
                    DataRow row = tbl.NewRow();
                    row["ID"] = i;
                    row["Name"] = "Master #" + i;
                    tbl.Rows.Add(row);
                }

                ds.Tables.Add(tbl);

                // Create the child table.
                tbl = new DataTable("Detail");
                tbl.Columns.Add("MasterID", typeof(int));
                tbl.Columns.Add("Info");

                for (int i = 0; i < 9; ++i)
                {
                    DataRow row = tbl.NewRow();
                    row["MasterID"] = i % 3;
                    row["Info"] = "Detail Info #" + (i / 3) + " for Master #" + (i % 3);
                    tbl.Rows.Add(row);
                }

                ds.Tables.Add(tbl);

                // Associate the ID and MasterID columns between the tables.
                ds.Relations.Add(
                 "Master2Detail",
                 ds.Tables["Master"].Columns["ID"],
                 ds.Tables["Detail"].Columns["MasterID"]);

                return ds;
            }
        }
    }
    Tuesday, February 13, 2007 12:14 AM

Answers

  • It looks like you found a bug, perhaps.  The ListView does not know how to bind to a single DataRowView.  Each root-level item in the TreeView should represent a DataRowView, so that's a problem.  I found a semi-acceptable workaround, but the item selection logic isn't correct.  Hopefully someone from MSFT can point us to a better solution.  Here's my hack... 

    class DataRowViewArrayConverter : IValueConverter
    {
     public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
     {
      return new DataRowView[] { value as DataRowView };
     }
    
     public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
     {
      throw new Exception( "The method or operation is not implemented." );
     }
    }
    

    <Window.Resources >

    <!-- Creates a DataSet with two related DataTables. -->

    <ObjectDataProvider x:Key="dataSetProvider" MethodName="CreateDataSet" ObjectType="{x:Type local:DataSetCreator}" />

    <local:DataRowViewArrayConverter x:Key="conv" />

    <!-- Displays a row in the 'Detail' table (i.e. the child table). -->

    <DataTemplate x:Key="DetailTemplate">

    <ListView ItemsSource="{Binding Converter={StaticResource conv}}">

    <ListView.View>

    <GridView >

    <GridViewColumn Header="Info" DisplayMemberBinding="{Binding Info}" Width="400"/>

    </GridView>

    </ListView.View>

    </ListView>

    </DataTemplate>

    <!-- Displays a row in the 'Master' table (i.e. the parent table).

    Pulls it's child items from the 'Master2Detail' DataRelation

    in the DataSet. Each child row is displayed via the 'DetailTemplate'. -->

    <HierarchicalDataTemplate

    x:Key="MasterTemplate"

    ItemsSource="{Binding Master2Detail}"

    ItemTemplate="{StaticResource DetailTemplate}">

    <ListView ItemsSource="{Binding Converter={StaticResource conv}}">

    <ListView.View>

    <GridView>

    <GridViewColumn Header="Name" Width="100" DisplayMemberBinding="{Binding Name}" />

    </GridView>

    </ListView.View>

    </ListView>

    </HierarchicalDataTemplate>

    </Window.Resources>

    <Grid>

    <TreeView

    DataContext="{StaticResource dataSetProvider}"

    ItemsSource="{Binding Master}"

    ItemTemplate="{StaticResource MasterTemplate}"

    />

    </Grid>

     

    Sorry for the lack of indentation. I still can't figure this editor out!

    Tuesday, February 13, 2007 4:29 AM

All replies

  • It looks like you found a bug, perhaps.  The ListView does not know how to bind to a single DataRowView.  Each root-level item in the TreeView should represent a DataRowView, so that's a problem.  I found a semi-acceptable workaround, but the item selection logic isn't correct.  Hopefully someone from MSFT can point us to a better solution.  Here's my hack... 

    class DataRowViewArrayConverter : IValueConverter
    {
     public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
     {
      return new DataRowView[] { value as DataRowView };
     }
    
     public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture )
     {
      throw new Exception( "The method or operation is not implemented." );
     }
    }
    

    <Window.Resources >

    <!-- Creates a DataSet with two related DataTables. -->

    <ObjectDataProvider x:Key="dataSetProvider" MethodName="CreateDataSet" ObjectType="{x:Type local:DataSetCreator}" />

    <local:DataRowViewArrayConverter x:Key="conv" />

    <!-- Displays a row in the 'Detail' table (i.e. the child table). -->

    <DataTemplate x:Key="DetailTemplate">

    <ListView ItemsSource="{Binding Converter={StaticResource conv}}">

    <ListView.View>

    <GridView >

    <GridViewColumn Header="Info" DisplayMemberBinding="{Binding Info}" Width="400"/>

    </GridView>

    </ListView.View>

    </ListView>

    </DataTemplate>

    <!-- Displays a row in the 'Master' table (i.e. the parent table).

    Pulls it's child items from the 'Master2Detail' DataRelation

    in the DataSet. Each child row is displayed via the 'DetailTemplate'. -->

    <HierarchicalDataTemplate

    x:Key="MasterTemplate"

    ItemsSource="{Binding Master2Detail}"

    ItemTemplate="{StaticResource DetailTemplate}">

    <ListView ItemsSource="{Binding Converter={StaticResource conv}}">

    <ListView.View>

    <GridView>

    <GridViewColumn Header="Name" Width="100" DisplayMemberBinding="{Binding Name}" />

    </GridView>

    </ListView.View>

    </ListView>

    </HierarchicalDataTemplate>

    </Window.Resources>

    <Grid>

    <TreeView

    DataContext="{StaticResource dataSetProvider}"

    ItemsSource="{Binding Master}"

    ItemTemplate="{StaticResource MasterTemplate}"

    />

    </Grid>

     

    Sorry for the lack of indentation. I still can't figure this editor out!

    Tuesday, February 13, 2007 4:29 AM
  • Hey thanks for the info and the hack Josh, really appreciate it! Anyone from Microsoft care to take a stab at this one? I'm always happy to push WPF to its limits!

    Thanks
    Matthew
    Tuesday, February 13, 2007 4:28 PM