【问题标题】:Cannot find resource named 'X', why not?找不到名为“X”的资源,为什么不呢?
【发布时间】:2013-03-11 07:29:42
【问题描述】:

我想为库存管理创建一个向导 UI。 xaml 中的相关行是:

<ContentPresenter Content="{Binding Current}" ContentTemplateSelector="{StaticResource inventorySelector}"/>

“Current”是当前活动的视图模型,AvailableInventoriesViewModel、GroupsViewModel、NewArticlesViewModel、ResultViewModel 之一。我这样定义的 DataTemplateSelector:

using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using Centron.WPF.WarehousingExtension.InventoryModule.ViewModels.WizardViewModels;

namespace Centron.WPF.WarehousingExtension.InventoryModule.UI.DataTemplateSelectors
{
    public class InventoryDatatemplateSelector : DataTemplateSelector
    {
        public DataTemplate AvailableDatatype { get; set; }
        public DataTemplate GroupsDatatype { get; set; }
        public DataTemplate NewDatatype { get; set; }
        public DataTemplate ResultDatatype { get; set; }

        public InventoryDatatemplateSelector()
        {
            Debug.WriteLine("");
        }

        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            if (item is AvailableInventoriesViewModel)
                return AvailableDatatype;
            else if (item is GroupsViewModel)
                return GroupsDatatype;
            else if (item is NewArticlesViewModel)
                return NewDatatype;
            else return ResultDatatype;
        }
    }
}

然后我像这样创建 DataTemplates 和 Selector 的实例:

<base:InventoryViewBase.Resources>
    <DataTemplate DataType="viewModels:AvailableInventoriesViewModel" x:Key="availableInventoriesDatatype">
        <controls:AvailableInventoriesView />
    </DataTemplate>
    <DataTemplate DataType="viewModels:GroupsViewModel" x:Key="groupsDatatype">
        <controls:GroupsView />
    </DataTemplate>
    <DataTemplate DataType="viewModels:NewArticlesViewModel" x:Key="newArticlesDatatype">
        <controls:NewArticlesView />
    </DataTemplate>
    <DataTemplate DataType="viewModels:ResultViewModel" x:Key="resultDatatype">
        <controls:ResultView/>
    </DataTemplate>
    <selector:InventoryDatatemplateSelector
            x:Key="inventorySelector" 
            AvailableDatatype="{StaticResource availableInventoriesDatatype}"
            GroupsDatatype="{StaticResource groupsDatatype}"
            NewDatatype="{StaticResource newArticlesDatatype}"
            ResultDatatype="{StaticResource resultDatatype}"/>
</base:InventoryViewBase.Resources>

我在我的 InventoryDatatemplateSelector 的构造函数中设置了一个断点,并且可以单步执行它,但是在下一个 Debug 步骤中,显然当它尝试设置该选择器实例的第一个属性时,我立即得到一个带有内部异常的异常:

找不到名为“availableInventoriesDatatype”的资源。资源名称区分大小写。

怎么回事,为什么明确定义的资源却找不到?

【问题讨论】:

  • 您可能不知道导致此问题的几件事。首先,xaml(除了极少数例外)从上到下解析并转换为对象图。这意味着顺序很重要。其次,DataTemplate 的设计目的是让它们根据 DataType 为自己分配一个 Key,这(本质上)取代了 x:Key 属性。所以,如果你想定义一个同时包含 DataType(在你使用它时完全没有必要)和一个 x:Key 的 DataTemplate,你必须把 x:Key 放在第一位。是的,令人困惑,但这是因为使 DT 更易于使用。

标签: wpf xaml mvvm


【解决方案1】:

好的,我找到了解决方案。唯一的错误是必须首先设置资源的“Key”属性。所以而不是:

    <DataTemplate DataType="viewModels:AvailableInventoriesViewModel" x:Key="availableInventoriesDatatype" >
        <controls:AvailableInventoriesView />
    </DataTemplate>

我需要:

    <DataTemplate x:Key="availableInventoriesDatatype" DataType="viewModels:AvailableInventoriesViewModel" >
        <controls:AvailableInventoriesView />
    </DataTemplate>

