我正在尝试正确设置我的样式。因此,我创建了一个外部 ResourceDictionary
对于所有常见的样式属性,我在其中定义了一个默认字体系列,如下所示:
<FontFamily x:Key="Default.FontFamily">Impact</FontFamily>
这样,当我更改这一行时,家庭会在所有地方发生变化。
使用和引用静态资源
现在我想在没有其他任何定义的地方使用这个默认字体系列,这是在大多数地方(但不是全部)。但是,我想保留为使用它的任何地方定义其他字体系列的能力。所以我选择了我找到的示例here和 here ,并为组框标题明确定义了默认字体:
<StaticResource x:Key="GroupBox.HeaderFontFamily" ResourceKey="Default.FontFamily"/>
我在
TextBlock
上使用它包含在我的组框模板中。<Style x:Key="GroupBoxHeaderTextStyle" TargetType="{x:Type TextBlock}">
<Setter Property="FontFamily" Value="{StaticResource GroupBox.HeaderFontFamily}"/>
</Style>
到目前为止,这是有效的。但是,只要我添加另一行:
<StaticResource x:Key="GroupBox.HeaderFontFamily" ResourceKey="Default.FontFamily"/>
<StaticResource x:Key="FormLabel.FontFamily" ResourceKey="Default.FontFamily"/>
我抛出了这个异常:
Exception: Cannot find resource named 'Hsetu.GroupBox.HeaderFontFamily'. Resource names are case sensitive.
所以我经历过,当 WPF 后跟
StaticResource
时,无法找到直接寻址的元素。 (是的,这也适用于 StaticResources 以外的元素。例如,如果我尝试直接处理字体系列 "Default.FontFamily"
,我会得到相同的错误,因为它位于 StaticResource
元素之前)使用 DynamicResource 并引用 StaticResource
我试过使用
DynamicResource
正如第二个示例中所建议的,我提供了上面的链接:<DynamicResource x:Key="GroupBox.HeaderFontFamily" ResourceKey="Default.FontFamily"/>
<DynamicResource x:Key="FormLabel.FontFamily" ResourceKey="Default.FontFamily"/>
<Style x:Key="GroupBoxHeaderTextStyle" TargetType="{x:Type TextBlock}">
<Setter Property="FontFamily" Value="{StaticResource GroupBox.HeaderFontFamily}"/>
</Style>
这会引发以下错误:
ArgumentException: 'System.Windows.ResourceReferenceExpression' is not a valid value for property 'FontFamily'.
使用和引用动态资源
使用
DynamicResource
在我的组框样式中只更改了错误消息:<DynamicResource x:Key="GroupBox.HeaderFontFamily" ResourceKey="Default.FontFamily"/>
<DynamicResource x:Key="FormLabel.FontFamily" ResourceKey="Default.FontFamily"/>
<Style x:Key="GroupBoxHeaderTextStyle" TargetType="{x:Type TextBlock}">
<Setter Property="FontFamily" Value="{DynamicResource GroupBox.HeaderFontFamily}"/>
</Style>
System.InvalidCastException: 'Unable to cast object of type 'System.Windows.ResourceReferenceExpression' to type 'System.Windows.Media.FontFamily'.'
添加虚拟元素
所以,因为这个问题只发生在我的
StaticResource
紧随其后的是另一个,我想在资源之间包含一个虚拟元素。<StaticResource x:Key="GroupBox.HeaderFontFamily" ResourceKey="Default.FontFamily"/>
<Separator x:Key="Dummy"/>
<StaticResource x:Key="FormLabel.FontFamily" ResourceKey="Default.FontFamily"/>
现在,这行得通。万岁!但是等一下……继续,我尝试使用第二个资源
"FormLabel.FontFamily"
<Style x:Key="FormLabelStyle" TargetType="{x:Type Label}">
<Setter Property="FontFamily" Value="{StaticResource FormLabel.FontFamily}"/>
</Style>
这会引发另一个异常:
System.InvalidCastException: 'Unable to cast object of type 'System.Windows.Controls.Separator' to type 'System.Windows.Media.FontFamily'.'
漏洞?
我什至没有使用
Separator
怎么回事?我假设,在处理 StaticResource 时,WPF 实际上会尝试使用前面的元素——它只在开始时起作用,因为前面的元素是 FontFamily
偶然 - 而不是 ResourceKey
引用的元素.同时,使前面的元素无法直接访问。为了证实我的怀疑,我替换了 Separator
与另一个 FontFamily
.<StaticResource x:Key="GroupBox.HeaderFontFamily" ResourceKey="Default.FontFamily"/>
<FontFamily x:Key="Dummy">Courier New</FontFamily>
<StaticResource x:Key="FormLabel.FontFamily" ResourceKey="Default.FontFamily"/>
事实上,它确实有效,但标签现在使用 Courier New 字体而不是引用的 Impact 字体。
顺便提一句。这不仅发生在字体系列中,还发生在其他属性(
FontSize
、 BorderThickness
、 FontWeight
等)中。那么,这实际上是 WPF 中的错误还是 StaticResource
s 应该这样做(这对我来说没有任何意义)?我怎样才能在多个地方使用我的字体系列,只定义一次?
最佳答案
不确定奇数引用发生了什么,但如果您使用 DynamicResource
为资源设置别名您必须使用 StaticResource
进行查找.也许有一种方法可以使引用另一个动态资源的动态资源解析为原始值(例如,使用自定义标记扩展),但这不是默认情况下发生的。
<Grid>
<Grid.Resources>
<FontFamily x:Key="Default.FontFamily">Impact</FontFamily>
<DynamicResource x:Key="FormLabel.FontFamily" ResourceKey="Default.FontFamily"/>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" FontFamily="{StaticResource FormLabel.FontFamily}">Test</Label>
<TextBox Grid.Column="1"/>
</Grid>
所以步骤是:
要自己解析该值,您可以编写一个使用
MultiBinding
的自定义标记扩展。在内部获取对绑定(bind)元素的引用,然后解析其上的资源。<FontFamily x:Key="Default.FontFamily">Impact</FontFamily>
<DynamicResource x:Key="FormLabel.FontFamily" ResourceKey="Default.FontFamily"/>
<Style TargetType="{x:Type Label}">
<Setter Property="FontFamily" Value="{local:CascadingDynamicResource FormLabel.FontFamily}"/>
</Style>
public class CascadingDynamicResourceExtension : MarkupExtension
{
public object ResourceKey { get; set; }
public CascadingDynamicResourceExtension() { }
public CascadingDynamicResourceExtension(object resourceKey)
{
ResourceKey = resourceKey;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
var binding = new MultiBinding { Converter = new CascadingDynamicResourceResolver() };
binding.Bindings.Add(new Binding { RelativeSource = new RelativeSource(RelativeSourceMode.Self) });
binding.Bindings.Add(new Binding { Source = ResourceKey });
return binding;
}
}
internal class CascadingDynamicResourceResolver : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var target = (FrameworkElement)values[0];
var resourceKey = values[1];
var converter = new ResourceReferenceExpressionConverter();
object value = target.FindResource(resourceKey);
while (true)
{
try
{
var dynamicResource = (DynamicResourceExtension)converter.ConvertTo(value, typeof(MarkupExtension));
value = target.FindResource(dynamicResource.ResourceKey);
}
catch (Exception)
{
return value;
}
}
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
丑的
try
/catch
存在是因为 ResourceReferenceExpressionConverter
没有正确实现 CanConvertFrom
不幸的是ResourceReferenceExpression
是内部的,所以这可能仍然是最干净的方法。它仍然假设一些内部结构,例如转换为 MarkupExtension
, 尽管。此扩展解决了任何级别的别名,例如有两个别名:
<FontFamily x:Key="Default.FontFamily">Impact</FontFamily>
<DynamicResource x:Key="FormLabel.FontFamily" ResourceKey="Default.FontFamily"/>
<DynamicResource x:Key="My.FontFamily" ResourceKey="FormLabel.FontFamily"/>
<Style TargetType="{x:Type Label}">
<Setter Property="FontFamily" Value="{local:CascadingDynamicResource My.FontFamily}"/>
</Style>
关于wpf - 在另一个 StaticResource 中引用一个 StaticResource,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51968177/