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> ```