1

Q: How do I bind to a custom property of the template parent from a child control's style DataTrigger

I've been scratching my head over this one for a couple of days.

I have a databound TreeView which uses a Style which has a Template. The TreeView is bound to a ObservableCollection and a HierarchicalDataTemplate + DataTemplate bind to properties inside a collection item.

FontGroup -> Font(s)

<Style x:Key="ExpandCollapseToggleStyle" TargetType="{x:Type ToggleButton}">
...
<Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ToggleButton}">
                <Image x:Name="ExpanderImage" Source="/Typesee;component/Resources/tree_expand.png" RenderOptions.BitmapScalingMode="NearestNeighbor" />
                <ControlTemplate.Triggers>
                    <DataTrigger Binding="??? IsItemSelected ???" Value="True">
                            <Setter TargetName="ExpanderImage" Property="Source" Value="/Typesee;component/Resources/tree_collapse_selected.png" />
                    </DataTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<ControlTemplate x:Key="FontTreeViewTemplate" TargetType="{x:Type TreeViewItem}">
...
    <ToggleButton x:Name="Expander" Style="{StaticResource ExpandCollapseToggleStyle}" ... />
...
    <ControlTemplate.Triggers>
            <DataTrigger Binding="{Binding IsItemSelected}" Value="True">
            <!-- WORKS FINE HERE -->
            </DataTrigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

First I tried to bind like:

Binding Path=IsItemSelected, RelativeSource={RelativeSource TemplatedParent}

Then I read that might not work so I tried (including AncestorLevel 1+3):

Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TreeViewItem}, AncestorLevel=2

Have also tried combos with UpdateSourceTrigger=PropertyChanged and Mode=TwoWay

If this is a flawed design please suggest a way of doing this: I basically want to change the image of the expand toggle button based on whether the property IsItemSelected is true on the TreeViewItem -- any ideas?

Thanks so much for any help!

H.B.
  • 166,899
  • 29
  • 327
  • 400
Dominic
  • 62,658
  • 20
  • 139
  • 163

1 Answers1

6

The viewmodel in all likelihood will be the DataContext, so the binding should be a RelativeSource binding with a respective path which needs to explicity target the DataContext as the new source is the RelativeSource:

 {Binding DataContext.IsItemSelected,
          RelativeSource={RelativeSource AncestorType=TreeViewItem}}

As noted in my comment it might be advisable to extract this logic from the ControlTemplate as this leaves its bounds. One method would be subclassing the ToggleButton and exposing a public property for the image which then can be changed via a Style.

H.B.
  • 166,899
  • 29
  • 327
  • 400
  • 1
    Thanks but I have no problem binding to IsChecked or even binding to the parents IsSelected property (the parent template is a TreeViewItem. Its just binding to the parent custom propert IsItemSelected which is part of my ViewModel for the TreeViewItem. – Dominic Aug 02 '11 at 01:26
  • 1
    ControlTemplates should be fully self-contained, i do not think that binding to anything outside is a good idea... – H.B. Aug 02 '11 at 01:29
  • Thanks H.B - I basically want to change the color of the expand image based on whether the property IsItemSelected is true -- any ideas? – Dominic Aug 02 '11 at 01:31
  • 1
    You could potentially subclass ToggleButton (something like `ImageToggleButton`) which exposes the Image's source as a public dependency property, then you can define a style for the button, which on trigger changes this property. – H.B. Aug 02 '11 at 01:36
  • Ha such a simple great suggestion thanks :) Maybe post it as an answer then I can mark this as answered – Dominic Aug 02 '11 at 01:37
  • I edited my answer to also provide a binding which should work. – H.B. Aug 02 '11 at 01:40
  • omg you lifesaver thank you it works!! I agree it would be better to subclass, maybe later :p – Dominic Aug 02 '11 at 01:43
  • Glad that helped :) Just always keep in mind what your binding source is, not specifying anything implicitly uses DataContext so that if you do specify a source and you want to bind to the DataContext it needs to be included in the `Path`. – H.B. Aug 02 '11 at 01:47