wpfxamlmvvmcaliburn.microcaliburn

Caliburn.Micro DataTrigger with RelativeSource TemplatedParent


I developed an application with WPF without using a special MVVM framework. Now this application is getting bigger and bigger; therefore, I want to switch to Caliburn.Micro, but this causes somes problems.

I have a view containing ListBoxes inside an ItemsControl. In the ListBoxItems is a button placed, which has to change the opacity once the user hovers over the parent ListBox and once again, when the user hovers over the Button itself (and the way around, when the mouse leaves these controls again). To achieve this, I came up with this xaml code:

<Style x:Key="DeleteButtonStyle" TargetType="Button">
    <Setter Property="Opacity" Value="0.0" />
        <Style.Triggers>
            <EventTrigger RoutedEvent="Control.MouseEnter">
                <RemoveStoryboard BeginStoryboardName="PartiallyFadeOutStoryboard" />
                <RemoveStoryboard BeginStoryboardName="FadeOutStoryboard" />
                <BeginStoryboard Storyboard="{StaticResource FadeInStoryboard}" x:Name="FadeInStoryboard"/>
            </EventTrigger>
            <EventTrigger RoutedEvent="Control.MouseLeave">
                <RemoveStoryboard BeginStoryboardName="PartiallyFadeInStoryboard" />
                <RemoveStoryboard BeginStoryboardName="FadeInStoryboard" />
                <BeginStoryboard Storyboard="{StaticResource PartiallyFadeOutStoryboard}" x:Name="PartiallyFadeOutStoryboard"/>
            </EventTrigger>
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsMouseOver, NotifyOnSourceUpdated=True}" Value="True">
                <DataTrigger.EnterActions>
                    <RemoveStoryboard BeginStoryboardName="PartiallyFadeOutStoryboard" />
                    <RemoveStoryboard BeginStoryboardName="FadeOutStoryboard" />
                    <BeginStoryboard Storyboard="{StaticResource PartiallyFadeInStoryboard}" x:Name="PartiallyFadeInStoryboard"/>
                </DataTrigger.EnterActions>
                <DataTrigger.ExitActions>
                    <RemoveStoryboard BeginStoryboardName="PartiallyFadeInStoryboard" />
                    <RemoveStoryboard BeginStoryboardName="FadeInStoryboard" />
                    <RemoveStoryboard BeginStoryboardName="PartiallyFadeOutStoryboard" />
                    <BeginStoryboard Storyboard="{StaticResource FadeOutStoryboard}" x:Name="FadeOutStoryboard"/>
                 </DataTrigger.ExitActions>
              </DataTrigger>
          </Style.Triggers>
      </Style>

Sadly, this is now, after I switched to Caliburn, not any more working, as the code of the last DataTrigger is not anymore executed. I think the reason for this behavior is that I previously used a DataTemplate inside the ItemsControl to define the view; but now I created an extra .xaml file/class just for the view of this items which are bound to the ItemsControl (which contains the ListBox) - therefore, the RelativeSource TemplatedParent might not be working anymore. Is this idea correct? How can I solve this issue in the most elegant way?


Solution

  • Try to use a {RelativeSource} with an AncestorType:

    <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Path=IsMouseOver}" Value="True">
        <DataTrigger.EnterActions>
            <RemoveStoryboard BeginStoryboardName="PartiallyFadeOutStoryboard" />
            <RemoveStoryboard BeginStoryboardName="FadeOutStoryboard" />
            <BeginStoryboard Storyboard="{StaticResource PartiallyFadeInStoryboard}" x:Name="PartiallyFadeInStoryboard"/>
        </DataTrigger.EnterActions>
        <DataTrigger.ExitActions>
            <RemoveStoryboard BeginStoryboardName="PartiallyFadeInStoryboard" />
            <RemoveStoryboard BeginStoryboardName="FadeInStoryboard" />
            <RemoveStoryboard BeginStoryboardName="PartiallyFadeOutStoryboard" />
            <BeginStoryboard Storyboard="{StaticResource FadeOutStoryboard}" x:Name="FadeOutStoryboard"/>
        </DataTrigger.ExitActions>
    </DataTrigger>
    

    Change the latter to the type of whatever parent element you try to bind to.