DataTemplate中的StaticResource引用

11

当在 ResourceDictionary 中定义的 DataTemplate 中引用 StaticResources 时,我遇到了一些奇怪的行为。

在此示例中,我使用在 ResourceDictionary 中定义的 DataTemplate,向 ListBox 填充数字 1 到 9。

以下是 MainWindow.xaml 代码:

<Window x:Class="testResources.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow"
    Width="525"
    Height="350">
<Grid>
    <ListBox Width="100" ItemTemplate="{StaticResource NumberTemplate}">
        <ListBox.ItemsSource>
            <Int32Collection>1,2,3,4,5,6,7,8,9</Int32Collection>
        </ListBox.ItemsSource>
    </ListBox>
</Grid>

NumberTemplate 是在 ResourceDictionary1.xaml 中定义的:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DataTemplate x:Key="NumberTemplate">
    <Grid Background="{StaticResource CoolNumbersColor}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="35" />
        </Grid.ColumnDefinitions>
        <TextBox Grid.Column="0" Background="{StaticResource CoolNumbersColor}" Text="{Binding Mode=OneWay}" />
    </Grid>
</DataTemplate>

静态资源CoolNumbersColor在App.xaml中定义,与ResourceDictionary1.xaml一起。这是我的App.xaml文件:

<Application x:Class="testResources.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" StartupUri="MainWindow.xaml">
<Application.Resources>
    <ResourceDictionary>
        <SolidColorBrush x:Key="CoolNumbersColor">GreenYellow</SolidColorBrush>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/ResourceDictionary1.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

首先,我可以在Visual Studio 2010设计器中看到期望的行为。确实会显示一个有颜色的数字列表。但是当尝试运行这个示例时,我收到了以下错误:

 

"Cannot find resource named 'CoolNumbersColor'. Resource names are   case sensitive"

我不明白为什么会发生这种情况。难道CoolNumbersColor的评估方式有些延迟吗?从词法上讲,它在合并的资源字典前面。

除了使用DynamicResources之外,使其工作的唯一方法是创建第二个ResourceDictionary(例如ResourceDictionary2.xaml),在那里定义CoolNumbersColor,并将它们全部合并在ResourceDictionary.MergedDictionaries中,如下所示:

<Application x:Class="testResources.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" StartupUri="MainWindow.xaml">
<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/ResourceDictionary2.xaml" />
            <ResourceDictionary Source="pack://application:,,,/ResourceDictionary1.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>


1
你在哪里使用这个资源?我在一个小应用程序中尝试了一下,结果在我的端上运行良好。 - Rohit Vats
你是否尝试在Application.Resources中的ResourceDictionary.MergedDictionaries之前定义CoolNumbersColor? - Theodore Zographos
是的,我已经这样做了,并将其用于“ListBox”的“DataTemplate”中。仍然没有问题。你可以在小应用程序中尝试一下吗?我怀疑问题出在其他地方。 - Rohit Vats
将DataTemplate定义在单独的ResourceDictionary中。但这样对我不起作用。 - Theodore Zographos
1个回答

7
我猜这是由以下原因引起的: StaticResource
  • 不支持向前引用
  • 仅在程序启动时设置一次:资源的加载时间查找
DynamicResource
  • 支持向前引用
  • 每次访问资源时应用:运行时间查找
向前引用的示例

不适用于StaticResource

<Window x:Class="SeveralResourceDictionariesHelp.MainWindow"
        Background="{StaticResource testColor}" ... >

<Window.Resources>
    <SolidColorBrush x:Key="testColor">Red</SolidColorBrush>
</Window.Resources>

使用DynamicResource

<Window x:Class="SeveralResourceDictionariesHelp.MainWindow"
        Background="{DynamicResource testColor}" ... >

<Window.Resources>
    <SolidColorBrush x:Key="testColor">Red</SolidColorBrush>
</Window.Resources>

在应用程序启动时,CoolNumbersColor(StaticResource)在DataTemplate的“可见性”范围内不可用,因此会抛出异常,它会尝试在其作用域中查找但无法找到。
使用资源字典时,它们被加载到第一个队列中,因此在这种情况下将是存在资源的单个视图范围。
当应用程序启动时,DynamicResource不会被加载,它将在首次请求时加载,在这个阶段DataTemplate“看到”了资源。
问题仍然存在:为什么这个技巧在Studio中起作用?可能在运行时和设计模式下的加载之间存在差异,但我在文档或其他地方没有找到官方确认。

@Theodore Zographos:是的,我想在我的答案中写下它,但只限于一个段落。 - Anatoliy Nikolaev
至少在词法上,我没有看到前向引用,因为CoolNumbersColorMergedDictionaries之前被定义。当解析器评估DataTemplate时,它应该会找到CoolNumbersColor,因为它在查找链中被定义:1.相同的xaml 2.Generic.xaml 3.app.resources - Theodore Zographos
2
@Theodore Zographos:在WPF中,元素首先从其资源部分查找资源,然后向上冒泡到元素树的根,最后到达系统主题,以下顺序说明了顺序:1. 元素层次结构。2. 应用程序资源。3. 类型主题。4. 系统主题。 - Anatoliy Nikolaev
@Theodore Zographos:看起来是前向引用。当样式在本地可见性时-必须是静态的,如果不是-则为动态。我在互联网上遇到过这个声明,如果您想要,我可以给您提供来源。 - Anatoliy Nikolaev
然而,CoolNumbersColor确实在资源链中。似乎合并的字典首先在App.Resources中进行评估。 - Theodore Zographos
2
@Theodore Zographos:是的,没错。在App.xaml中的字典会被优先加载,所有可用的资源都是全局的,适用于整个应用程序。 - Anatoliy Nikolaev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接