In WPF Style, How can I change defined color?

2019-08-15 19:13发布

I am making Image/Text button. When mouse over event arised, I want to change color of my drawing brush. How can I this? In below example, I want to iconBrush's color, Red -> Blue when mouse over.

<SolidColorBrush x:Key="iconBrush" Color="Red"/>
<DrawingBrush x:Key="buttonIcon" Stretch="Uniform">
    <DrawingBrush.Drawing>
        <DrawingGroup>
            <DrawingGroup.Children>
                <GeometryDrawing Brush="{StaticResource iconBrush}" Geometry="... />
            </DrawingGroup.Children>
        </DrawingGroup>
    </DrawingBrush.Drawing>
</DrawingBrush>

<Style x:Key="ImageTextButtonStyle" TargetType="{x:Type Button}">
    ...
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border>                        
                        <Grid>
                           <Grid.RowDefinitions>
                               <RowDefinition Height="20"/>
                               <RowDefinition Height="10"/>
                           </Grid.RowDefinitions>

                            <Grid Grid.Row="0" Background="{StaticResource buttonIcon}" />
                            <Grid Grid.Row="1">
                                <ContentPresenter ...
                                      />
                        </Grid>

                        </Grid>

                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter TargetName="{StaticResource iconBrush}" Value="Blue" />
                         ---> I Want to do this way..

2条回答
放我归山
2楼-- · 2019-08-15 19:57

This can be achieved quite simply using Attached Properties. You could also override the Button class but I prefer the first solution since you are only templating an existing control. Furthermore, you could reuse the attached property with controls other than Button.

The attached property:

public class OnMouseOver : DependencyObject
{
    public static readonly DependencyProperty BackgroundProperty =
    DependencyProperty.RegisterAttached(
      "Background",
      typeof(Brush),
      typeof(OnMouseOver)
    );
    public static void SetBackground(UIElement element, Brush value)
    {
        element.SetValue(BackgroundProperty, value);
    }
    public static Brush GetBackground(UIElement element)
    {
        return (Brush)element.GetValue(BackgroundProperty);
    }
}

The XAML part:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <Style x:Key="buttonBaseStyle" TargetType="Button">
            <Style.Setters>
                <Setter Property="Background" Value="Green" />
                <Setter Property="local:OnMouseOver.Background" Value="Lime" />
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="Button">
                            <Border Name="border" Background="{TemplateBinding Background}" CornerRadius="8" />
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsMouseOver" Value="True">
                                    <Setter TargetName="border" Property="Background" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(local:OnMouseOver.Background)}" />
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style.Setters>
        </Style>
        <Style x:Key="buttonRedStyle" TargetType="Button" BasedOn="{StaticResource buttonBaseStyle}">
            <Style.Setters>
                <Setter Property="Background" Value="Red" />
                <Setter Property="local:OnMouseOver.Background" Value="Pink" />
            </Style.Setters>
        </Style>
        <Style x:Key="buttonBlueStyle" TargetType="Button" BasedOn="{StaticResource buttonBaseStyle}">
            <Style.Setters>
                <Setter Property="Background" Value="Blue" />
                <Setter Property="local:OnMouseOver.Background" Value="Aqua" />
            </Style.Setters>
        </Style>
    </Window.Resources>
    <UniformGrid Columns="3">
        <Button Style="{StaticResource buttonBaseStyle}" />
        <Button Style="{StaticResource buttonRedStyle}" />
        <Button Style="{StaticResource buttonBlueStyle}" />
    </UniformGrid>
</Window>
查看更多
放荡不羁爱自由
3楼-- · 2019-08-15 20:06

it is not possible directly the way you are trying to achieve as nested properties or setting the resources values are not supported in setters

here is a workaround

  • i moved the drawing brush in background property of grid
  • binded brush of geometry drawing brush to background of templated parent which is button
  • and then switched the background of the template in the trigger

here is the code

