具有动态 Brush 属性的 DrawingBrush.GeometryDrawing [英] DrawingBrush.GeometryDrawing with dynamic Brush property

查看:35
本文介绍了具有动态 Brush 属性的 DrawingBrush.GeometryDrawing的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to dynamically change the Brush of a GeometryDrawing inside a DrawingBrush by setting a DynamicResource.

<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:

When I change the color scheme of my app, I shift the ordering of my ResourceDictionary by Remove() and Insert() in the 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:

For example, inside the Light.xaml, I have a SolidColorBrush:

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

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

Inside the App.xaml, I import both my resource dictionaries (the order does not matter, since the resources will be shifted to the last position):

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

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

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


矢量用作自定义 Button 上的图标.按钮内部有一个带大小和对齐的边框,矢量用作背景.


The vector is used as an icon on a custom Button. Inside the button there's a Border with a sizing and alignment, and the vector is used as the Background.

Button 定义和用法(Icon 是一个 Brush DependencyProperty):

Button definition and usage (Icon is 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"/>

我将 Icon 设置为 StaticResource,但我在这里询问之前更改为 DynamicResource,作为测试.但是还是不行.

I was setting the Icon as a StaticResource, but I changed to DynamicResource before asking in here, as a test. But it still didn't work.

这是按钮的简化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.Gly​​ph.Strong 不会更新.

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

Only when closing the app and opening again will display the vector with the correct color, since it loads with the new theme.

我猜测 Brush 属性,作为 DependencyProperty 会在资源更新时更新.

I guessed that the Brush property, as a DependencyProperty would update when the resource updated too.

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

I wonder how could I set the Brush with a dynamic color, without having to work with code behind?

推荐答案

我不确定您是如何更改主题的,但如果其他组件正在更改,那么我假设您的操作是正确的.

I'm not sure exactly how you are changing themes, but if other components are changing then I am assuming you are doing that correctly.

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

I think the key is to make sure you are using Background="{DynamicResource Vector.Close}" instead of 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);
}

显然这有点凌乱和笨拙,但它有效:

Obviously this is a little messy and hacky, but it works:

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

I am not able to reproduce even when using the custom styling. Here it is after switching:

这篇关于具有动态 Brush 属性的 DrawingBrush.GeometryDrawing的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