【讨论】:

  • 这太愚蠢了。我恨 xaml,复仇。
  • Xaml 很棒,您的评论无效。我不确定当您可以在数据模板选择器中内联定义静态资源时,为什么还要费心使用它们。另外,你这样做的方式有点奇怪。内容控件将自动在资源中搜索具有给定类型的第一个数据模板,因此如果每个模板都与特定类型匹配,您可能已经放弃了选择器
  • @我会按照你的方式尝试吗。我从我的 DataTemplates 中删除了 Key 属性,并且在 ContentPresenter 上没有使用选择器。现在 ContentPresenter 中显示的只是 Current.ToString(),而不是实际的控件。如果我将 DataTemplates 放在 ContentPresenter.Resources 中,也会发生这种情况。
  • 这看起来确实很愚蠢。属性顺序在 XML 中并不重要,因为 XAML 基于 XML,我不认为属性顺序很重要。
  • 对我而言,XAML 对 VB6 的支持已经遍及整个领域,而且我都做了很多。
【解决方案2】:

我知道你发现了你的问题,但我认为你应该知道有一种更简单的方法可以解决这个问题。由于您的每个 DataTemplates 都在不同的类上工作,因此您实际上不需要构建 DataTemplateSelector 来执行此操作。如果你只是简单地声明你的 DataTemplates 而没有像这样的键:

<DataTemplate DataType="{x:Type viewModels:AvailableInventoriesViewModel}">
    <controls:AvailableInventoriesView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:GroupsViewModel}">
    <controls:GroupsView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:NewArticlesViewModel}">
    <controls:NewArticlesView />
</DataTemplate>
<DataTemplate DataType="viewModels:ResultViewModel">
    <controls:ResultView/>
</DataTemplate>

并声明您的ContentPresenter,而不指定ContentTemplateSelector,例如:

<ContentPresenter Content="{Binding Current}" />

然后将为 Current 设置的任何类型选择适当的 DataTemplate。

这是一个更简洁的解决方案,无需自定义选择器。

WPF 功能强大且非常灵活,但您可能很难完全理解它。但是一旦你明白了它能做什么,我想你会改变对这件事的看法。

希望这会有所帮助。

【讨论】:

  • 您能否提供将多个 DataTemplate 分配给单个 ContentPresenter 的完整基本代码?我尝试将多个 DataTemplate 分配给 ContentPresenter.ContentTemplate 属性,但它只能设置一次。这给了我一个错误:。内容模板>
  • 我的意思是你不需要为你的 ContentPresenter 分配任何DataTemplate。如果您将密钥从 DataTemplate 声明中删除,那么您的 ContentPresenter 将自动使用与您的 DataType 匹配的 DataTemplate
  • 我已经按照你的方法试过了。我从我的 DataTemplates 中删除了 Key 属性,并且在 ContentPresenter 上没有使用任何选择器。现在 ContentPresenter 中显示的只是 Current.ToString(),而不是实际的控件。如果我将 DataTemplates 放在 ContentPresenter.Resources 中,也会发生这种情况。
  • 那一定是有什么东西让你搞砸了,因为它对我有用。如果你不能让它工作,那么我会发布另一个问题,询问你的新代码有什么问题。很难诊断 cmets 中的任何内容,并且对未来遇到相同问题的用户没有帮助。
  • 另外,您在 DataType 声明中需要 x:Type 是正确的。我最近才发现我并不总是需要 x:Type 语法(显然它不能通用)。我检查了我的示例应用程序,果然我使用的是 x:Type,当我删除它时它停止工作。抱歉疏忽。我已经为未来的用户修复了示例。
【解决方案3】:

这是我的情况 - 我在 DataTemplate 之前声明了 ItemTemplate:

<ListBox Name="peopleListBox" Grid.Column="1" Grid.Row="2" 
     ItemsSource="{Binding Source={StaticResource ExpenseDataSource}, XPath=Person}"
     ItemTemplate="{StaticResource nameItemTemplate}">
    </ListBox>

<Grid.Resources>
            <!-- Name item template -->
            <DataTemplate x:Key="nameItemTemplate">
                <Label Content="{Binding XPath=@Name}"/>
            </DataTemplate>          
</Grid.Resources>

然后我只需更改顺序并将 Grid.Resources 放在 Listbox 之前,如下所示,现在一切正常!!!

<Grid.Resources>
        <!-- Name item template -->
        <DataTemplate x:Key="nameItemTemplate">
            <Label Content="{Binding XPath=@Name}"/>
        </DataTemplate>          
    </Grid.Resources>