<SolidColorBrush x:Key="iconBrush" Color="Red" />
<SolidColorBrush x:Key="blueBrush" Color="Blue" />
<Style x:Key="ImageTextButtonStyle" TargetType="{x:Type Button}">
    <Setter Property="Background" Value="{StaticResource iconBrush}" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border>
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="20" />
                            <RowDefinition Height="10" />
                        </Grid.RowDefinitions>
                        <Grid Grid.Row="0">
                            <Grid.Background>
                                <DrawingBrush Stretch="Uniform">
                                    <DrawingBrush.Drawing>
                                        <DrawingGroup>
                                            <DrawingGroup.Children>
                                                <GeometryDrawing Brush="{Binding Background, RelativeSource={RelativeSource TemplatedParent}}" Geometry="..." />
                                            </DrawingGroup.Children>
                                        </DrawingGroup>
                                    </DrawingBrush.Drawing>
                                </DrawingBrush>
                            </Grid.Background>
                        </Grid>
                        <Grid Grid.Row="1">
                            <ContentPresenter />
                        </Grid>
                    </Grid>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Background" Value="{StaticResource blueBrush}" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Another approach

  • I defined 2 icons
  • set one icon to the background of the grid
  • switch to another icon based on the trigger

code

<DrawingBrush x.Key="redIcon" Stretch="Uniform">
    <DrawingBrush.Drawing>
        <DrawingGroup>
            <DrawingGroup.Children>
                <GeometryDrawing Brush="Red" Geometry="..." />
            </DrawingGroup.Children>
        </DrawingGroup>
    </DrawingBrush.Drawing>
</DrawingBrush>

<DrawingBrush x.Key="blueIcon" Stretch="Uniform">
    <DrawingBrush.Drawing>
        <DrawingGroup>
            <DrawingGroup.Children>
                <GeometryDrawing Brush="Blue" Geometry="..." />
            </DrawingGroup.Children>
        </DrawingGroup>
    </DrawingBrush.Drawing>
</DrawingBrush>

<Style x:Key="ImageTextButtonStyle" TargetType="{x:Type Button}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border>
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="20" />
                            <RowDefinition Height="10" />
                        </Grid.RowDefinitions>
                        <Grid Grid.Row="0" x:Name="icon" Background="{StaticResource redIcon}" />
                        <Grid Grid.Row="1">
                            <ContentPresenter />
                        </Grid>
                    </Grid>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Background" Value="{StaticResource blueIcon}" TargetName="icon" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Attached Property for Icon

class to declare the property and hold the value

class Extras: DependencyObject
{
    public static Brush GetIcon(DependencyObject obj)
    {
        return (Brush)obj.GetValue(IconProperty);
    }

    public static void SetIcon(DependencyObject obj, Brush value)
    {
        obj.SetValue(IconProperty, value);
    }

    // Using a DependencyProperty as the backing store for Icon.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty IconProperty =
        DependencyProperty.RegisterAttached("Icon", typeof(Brush), typeof(Extras), new PropertyMetadata(null));
}

XAML resources

<DrawingBrush x:Key="buttonIcon"
                Stretch="Uniform">
    <DrawingBrush.Drawing>
        <DrawingGroup>
            <DrawingGroup.Children>
                <GeometryDrawing Brush="Red"
                                    Geometry="..." />
            </DrawingGroup.Children>
        </DrawingGroup>
    </DrawingBrush.Drawing>
</DrawingBrush>
<Style x:Key="ImageTextButtonStyle"
        TargetType="{x:Type Button}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border>
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="20" />
                            <RowDefinition Height="10" />
                        </Grid.RowDefinitions>
                        <Grid Grid.Row="0"
                                Background="{TemplateBinding l:Extras.Icon}" />
                        <Grid Grid.Row="1">
                            <ContentPresenter />
                        </Grid>
                    </Grid>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

usage

<Button Style="{StaticResource ImageTextButtonStyle}"
        Content="Icon Button"
        l:Extras.Icon="{StaticResource buttonIcon}"/>
查看更多
登录 后发表回答