Styling Brushes

It appears that there is no way to apply a style to a Brush (such as SolidColorBrush) -- the style property is seemingly non-existant. Is there any reason/workaround for this?

Thanks!

[196 byte] By [PiGuy] at [2007-12-24]
# 1

Styling is an element feature (Style is a property of FrameworkElement), so not available on brushes. But brushes to some extent do support some dynamic features, such as databinding and resource references. If you can give an example, there might be a workaround.

MikeHillberg-MSFT at 2007-8-31 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...
# 2

Sure, I would like to be able to say something like this:

<Style TargetType ="{x:Type Brush}">

<Setter Property="Opacity" Value="0.5" />

</Style>

In my case, I will be applying a brush to a Rectangle's Fill property. I am generating a brush color (through custom logic) in my code behind and setting a number of rectangles' fills that way. The end result may be the equivalent (code-behind) code of a SolidColorBrush such as:

<Rectangle>

<Rectangle.Fill>

<SolidColorBrush Color="Red" />

</Rectangle.Fill>

</Rectangle>

or a LinearGradientBrush such as:

<Rectangle>

<Rectangle.Fill>

<LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >

<LinearGradientBrush.GradientStops>

<GradientStop Color ="Red" Offset ="0" />

<GradientStop Color ="White" Offset ="1" />

</LinearGradientBrush.GradientStops>

</LinearGradientBrush>

</Rectangle.Fill>

</Rectangle>

I am trying to avoid hardcoding this opacity value in my code-behind, but rather keeping all styles in my xaml. If there were some way to get at the opacity value from the xaml other than using a style, that would work too, but I don't yet see how.

Thanks in advance for any suggestions!

PiGuy at 2007-8-31 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...
# 3

The best solution is to style the element, and animate the brush's opacity from there. Then the issue you run into is that you can't specify a property path in a setter, e.g. you can't do "<Setter Property="Fill.Color" .../>. The solution to that is to do an "instant animation"; it's more work, but gets the job done. For example (combining those two things):

<Rectangle Width="100" Height="100" Fill="Red">
<
Rectangle.Style>
<
Style>
<
Style.Triggers>
<
EventTrigger RoutedEvent="Rectangle.Loaded">
<
BeginStoryboard>
<
Storyboard TargetProperty="Fill.Opacity">
<
DoubleAnimation To="0.5" Duration="0:0:0"/>
</
Storyboard>
</
BeginStoryboard>
</
EventTrigger>
</
Style.Triggers>
</
Style>
</
Rectangle.Style>
</
Rectangle>

MikeHillberg-MSFT at 2007-8-31 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...
# 4

I actually tried that Fill.Color idea before I asked....as you say, it doesn't work.

I am actually in the midst of upgrading from June CTP to RC1, so I can't test this at the moment. However, will this work if I change the brush of the Rectangle after it has been loaded (i.e. will this still take effect if I set its fill to a new brush from the code behind after I have placed it on the screen)? I wouldn't think so -- I would only think it would work when the rectangle was loaded, not when the fill was changed.

Thanks!

PiGuy at 2007-8-31 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...
# 5

I used you method and it works in general, but not for my case. As a twist on this, I also have other animations on mouseover on this rectangle changing its opacity to 1. However, my method throws an error when I try to bind to a brush, rather than providing it explicitly.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib"
>
<Page.Resources>

<Style TargetType="{x:Type Button}">

<Style.Triggers>
<Trigger Property="IsMouseOver" Value="False">
<Trigger.EnterActions>
<BeginStoryboard >
<!--Fades the button out and stops the initial 0.0 opacity if it was running-->
<Storyboard >
<DoubleAnimation Storyboard.TargetProperty="Background.Opacity"
From="1.0" To="0.0" Duration="0:0:1" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<StopStoryboard BeginStoryboardName="sb" />
<BeginStoryboard >
<!--Creates the appearance of the rectangle fill color fading in and out-->
<Storyboard >
<DoubleAnimation Storyboard.TargetProperty="Background.Opacity"
To="1.0" Duration="0:0:1" AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>

<EventTrigger RoutedEvent="Button.Loaded">
<EventTrigger.Actions>
<BeginStoryboard x:Name="sb">
<!--Starts the button faded out-->
<Storyboard >
<DoubleAnimation Storyboard.TargetProperty="Background.Opacity"
To="0.0" Duration="0:0:0" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</Page.Resources>

<Border Name="border1" VerticalAlignment="Center" HorizontalAlignment="Center" BorderThickness="2">
<Button Canvas.Top="200" Canvas.Left="400" Width="100" Background="{Binding ElementName=border1, Path=BorderBrush}" Height="100">
Mouse Over Me!
</Button>
</Border>
</Page>

If you change the highlighted property to something like Background="Red", it works fine. Otherwise, you get the error "Cannot resolve all property references in the property path 'Background.Opacity'. Verify that applicable objects support the properties."

Is this a problem with the binding?

Thanks!

PiGuy at 2007-8-31 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...
# 6

You're running into a couple of known issues. One issue is that the Button picks up its implicit style (the one you defined for it in the Page.Resources) before the Border picks up its implicit style (from the theme in this case). That's because the implicit styles are picked up essentially on the end tag, and the </Button> is ahead of the </Border> (lots more detail on that here). You can work around that by making the Border's style explicit, like this:

<Border Style="{DynamicResource {x:Type Border}}" Name="border1" VerticalAlignment="Center" HorizontalAlignment="Center" BorderThickness="2">

<Button Canvas.Top="200" Canvas.Left="400" Width="100"

Background="{Binding ElementName=border1, Path=BorderBrush}" Height="100">

Mouse Over Me!

</Button>
</Border>

This causes the Border to explicitly pick up the style that it would have implicitly picked up anyway.

Then you run into an issue where the Background property is a frozen brush that can't be animated. The workaround for that is to create a value converter for your Binding to clone the brush. So the binding looks like:

"{Binding ElementName=border1, Path=BorderBrush, Converter={x:Static local:MyCloneConverter.Instance}}"

And MyCloneConverter is:

internal class MyCloneConverter : IValueConverter

{

public static MyCloneConverter Instance = new MyCloneConverter();

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

{

if (value is Freezable)

{

value = (value as Freezable).Clone();

}

return value;

}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

{

throw new NotSupportedException();

}

}

MikeHillberg-MSFT at 2007-8-31 > top of Msdn Tech,Visual Studio Orcas,Windows Presentation Foundation (WPF)...

Visual Studio Orcas

Site Classified