【问题标题】:Using BasedOn Style with static ResourceDictionary in different Assembly在不同的程序集中使用带有静态 ResourceDictionary 的 BasedOn Style
【发布时间】:2020-11-02 09:52:27
【问题描述】:

背景

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

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>

只允许我的绑定方法,报错:

不能在Style 类型的BasedOn 属性上设置BindingBinding 只能在 DependencyObject 的 DependencyProperty 上设置。

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

【问题讨论】:

    标签: wpf xaml resourcedictionary


    【解决方案1】:

    BasedOn 属性是常规 CLR 属性,而不是依赖属性,这意味着您无法绑定它。此外,other binding path constructs 中的索引器语法仅在 Binding 标记扩展中可用,在 x:StaticStaticResourceDynamicResource 中不可用。

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

    如果你想共享资源,为什么要创建一个静态的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,这样访问资源要容易得多。您也可以访问子控件中的资源,因为对资源的访问范围仅限于定义它们的位置。

    【讨论】:

    • 谢谢!我这样做的原因是能够轻松地从我的视图模型中访问字典,例如Icon = ResourceFactory.Resources[ResourceFactory.BoxIconKey] as Canvas;。此外,我不想再次合并每个 UserControl 中的所有词典,而且我不知道我可以加载合并后的词典。我现在使用混合,按照你在 xaml 中的建议做,并在我的视图模型中使用旧技巧。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-11
    • 1970-01-01
    • 2019-08-17
    相关资源
    最近更新 更多