5

In my WPF control, I have the following two triggers:

<Trigger
  Property="Controls:TreeViewExItem.IsMouseOver"
  Value="True"
  SourceName="ElementGrid">

and

<DataTrigger
  Binding="{Binding
    RelativeSource={RelativeSource AncestorType={x:Type Controls:TreeViewEx}},
    Path=HoverHighlighting}"
  Value="False">

Both for themselves work fine. But I need a combination of these. I tried this:

<MultiDataTrigger>
  <MultiDataTrigger.Conditions>
    <Condition
      Binding="{Binding
        RelativeSource={RelativeSource AncestorType={x:Type Controls:TreeViewEx}},
        Path=HoverHighlighting}"
      Value="True"/>
    <Condition
      Binding="{Binding
        (Controls:TreeViewExItem.IsMouseOver),
        Source=ElementGrid}"
      Value="True"/>
  </MultiDataTrigger.Conditions>

But it does nothing. I get this message in the output window:

System.Windows.Data Error: 17 : Cannot get 'IsMouseOver' value (type 'Boolean') from '' (type 'String'). BindingExpression:Path=(0); DataItem='String' (HashCode=1047858601); target element is 'TreeViewExItem' (Name=''); target property is 'NoTarget' (type 'Object') InvalidCastException:'System.InvalidCastException: Das Objekt des Typs "System.String" kann nicht in Typ "System.Windows.DependencyObject" umgewandelt werden.

That doesn't tell me anything. How will it work?

Update: The complete project code is now available in my GitHub repository for review. My guesswork of a MultiDataTrigger is currently located at.

Anatoliy Nikolaev
  • 22,370
  • 15
  • 69
  • 68
ygoe
  • 18,655
  • 23
  • 113
  • 210

2 Answers2

3

I have tried many things now and found nothing that worked. Until somebody proves me wrong, I must assume that Triggers and DataTriggers cannot be combined.

My solution is a different one: Instead of trying to access local properties and parent element properties from the same trigger (which need different Trigger types), I have added another DependencyProperty to my child element class and bind its value to the parent element's property. Thus the child element won't need to find the parent element value - it always has a current copy of the value itself. Since copying that value is done in another place, it keeps the triggers nice and small. :-)

So this is what my added XAML code looks like. Here's a new setter in the child item's style:

<!-- Pass on the TreeViewEx' HoverHighlighting value to each item
  because we couldn't access it otherwise in the triggers -->
<Setter
  Property="HoverHighlighting"
  Value="{Binding (Controls:TreeViewEx.HoverHighlighting),
    RelativeSource={RelativeSource
      AncestorType={x:Type Controls:TreeViewEx}}}" />

And this is in the triggers section where all the other triggers have already been:

<!-- Set the border and background when the mouse is located over
  the item and HoverHighlighting is active -->
<MultiTrigger>
  <MultiTrigger.Conditions>
    <Condition
      Property="Controls:TreeViewExItem.HoverHighlighting" Value="True"/>
    <Condition
      Property="Controls:TreeViewExItem.IsMouseOver" Value="True"
      SourceName="ElementGrid"/>
  </MultiTrigger.Conditions>

Dependency properties and data binding is great, once it works. But until then, it can be horrible.

ygoe
  • 18,655
  • 23
  • 113
  • 210
1

I know this is an older item, but i wanted to add something to it that i found today anyway: Even if you cannot combine Triggers and Datatriggers, you can easily upgrade a Trigger to a DataTrigger that refers to Self, like so:

<MultiDataTrigger.Conditions>
    <Condition Binding="{Binding ElementName=TabsApp, Path=SelectedIndex}" value="0"/>
    <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled}" Value="False"/>
</MultiDataTrigger.Conditions>

This will enable you to combine conditions about the control containing the trigger with conditions about other controls, no dependency properties needed.