wpfxamltriggersmultidatatrigger

How can I combine a Trigger with a SourceName and a DataTrigger?


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.


Solution

  • 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.