【问题标题】:DrawingBrush.GeometryDrawing with dynamic Brush property具有动态画笔属性的 DrawingBrush.GeometryDrawing
【发布时间】:2020-09-11 18:59:31
【问题描述】:

我正在尝试通过设置DynamicResource 来动态更改GeometryDrawing 内的GeometryDrawingBrush

<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 的顺序更改为Remove()Insert()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定义和用法(IconBrushDependencyProperty):

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"/>

我将Icon 设置为StaticResource,但我在此处询问之前更改为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>

应用程序的其余部分正常工作,当更改主题时,其他所有内容都会更改。 GeometryDrawing 中的 Element.Glyph.Strong 不会更新。

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

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

我想知道如何将Brush 设置为动态颜色,而无需使用后面的代码?

【问题讨论】:

    标签: wpf resourcedictionary dynamicresource


    【解决方案1】:

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

    我认为关键是确保您使用的是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,但它确实有效:


    编辑:

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

    【讨论】:

    • 您好,很抱歉缺少详细信息。我更新了问题。我正在使用带有Style 的自定义按钮。也许这就是问题所在。
    • 我试图简单地使用您的Button,如上所述,而不是我的。颜色仍然没有改变。
    • 顺便说一句:我喜欢在我的图标中使用ContentControls。我在其中放置了一个画布和一条路径(来自 svg)。然后将其设置为按钮的内容。我使用TemplateBinding 到按钮的Foreground 作为路径颜色。
    • 我知道现在发生了什么。您删除带有向量的字典并再次添加它。这会刷新里面的所有动态资源。就我而言,我只是在切换颜色字典的位置。
    猜你喜欢
    • 2015-11-10
    • 2011-01-15
    • 2016-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-22
    • 2017-01-22
    相关资源
    最近更新 更多