0
votes

I am trying to create a TreeView with the following hierarchy:

Device1
--File1
--File2
--Hook1
--Hook2
Device2
--File1
--File1
Device3
--Hook1

So basically The Root level node is a device with children being File and Hook. I have created the following tree with the hierarchical data template

<TreeView ItemsSource="{Binding Devices}">
        <HierarchicalDataTemplate DataType="{x:Type datamodel:Device}" ItemsSource="{Binding Files}">
               <TextBlock Margin="5,5,0,0" Text="{Binding DeviceName}"/>
                  <HierarchicalDataTemplate.ItemTemplate>
                       <DataTemplate  DataType="{x:Type datamodel:File}">
                            <TextBlock Margin="5,0,0,0" Text="{Binding FileName}"/>
                        </DataTemplate>
                 </HierarchicalDataTemplate.ItemTemplate>
       </HierarchicalDataTemplate>

     Class Devices
     {

          public string DeviceName
          {
             get;set;
          }

          public string List<File> Files
          {
              get;set;
          }

         public string List<Hook> Hooks
          {
              get;set;
          }
     }

  public class File
{
     public string FileName
     {
        get;set;
     }


     public string FileType
    {
        get;set;
    }

    public string Location
    {
        get; set;
    }

}


public class Hook
{
    public string HookName
    {
       get;set;
    }

    public string Type
   {
      get;set;
   }
}

I am able to add only one Datatemplate in the ItemTemplate of the HierarchicalDataTemplate. How do I specify two data types under a single HierarchicalDataTemplate??

2

2 Answers

0
votes

You will have to use the converter here which will return the CompositeCollection which will contain both files and hooks. You will use this converter with ItemsSource of HierarchicalDataTemplate DataType="{x:Type datamodel:Device}"

Then you just need to define two datatemplates for File and Hook data type.

Thanks

0
votes

I tried with the CompositeCollection but realized that the bound objects were converted to base types. So I used it in combination of DataTemplateSelector. The following solution worked for me.

<TreeView ItemsSource="{Binding Devices}">
     <TreeView.Resources>
       <HierarchicalDataTemplate DataType="{x:Type datamodel:Devices}" ItemTemplateSelector="{StaticResource LeafDataTemplateSelector}">
            <HierarchicalDataTemplate.ItemsSource>
                 <MultiBinding Converter="{StaticResource CompositeCollectionConverter}">
                      <Binding Path="Files" />
                      <Binding Path="Hooks"/>
                 </MultiBinding>
            </HierarchicalDataTemplate.ItemsSource>
                <StackPanel Height="25" Orientation="Horizontal">
                   <Image Height="20" Width="20" Source="Device.png"/>
                    <TextBlock Margin="5,5,0,0" Text="{Binding Device}"/>
                </StackPanel>
           </HierarchicalDataTemplate>

         <DataTemplate x:Key="FileKey" DataType="{x:Type datamodel:File}">
                <StackPanel Height="25" Orientation="Horizontal" ToolTip="Installation File">
                     <Image Height="20" Width="20" Source="File.png" />
                      <TextBlock Text="{Binding FileName}"/>
                </StackPanel>
         </DataTemplate>
         <DataTemplate x:Key="HookKey"  DataType="{x:Type datamodel:Hook}">
               <StackPanel Height="25" Orientation="Horizontal"  ToolTip="Installation Hook">
                   <Image Height="20" Width="20" Source="Hook.png" />
                   <TextBlock Margin="5,5,0,0" Text="{Binding HookName}"/>
               </StackPanel>
         </DataTemplate>
    </TreeView.Resources>

The have used the template selector to select the appropriate template based on the key.

 public class LeafDataTemplateSelector :  DataTemplateSelector
{
    public override DataTemplate
        SelectTemplate(object item, DependencyObject container)
    {
        FrameworkElement element = container as FrameworkElement;

        if (element != null && item != null)
        {

            if (item is InstallationManifesFile)
                return
                        element.FindResource("FileKey")
                        as DataTemplate;
            else if (item is InstallationManifestHook)
                return element.FindResource("HookKey")
                        as DataTemplate;
        }

        return null;
    }
}

public class CompositeCollectionConverter : IMultiValueConverter
{

    public object Convert(object[] values
        , Type targetType
        , object parameter
        , System.Globalization.CultureInfo culture)
    {
        var res = new CompositeCollection();
        foreach (var item in values)
            if (item is IEnumerable && item != null)
                res.Add(new CollectionContainer()
                {
                    Collection = item as IEnumerable
                });
        return res;
    }

    public object[] ConvertBack(object value
        , Type[] targetTypes
        , object parameter
        , System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}