0

I have a situation where I want to selectively disable some effects based on the render capability of the host machine. I'm using RenderCapability.Tier to determine the hardware capabilities and have exposed this to the XAML using a static class and dependency property. However, in this situation I can't figure out how to go about disabling the effect from the XAML code.

The effect in question is a BlurEffect attached to a Grid:

    <Grid x:Name="contentGrid">
        <Grid.Effect>
            <BlurEffect Radius="0" />
        </Grid.Effect>
        ...
    </Grid>

I'm aware I can use a trigger to remove the effect based on the render tier:

<Trigger Property="local:RenderCapabilityWrapper.Tier" Value="0">
  <Setter Property="Effect" Value="{x:Null}"/>
</Trigger> 

However, the blur radius is animated from a data trigger in the template of another control:

            <ControlTemplate TargetType="controls:Menu">
                <ControlTemplate.Resources>
                    <Storyboard x:Key="FadeInContent">
                        <DoubleAnimation Storyboard.TargetProperty="ScreenContent.Opacity" From="0.1" To="1" Duration="0:0:.1" />
                        <DoubleAnimation Storyboard.TargetProperty="ScreenContent.Effect.Radius" From="3" To="0" Duration="0:0:.2" />
                    </Storyboard>
                    <Storyboard x:Key="FadeOutContent">
                        <DoubleAnimation Storyboard.TargetProperty="ScreenContent.Opacity" From="1" To="0.1" Duration="0:0:.2" />
                        <DoubleAnimation Storyboard.TargetProperty="ScreenContent.Effect.Radius" From="0" To="3" Duration="0:0:.2" />
                    </Storyboard>
                </ControlTemplate.Resources>
                <ControlTemplate.Triggers>
                    <DataTrigger Binding="{Binding Path=MenuModel.IsVisible, RelativeSource={RelativeSource Self}}" Value="True">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard  Storyboard="{StaticResource FadeOutContent}" />
                        </DataTrigger.EnterActions>
                        <DataTrigger.ExitActions>
                            <BeginStoryboard  Storyboard="{StaticResource FadeInContent}" />
                </ControlTemplate.Triggers>
                ...

I also need to remove the reference from the storyboard. I've considered having a second storyboard resource without the blur animation (so for example, FadeInContentLowQuality, FadInContentHighQuality) however I'm not sure how to switch between the two animations in the MenuModel.IsVisible data trigger?

Edit 1

As mm8 (thanks!) pointed out in the comments I can use a MultiDataTrigger to achieve the desired effect for DataTriggers:

                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding Path=MenuModel.IsVisible, RelativeSource={RelativeSource Self}}" Value="True" />
                            <Condition Binding="{Binding Path=Tier, Source={x:Static local:RenderCapabilityWrapper.Instance}}" Value="0" />
                        </MultiDataTrigger.Conditions>
                        <MultiDataTrigger.EnterActions>
                            <BeginStoryboard Storyboard="{StaticResource FadeInMenu}" />
                            <BeginStoryboard  Storyboard="{StaticResource FadeOutContentLow}" />
                        </MultiDataTrigger.EnterActions>
                        <MultiDataTrigger.ExitActions>
                            <BeginStoryboard Storyboard="{StaticResource FadeOutMenu}" />
                            <BeginStoryboard  Storyboard="{StaticResource FadeInContentLow}" />
                        </MultiDataTrigger.ExitActions>
                    </MultiDataTrigger>

Follow up question, is there an equivalent method I can use for switching animations in EventTriggers?

        <controls:PromptServiceListener>
            <controls:PromptServiceListener.Resources>
                <Storyboard x:Key="FadeOutLow">
                    <DoubleAnimation Storyboard.Target="{x:Reference rootLayout}" Storyboard.TargetProperty="Opacity" From="1" To="0.5" Duration="0:0:.2" />
                </Storyboard>
                <Storyboard x:Key="FadeOutHigh">
                    <DoubleAnimation Storyboard.Target="{x:Reference rootLayout}" Storyboard.TargetProperty="Opacity" From="1" To="0.5" Duration="0:0:.2" />
                    <DoubleAnimation Storyboard.Target="{x:Reference rootLayout}" Storyboard.TargetProperty="Effect.Radius" From="0" To="3" Duration="0:0:.2" />
                </Storyboard>
            </controls:PromptServiceListener.Resources>
            <controls:PromptServiceListener.Triggers>
                <EventTrigger RoutedEvent="controls:PromptServiceListener.PromptShown">
                    <BeginStoryboard>
                        <BeginStoryboard Storyboard="{StaticResource FadeOutHigh}" />
                    </BeginStoryboard>
                </EventTrigger>
            </controls:PromptServiceListener.Triggers>
        </controls:PromptServiceListener>

Edit 2

For a method of switching animations in event triggers see: WPF MultiDataTrigger on Tag property only firing once

MrQuery
  • 35
  • 6
  • 1
    Can't you use a [MultiDataTrigger](https://learn.microsoft.com/en-us/dotnet/api/system.windows.multidatatrigger?view=netframework-4.7.2) with two conditions; one that binds to `MenuModel.IsVisible` and another one that binds to `RenderCapabilityWrapper.Tier` and then set the actions and use the `Storyboards` as appropriate? – mm8 Feb 19 '19 at 13:15
  • Good point! I must admit, I wasn't aware of the MultiDataTrigger but it does exacty what I want. Follow up question though, is there an equivalent for EvenTriggers? – MrQuery Feb 19 '19 at 16:03
  • No, an `EventTrigger` is triggered in response to an event being raised. – mm8 Feb 19 '19 at 16:08

1 Answers1

1

You could use a MultiDataTrigger with two conditions; one that binds to MenuModel.IsVisible and another one that binds to RenderCapabilityWrapper.Tier and then set the actions and use the Storyboards as appropriate:

<MultiDataTrigger>
    <MultiDataTrigger.Conditions>
        <Condition Binding="{Binding Path=MenuModel.IsVisible, RelativeSource={RelativeSource Self}}" Value="True" />
        <Condition Binding="{Binding Path=Tier, Source={x:Static local:RenderCapabilityWrapper.Instance}}" Value="0" />
    </MultiDataTrigger.Conditions>
    <MultiDataTrigger.EnterActions>
        <BeginStoryboard Storyboard="{StaticResource FadeInMenu}" />
        <BeginStoryboard Storyboard="{StaticResource FadeOutContentLow}" />
    </MultiDataTrigger.EnterActions>
    <MultiDataTrigger.ExitActions>
        <BeginStoryboard Storyboard="{StaticResource FadeOutMenu}" />
        <BeginStoryboard  Storyboard="{StaticResource FadeInContentLow}" />
    </MultiDataTrigger.ExitActions>
</MultiDataTrigger>
mm8
  • 163,881
  • 10
  • 57
  • 88