Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change a style dynamically in WPF

Tags:

Is there a way to change(and apply) a style dynamically in WPF?

Say I have the style declared in XAML:

    <Style TargetType="local:MyLine" 
           x:Key="MyLineStyleKey" x:Name="MyLineStyleName">
        <Setter Property="Fill" Value="Pink"/>
        <Style.Triggers>
            <Trigger Property="IsSelected" Value="true">
                <Setter Property="Fill" Value="Blue" />                    
            </Trigger>
        </Style.Triggers>
    </Style>
  1. In a moment, I need to change the Pink color, to, say Green, and all lines with style MyLineStyleKey became Green. A line is Pink when released, and Blue when selected... Now, I needed to change the unselected property(Pink to Green)..., so this is not just setting it to an other color, the trigger (selection>Blue) will not work anymore...Is that possible? How?

  2. Is that possible to bind to the Pink color in the Style, say, to a Button background, that will reflect the currently used style color?

EDIT:
For 1 I tried:

Style s = (Style)this.Resources["MyLineStyleKey"];

(s.Setters[0] as Setter).Value = background;
(s.Setters[1] as Setter).Value = background;

but an exception occured:

After a 'SetterBase' is in use (sealed), it cannot be modified.

like image 461
serhio Avatar asked Sep 29 '10 12:09

serhio


People also ask

What is TAG property in WPF?

In WPF, the FrameworkElement class includes a Tag property that allows storing some arbitrary data with an element. You'd normally use the Tag property to store some custom data on an element that inherits from FrameworkElement.


2 Answers

Create a brush as a resource

<SolidColorBrush x:Key="MyFillBrush" Color="Pink" />

and refer to that in your style

<Style x:Key="MyShapeStyle" TargetType="Shape">
    <Setter Property="Fill" Value="{DynamicResource MyFillBrush}" />
</Style>
...
<!-- Then further down you may use it like this -->
<StackPanel Width="100">
    <Rectangle Style="{StaticResource MyShapeStyle}" Height="50" Margin="8" />
    <Rectangle Style="{StaticResource MyShapeStyle}" Height="50" Margin="8" />
    <Ellipse Style="{StaticResource MyShapeStyle}" Height="50" Margin="8" />
    <Button Content="Click to change color" Click="Button_Click" Margin="8" />
</StackPanel>

Now to change the color of all shapes that use the "MyShapeStyle" style, you can do the following from your code-behind:

private void Button_Click(object sender, RoutedEventArgs e)
{
    Random r = new Random();
    this.Resources["MyFillBrush"] = new SolidColorBrush(Color.FromArgb(
          0xFF, 
          (byte)r.Next(255), 
          (byte)r.Next(255), 
          (byte)r.Next(255)));
}

The thing that makes this work is the fact that you use a DynamicResource for the brush reference in your style - this tells WPF to monitor that resource for changes. If you use a StaticResource instead, you won't get this behavior.

like image 58
Isak Savo Avatar answered Sep 28 '22 02:09

Isak Savo


A style can only be modified before its first use. From MSDN:

A style is sealed when another style is based on it or when it is applied for the first time.

Instead, you could create a new style based on your existing style, and override the properties you want:

Style newStyle = new Style();
newStyle.BasedOn = originalStyle;
newStyle.TargetType = typeof(MyLine);
Brush blue = new SolidColorBrush(Colors.Blue);
newStyle.Setters.Add(new Setter(Shape.FillProperty, blue));
newStyle.Setters.Add(new Setter(Shape.StrokeProperty, blue));
like image 24
Thomas Levesque Avatar answered Sep 28 '22 00:09

Thomas Levesque