XAML to change background opacity without changing color

c#, wpf, xaml

Solution

It took me a little while to think of the best way to do this... it turns out that it was trickier than I had first thought. All the same, it is possible, but it does involve quite a lot of code. In order to be able to target the actual `Opacity` property of the `Background Brush` object, you'll need to use a `StoryBoard`... that's why this code example is so verbose.

Because we need to use a `Storyboard` object in the `DataTrigger`, that means that we must use the `DataTrigger.EnterActions` as a `Storyboard` cannot be used in the normal `DataTrigger.Setters` collection. This follows that we must also use the `DataTrigger.ExitActions` to provide another `Storyboard` that sets the `Opacity` property back to its original value. Try this:

<Grid Name="YourGrid">
    <Grid.Background>
        <SolidColorBrush Color="Green" Opacity="0.2" />
    </Grid.Background>
    <Grid.Style>
        <Style TargetType="{x:Type Grid}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsMouseOver, ElementName=YourGrid}" 
                    Value="True">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimationUsingKeyFrames 
Storyboard.TargetProperty="Background.(SolidColorBrush.Opacity)">
                                    <LinearDoubleKeyFrame Value="0.7" KeyTime="0:0:0"/>
                                </DoubleAnimationUsingKeyFrames>
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                    <DataTrigger.ExitActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimationUsingKeyFrames 
Storyboard.TargetProperty="Background.(SolidColorBrush.Opacity)">
                                    <LinearDoubleKeyFrame Value="0.2" KeyTime="0:0:0"/>
                                </DoubleAnimationUsingKeyFrames>
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.ExitActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Grid.Style>
</Grid>

Despite the amount of code required to implement this method, it does do exactly what you were after. However, there is a simpler way to get the same overall effect, but with slightly less code. You could simply add a `Rectangle` into the back of each `Grid` cell, or division and set the colours and opacity on that instead. Using this method, you could simply set the `Rectangle.Opacity` value directly, although you would be using extra controls... the choice is yours.

Problem

In my C# / WPF / .NET 4.5 app I would like to implement a `Trigger` that toggles the background opacity of a control without changing its color. Normally to set the background brush of a control, I would use the following `Setter`: ``` <Setter TargetName="TargetControl" Property="Background"> <Setter.Value> <SolidColorBrush Color="Red" Opacity="0.2"/> </Setter.Value> ``` Now I am in a situation where I have to change the opacity only and not the color. What would my setter look like in this case, where I don't care what color the background is but I want to preserve the color while changing the opacity? More details: The reason for this is that I am working on an `ItemsControl` where the background color changes depending on the item's `AlternationIndex`: ``` <ItemsControl ItemsSource="{Binding SomeCollection}" AlternationCount="6"> <ItemsControl.ItemTemplate> <DataTemplate> <Grid x:Name="GridWithin"> <!-- ... --> </Grid> <DataTemplate.Triggers> <!-- Aternating colors for each row --> <Trigger Property="ItemsControl.AlternationIndex" Value="0"> <Setter TargetName="GridWithin" Property="Background"> <Setter.Value> <SolidColorBrush Color="Red" Opacity="0.2"/> </Setter.Value> </Setter> </Trigger> <Trigger Property="ItemsControl.AlternationIndex" Value="1"> <Setter TargetName="AllGesturesDataTemplateGrid" Property="Background"> <Setter.Value> <SolidColorBrush Color="Green" Opacity="0.2"/> </Setter.Value> </Setter> </Trigger> <!-- ... --> <!-- Highlight when a hit is registered --> <DataTrigger> <DataTrigger.Conditions> <Condition Binding="{Binding IsHit}" Value="True" /> </MultiDataTrigger.Conditions> <!-- The culprit --> <Setter TargetName="GridWithin" Property="Background"> <Setter.Value> <SolidColorBrush Opacity="0.7"/> </Setter.Value> </Setter> <!-- /culprit --> </DataTrigger> </DataTemplate.Triggers> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> ```

Original source