在不同的程序集中使用带有静态 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:Static
、StaticResource
或 DynamicResource
.
中不可用
您可以基于 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
,这样访问资源就容易多了。您也可以访问子控件中的资源,因为对资源的访问仅限于定义资源的范围。
背景
我的解决方案中有多个项目,在一个项目中,我制作了一个包含合并的 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 theBasedOn
property of typeStyle
. ABinding
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:Static
、StaticResource
或 DynamicResource
.
您可以基于 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
,这样访问资源就容易多了。您也可以访问子控件中的资源,因为对资源的访问仅限于定义资源的范围。