0

I have my own treeview implementation based on this post, but I have problems defining a different style based on what object type is in the treeviewitem. I know the simple way is to define a templateselector, but I can't figure out how this would work when you have two HierarchicalDataTemplates.

 <HierarchicalDataTemplate DataType="{x:Type domainLayer:Folder}" ItemsSource="{Binding Converter={StaticResource BaseTypeConverter}}" />
 <HierarchicalDataTemplate DataType="{x:Type domainLayer:Document}" ItemsSource="{Binding Converter={StaticResource BaseTypeConverter}}" />

I use these templates to lazy load my tree, which works fine. There's also a Style defined for all TreeListViewItems. Maybe there's a solution too, but I can't figure out how to define if my TreeListViewItem is either a Folder or a Document.

Any help is much appreciated. If you need more code, just let me know!

Update 10:40am:

In a Style the row is defined for every TreeListViewItem:

<Style x:Key="cxc" TargetType="{x:Type local:TreeListViewItem}">
    <Setter Property="FontFamily" Value="TradeGothic LT" />
    <Setter Property="FontSize" Value="14px" />
    <Setter Property="Foreground" Value="{StaticResource TextBrush}" />
    <Setter Property="Background" Value="Transparent" />
    <EventSetter Event="MouseDoubleClick" Handler="OnItemMouseDoubleClick" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:TreeListViewItem}">
                <StackPanel>
                    <Border Name="Bd"
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            Padding="{TemplateBinding Padding}">
                        <GridViewRowPresenter x:Name="PART_Header"
                                                Content="{TemplateBinding Header}"
                                                Columns="{Binding Path=Columns,RelativeSource={RelativeSource AncestorType={x:Type local:TreeListView}}}"
                                                />
                    </Border>
                    <ItemsPresenter x:Name="ItemsHost" />
                </StackPanel>
                <ControlTemplate.Triggers>
<!-- ... -->

When I copy the template (everything in the StackPanel tag) to the HierarchicalDataTemplate I get an error: Cannot find the static member 'BackgroundProperty' on the type 'ContentPresenter'.

Michiel M.
  • 47
  • 1
  • 5
  • It looks like I've found a solution, i.e. get rid of the style and define the template inside the HierarchicalDataTemplate. Like so: http://stackoverflow.com/questions/4726318/how-can-i-specify-which-treeviewitem-style-template-for-a-treeviewitem-generated – Michiel M. Dec 09 '13 at 09:35

2 Answers2

1

You seem to be a little bit confused by the different Templates that WPF provides. First, we can define a Style for the TreeViewItem (the ItemContainerStyle), the data item 'container'. Then we can define a DataTemplate for the data item that appears within the container (the ItemTemplate), or HierarchicalDataTemplate in your case.

So don't try to put your data item Binding in the ItemContainerStyle and don't put your UI element Binding in the DataTemplate and you should be fine. Note that you can supply one DataTemplate/HierarchicalDataTemplate without setting their x:Key property for each data type in your collection and there is no need to use a DataTemplateSelector... let WPF do the implicit selecting of DataTemplates based on the data item's types. Here is a simple example:

In code:

public class BaseClass { }

public class ClassA : BaseClass { }

public class ClassB : BaseClass { }

...

public Observablecollection<BaseClass> Items { get ; set; }

In XAML:

<ListBox ItemsSource="{Binding Items}">
    <ListBox.Resources>
        <DataTemplate DataType="{x:Type DataTypes:ClassA}">
            <Ellipse Fill="Red" />
        </DataTemplate>
        <DataTemplate DataType="{x:Type DataTypes:ClassB}">
            <Rectangle Fill="Blue" />
        </DataTemplate>
    </ListBox.Resources>
</ListBox>

This ListBox would display red circles for the ClassA items and blue rectangles for the ClassB items. You can do a similar thing for your folders and files

Sheridan
  • 68,826
  • 24
  • 143
  • 183
  • Hi Sheridan, thanks for replying. Thanks for clearing this up, because I really was confused about it. However, I don't think this would work for what I want as I need quite a lot of overlap. But, I have fixed it. I will answer to myself. – Michiel M. Dec 09 '13 at 11:54
  • Althoug this works now, I have to come back to my statement as this isn't quite the proper way: the problem I've encountered now is that for an exact same TreeView, but with different objects, I'd have to create a complete new Style for these objects. Any thoughts? – Michiel M. Dec 09 '13 at 12:04
  • 1
    Remember, not `Style`s... data objects <==> `DataTemplate`s. You'll need to create a new `DataTemplate` for each data type that you use, but I fail to see this as a problem... just the norm. – Sheridan Dec 09 '13 at 12:17
  • Maybe I'm taking the too easy way out of this, but what I've tried is to copy the Template code in the Style to the HierarchicalDataTemplate. I got quite some errors on the styling (e.g. the Background property), but maybe that's what you're saying: just copy the template without the UI styling. I'll try that first. Thanks again! – Michiel M. Dec 09 '13 at 12:24
  • Dude, it seems like you still haven't quite got it yet... there's really no need for `DataTemplateSelector`s, or `DataTrigger`s to do any of this. All you need is a `DataTemplate`/`HierarchicalDataTemplate` for each data type and that's it. Still, if you're happy with what you have, that's fine. – Sheridan Dec 09 '13 at 12:44
  • Yeah, I've got that. I have no Selector and no DataTrigger. A very simple HDataTemplate. The only thing that doesn't work now is that I have the original togglebutton right before my own togglebutton. What I don't get exactly is how the Style declaration got rid of the original togglebutton. Working on that ... but looks promising. If you want I can send you what I've got. – Michiel M. Dec 09 '13 at 12:53
  • From [MSDN](http://msdn.microsoft.com/en-us/library/system.windows.controls.gridviewrowpresenter(v=vs.110).aspx): *The GridViewRowPresenter and GridViewHeaderRowPresenter classes support the GridView view mode for a ListView control*. Wouldn't a `Grid` with [`Grid.IsSharedSizeScope`](http://msdn.microsoft.com/en-us/library/system.windows.controls.grid.issharedsizescope(v=vs.110).aspx)`="True"` be easier and more efficient? – Sheridan Dec 09 '13 at 13:40
0

I've solved my problem as follows. In the aforementioned Style I've added a new MultiDataTrigger:

<MultiDataTrigger>
    <MultiDataTrigger.Conditions>
        <Condition
            Binding="{Binding RelativeSource={RelativeSource Self}, Path=Header, Converter={StaticResource IsFolder}}"
            Value="False" />
        <Condition
            Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}"
            Value="True" />
    </MultiDataTrigger.Conditions>
    <Setter TargetName="Bd"
            Property="Background"
            Value="{StaticResource HighlightBackgroundBrush}" />
</MultiDataTrigger>

This seems to work and looks like the proper solution. Thanks, Sheridan for the background on this.

Michiel M.
  • 47
  • 1
  • 5