在不同的程序集中使用带有静态 ResourceDictionary 的 BasedOn 样式

Using BasedOn Style with static ResourceDictionary in different Assembly

背景

我的解决方案中有多个项目,在一个项目中,我制作了一个包含合并的 ResourceDictionary 的静态 class,我在所有其他项目中都使用了它:

namespace GUI.Shared.Resources
{
    public static class ResourceFactory
    {
        public static ResourceDictionary _resources = null;

        public static ResourceDictionary Resources
        {
            get
            {
                if (_resources == null)
                {
                    _resources = new ResourceDictionary();
                    _resources.MergedDictionaries.Add(new ResourceDictionary() { Source = new Uri("pack://application:,,,/GUI.Shared;component/Resources/VectorIcons.xaml") });
                    _resources.MergedDictionaries.Add(new ResourceDictionary() { Source = new Uri("pack://application:,,,/GUI.Shared;component/Resources/ButtonStyles.xaml") });
                }

                return _resources;
            }
        }       
    }
}

我的样式在 xaml 文件中定义 ButtonStyles.xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Style x:Key="SpecialButtonStyle" TargetType="{x:Type Button}">
        <Setter Property="Background" Value="Red"/>
    </Style>

</ResourceDictionary>

通常我使用这样的样式:

<UserControl x:Class="GUI.Modules.TextControl.Views.TextControlView"
             x:Name="TextControl"
             xmlns:resources="clr-namespace:GUI.Shared.Resources;assembly=GUI.Shared">
    <Grid>
        <Button Style="{Binding Path=[SpecialButtonStyle],  Source={x:Static resources:ResourceFactory.Resources}}">
    </Grid>
</UserControl>  

问题

现在我想在 View 中本地扩展我的风格。我发现您使用 BasedOn 属性.

<Button>
    <Button.Style>
        <Style TargetType="Button" BasedOn="{Binding Path=[SpecialButtonStyle],  Source={x:Static resources:ResourceFactory.Resources}}">
    
        </Style>
    </Button.Style>
</Button>

只有我的绑定方式不行,报错:

A Binding cannot be set on the BasedOn property of type Style. A Binding can only be set on a DependencyProperty of a DependencyObject.

如何将 ResourceFactory.Resources 中的这种样式用作 BasedOn 样式?

BasedOn property is a regular CLR property, not a dependency property, which means you cannot bind it. Furthermore the indexer syntax among other binding path constructs 仅在 Binding 标记扩展中可用,在 x:StaticStaticResourceDynamicResource.

中不可用

您可以基于 x:Static 实现创建您自己的标记扩展,但那非常复杂并且是错误的做法。相反,您应该考虑采用不同的 built-in 方法来解决您的问题。

如果要共享资源,为什么要创建静态 ResourceFactory? WPF 已经通过 Resources 属性 支持使用 App.xaml 资源字典和每个 FrameworkElement 范围内的资源提供资源。为您的共享资源创建资源字典,例如像这样:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WpfApp1">
   <ResourceDictionary.MergedDictionaries>
      <ResourceDictionary Source="pack://application:,,,/GUI.Shared;component/Resources/VectorIcons.xaml"/>
      <ResourceDictionary Source="pack://application:,,,/GUI.Shared;component/Resources/ButtonStyles.xaml"/>
   </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

如您所见,这与您的 ResourceFactory 相同,但更易于使用。使用 pack URI 例如:

将此词典包含到应用程序资源或任何项目的任何其他资源部分
<UserControl x:Class="GUI.Modules.TextControl.Views.TextControlView"
             x:Name="TextControl"
             xmlns:resources="clr-namespace:GUI.Shared.Resources;assembly=GUI.Shared">
   <UserControl.Resources>
      <ResourceDictionary>
         <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/GUI.Shared;component/Resources/SharedResourceDictionary.xaml"/>
         </ResourceDictionary.MergedDictionaries>
      </ResourceDictionary>
   </UserControl.Resources>
   <Grid>
      <Button>
         <Button.Style>
            <Style TargetType="Button" BasedOn="{StaticResource SpecialButtonStyle}">
               <!-- ...your style definition. -->
            </Style>
         </Button.Style>
      </Button>
   </Grid>
</UserControl>

这里不需要Binding,这样访问资源就容易多了。您也可以访问子控件中的资源,因为对资源的访问仅限于定义资源的范围。