首页 > 解决方案 > 具有动态画笔属性的 DrawingBrush.GeometryDrawing

问题描述

我正在尝试通过设置 a来动态更改BrushaGeometryDrawing内部的a 。DrawingBrushDynamicResource

<DrawingBrush x:Key="Vector.Close" Stretch="Uniform" AlignmentX="Center" AlignmentY="Center">
    <DrawingBrush.Drawing>
        <DrawingGroup>
            <GeometryDrawing Brush="{DynamicResource Element.Glyph.Strong}" Geometry="F1 M 38.199,40 L 0,1.801 L 1.801,0 L 40,38.199 L 38.199,40 Z"/>
            <GeometryDrawing Brush="{DynamicResource Element.Glyph.Strong}" Geometry="F1 M 1.801,40 L 0,38.199 L 38.199,0 L 40,1.801 L 1.801,40 Z"/>
        </DrawingGroup>
    </DrawingBrush.Drawing>
</DrawingBrush>

当我更改应用程序的配色方案时,我将ResourceDictionarybyRemove()Insert()in 的顺序转移MergedDictionary

public static void SelectTheme(string id = "Light")
{
    var theme = Application.Current.Resources.MergedDictionaries.FirstOrDefault(f => f.Source != null && f.Source.ToString().EndsWith($"Colors/{id}.xaml"));

    if (theme == null)
    {
        theme = Application.Current.Resources.MergedDictionaries.FirstOrDefault(f => f.Source != null && f.Source.ToString().EndsWith("Colors/Light.xaml"));
        UserSettings.All.MainTheme = AppTheme.Light;
    }

    Application.Current.Resources.MergedDictionaries.Remove(theme);
    Application.Current.Resources.MergedDictionaries.Add(theme);
}

例如,在里面Light.xaml,我有一个SolidColorBrush

<SolidColorBrush x:Key="Element.Glyph.Strong" Color="#FF231F20"/>

在 内部App.xaml,我导入了我的两个资源字典(顺序无关紧要,因为资源将被转移到最后一个位置):

<!--Themes-->
<ResourceDictionary Source="/Themes/Colors/Dark.xaml"/>
<ResourceDictionary Source="/Themes/Colors/Light.xaml"/>

<ResourceDictionary Source="/Resources/Vectors.xaml"/>

<ResourceDictionary Source="/Themes/Button.xaml"/>

该矢量用作自定义图标上的图标Button。按钮内部有一个带大小和对齐方式的边框,向量用作Background.

Button定义和用法(Iconis a Brush DependencyProperty):

public class ExtendedButton : Button
{
    public static readonly DependencyProperty IconProperty = DependencyProperty.Register(nameof(Icon), typeof(Brush), typeof(ExtendedButton));

    public Brush Icon
    {
        get => (Brush)GetValue(IconProperty);
        set => SetCurrentValue(IconProperty, value);
    }

    //Ctor and other stuff.
}

<n:ExtendedButton Style="{DynamicResource Style.Button.NoText}" 
                  Icon="{DynamicResource Vector.Close}" Width="30" Padding="6"/>

我将 设置IconStaticResource,但我在这里询问之前更改为DynamicResource,作为测试。但它仍然没有工作。

Style这是按钮的简化版:

<!--Button • No Border • No Text-->
<Style TargetType="{x:Type n:ExtendedButton}" BasedOn="{StaticResource {x:Type Button}}" x:Key="Style.Button.NoText">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type n:ExtendedButton}">
                <Border x:Name="MainBorder" MinHeight="{TemplateBinding MinHeight}" Background="{TemplateBinding Background}">
                    <Grid x:Name="InnerGrid">
                        <Border Background="{TemplateBinding Icon}" Margin="{TemplateBinding Padding}" Opacity="{DynamicResource Element.Opacity}"
                                Height="14" Width="14" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                    </Grid>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>

    <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="Background" Value="{DynamicResource Brush.Button.Background.Hover}"/>
        </Trigger>
        <Trigger Property="IsPressed" Value="True">
            <Setter Property="Background" Value="{DynamicResource Brush.Button.Background.Pressed}"/>
        </Trigger>
        <Trigger Property="IsEnabled" Value="False">
            <Setter Property="Opacity" Value="0.7"/>
        </Trigger>
    </Style.Triggers>
</Style>

该应用程序的其余部分可以正常工作,更改主题时,其他所有内容都会更改。内部Element.Glyph.StrongGeometryDrawing更新。

只有在关闭应用程序并再次打开时才会以正确的颜色显示矢量,因为它会以新主题加载。

我猜想该Brush属性DependencyProperty也会在资源更新时更新。

我想知道如何设置Brush动态颜色,而不必使用后面的代码?

标签: wpfresourcedictionarydynamicresource

解决方案


我不确定您到底是如何更改主题的,但是如果其他组件正在更改,那么我假设您这样做是正确的。

我认为关键是确保您使用Background="{DynamicResource Vector.Close}"的是Background="{StaticResource Vector.Close}".

Dictionary1.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WpfApp1">

    <SolidColorBrush x:Key="Element.Glyph.Strong" Color="Black" />

</ResourceDictionary>

Dictionary2.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WpfApp1">

    <SolidColorBrush x:Key="Element.Glyph.Strong" Color="Yellow" />

</ResourceDictionary>

Dictionary3.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WpfApp1">
    
    <DrawingBrush x:Key="Vector.Close" Stretch="Uniform" AlignmentX="Center" AlignmentY="Center">
        <DrawingBrush.Drawing>
            <DrawingGroup>
                <GeometryDrawing Brush="{DynamicResource Element.Glyph.Strong}" Geometry="F1 M 38.199,40 L 0,1.801 L 1.801,0 L 40,38.199 L 38.199,40 Z"/>
                <GeometryDrawing Brush="{DynamicResource Element.Glyph.Strong}" Geometry="F1 M 1.801,40 L 0,38.199 L 38.199,0 L 40,1.801 L 1.801,40 Z"/>
            </DrawingGroup>
        </DrawingBrush.Drawing>
    </DrawingBrush>
</ResourceDictionary>

MainWindow.xaml

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Grid>
        <Button Background="{DynamicResource Vector.Close}" Width="40" Height="40" VerticalAlignment="Center" Click="ChangeTheme_Click" HorizontalAlignment="Center"/>
    </Grid>
</Window>

MainWindow.xaml.cs

// stuff up here...

public string currentDict = "Dictionary1.xaml";

private void ChangeTheme_Click(object sender, RoutedEventArgs e)
{
    if (currentDict == "Dictionary1.xaml")
    {
        currentDict = "Dictionary2.xaml";
    } else
    {
        currentDict = "Dictionary1.xaml";
    }
    var app = (App)Application.Current;
    app.ChangeTheme(new Uri(currentDict, UriKind.RelativeOrAbsolute));
}

App.xaml

<Application x:Class="WpfApp1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WpfApp1"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Dictionary1.xaml" />
                <ResourceDictionary Source="Dictionary3.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

App.xaml.cs

public void ChangeTheme(Uri uri)
{
    var dict = new ResourceDictionary() { Source = uri };
    var dict2 = new ResourceDictionary() { Source = new Uri("Dictionary3.xaml", UriKind.RelativeOrAbsolute) };
    Resources.MergedDictionaries.Clear();
    Resources.MergedDictionaries.Add(dict);
    Resources.MergedDictionaries.Add(dict2);
}

显然这有点混乱和hacky,但它有效:

带黑色 x 的按钮

带有黄色 x 的按钮


编辑:

即使使用自定义样式,我也无法重现。切换后是这样的:

两个按钮,都是黄色的


推荐阅读