<ListBox Name="peopleListBox" Grid.Column="1" Grid.Row="2" 
     ItemsSource="{Binding Source={StaticResource ExpenseDataSource}, XPath=Person}"
     ItemTemplate="{StaticResource nameItemTemplate}">
    </ListBox>

XAML 是不是很蠢? :) :)

【讨论】:

  • 操作顺序在任何非编译语言中都很重要,XML 就是这样。
【解决方案4】:

在样式嵌套组件的情况下,我会提供更多细节。在本例中,MainWindowGrid 包含 UserControlGrid 和 PanelGrid。

以下代码将不起作用。

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:XeerSoft.UX.Themes">
    <Thickness x:Key="PanelRowMargin">0,0,0,10</Thickness>
    <Thickness x:Key="PanelPadding">10</Thickness>

    <Color x:Key="Primary">#005C9D</Color>
    <SolidColorBrush x:Key="PrimaryBrush" Color="{StaticResource Primary}"></SolidColorBrush>

    <Color x:Key="Accent">#E3672B</Color>
    <SolidColorBrush x:Key="AccentBrush" Color="{StaticResource Accent}"></SolidColorBrush>

    <Color x:Key="DarkGray">#777777</Color>
    <SolidColorBrush x:Key="DarkGrayBrush" Color="{StaticResource DarkGray}"></SolidColorBrush>

    <Color x:Key="LightGray">#E4E4E4</Color>
    <SolidColorBrush x:Key="LightGrayBrush" Color="{StaticResource LightGray}"></SolidColorBrush>

    <Style x:Key="MainWindowGrid"
           BasedOn="{StaticResource {x:Type Grid}}"
           TargetType="Grid">
        <Setter Property="Background" Value="{StaticResource LightGrayBrush}"/>
    </Style>

    <Style x:Key="GridPanel"
           BasedOn="{StaticResource {x:Type Grid}}"
           TargetType="Grid">
        <Setter Property="Background" Value="White"/>
    </Style>

    <Style x:Key="UserControlPanel"
           BasedOn="{StaticResource {x:Type UserControl}}"
           TargetType="UserControl">
        <Setter Property="Background" Value="White"/>
        <Setter Property="BorderBrush" Value="{StaticResource DarkGrayBrush}"/>
        <Setter Property="BorderThickness" Value="1"/>
    </Style>

</ResourceDictionary>

现在,如果您交换声明顺序以使 MainWindowGrid 最后运行,它将起作用。 (外部范围,最后)

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:XeerSoft.UX.Themes">
    <Thickness x:Key="PanelRowMargin">0,0,0,10</Thickness>
    <Thickness x:Key="PanelPadding">10</Thickness>

    <Color x:Key="Primary">#005C9D</Color>
    <SolidColorBrush x:Key="PrimaryBrush" Color="{StaticResource Primary}"></SolidColorBrush>

    <Color x:Key="Accent">#E3672B</Color>
    <SolidColorBrush x:Key="AccentBrush" Color="{StaticResource Accent}"></SolidColorBrush>

    <Color x:Key="DarkGray">#777777</Color>
    <SolidColorBrush x:Key="DarkGrayBrush" Color="{StaticResource DarkGray}"></SolidColorBrush>

    <Color x:Key="LightGray">#E4E4E4</Color>
    <SolidColorBrush x:Key="LightGrayBrush" Color="{StaticResource LightGray}"></SolidColorBrush>


    <Style x:Key="GridPanel"
           BasedOn="{StaticResource {x:Type Grid}}"
           TargetType="Grid">
        <Setter Property="Background" Value="White"/>
    </Style>

    <Style x:Key="UserControlPanel"
           BasedOn="{StaticResource {x:Type UserControl}}"
           TargetType="UserControl">
        <Setter Property="Background" Value="White"/>
        <Setter Property="BorderBrush" Value="{StaticResource DarkGrayBrush}"/>
        <Setter Property="BorderThickness" Value="1"/>
    </Style>

    <Style x:Key="MainWindowGrid"
           BasedOn="{StaticResource {x:Type Grid}}"
           TargetType="Grid">
        <Setter Property="Background" Value="{StaticResource LightGrayBrush}"/>
    </Style>
</ResourceDictionary>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-13
    • 2013-10-01
    • 1970-01-01
    相关资源
    最近更新 更多