wpf 找不到名为“X”的资源,为什么不呢?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15553446/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Cannot find resource named 'X', why not?
提问by Hackworth
I want to create a wizard UI for inventories management. The relevant line in the xaml is:
我想为库存管理创建一个向导 UI。xaml 中的相关行是:
<ContentPresenter Content="{Binding Current}" ContentTemplateSelector="{StaticResource inventorySelector}"/>
"Current" is the currently active view model, one of AvailableInventoriesViewModel, GroupsViewModel, NewArticlesViewModel, ResultViewModel. The DataTemplateSelector I have defined as such:
“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;
}
}
}
Then I create instances of the DataTemplates and a Selector like this:
然后我像这样创建 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>
I set a breakpoint in the constructor of my InventoryDatatemplateSelector, and can step through it, but in the next Debug step, apparently when it tries to set the first property of that selector instance, I immediately get an exception with inner exception:
我在 InventoryDatatemplateSelector 的构造函数中设置了一个断点,并且可以单步执行,但是在下一个 Debug 步骤中,显然当它尝试设置该选择器实例的第一个属性时,我立即收到一个带有内部异常的异常:
Cannot find resource named \"availableInventoriesDatatype\". Resource names are case sensitive.
找不到名为 \"availableInventoriesDatatype\" 的资源。资源名称区分大小写。
What's the deal, why is the resource not found when it's clearly defined?
怎么回事,为什么资源在明确定义的情况下找不到?
回答by Hackworth
Ok, I found the solution. The only error was that the "Key" property of a resource has to be set first. So instead of:
好的,我找到了解决方案。唯一的错误是必须首先设置资源的“Key”属性。所以而不是:
<DataTemplate DataType="viewModels:AvailableInventoriesViewModel" x:Key="availableInventoriesDatatype" >
<controls:AvailableInventoriesView />
</DataTemplate>
I need:
我需要:
<DataTemplate x:Key="availableInventoriesDatatype" DataType="viewModels:AvailableInventoriesViewModel" >
<controls:AvailableInventoriesView />
</DataTemplate>
回答by Brent Stewart
I know you found your problem, but there is a simpler way to solve this that I thought you should know about. Since each of your DataTemplates are working on different classes, you don't really need to build your DataTemplateSelector to do this. If you simply declare your DataTemplates without keys like:
我知道你发现了你的问题,但有一种更简单的方法可以解决这个问题,我认为你应该知道。由于您的每个 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>
And declare your ContentPresenterwithout specifying the ContentTemplateSelectorsuch as:
并在ContentPresenter不指定的情况下声明您的,ContentTemplateSelector例如:
<ContentPresenter Content="{Binding Current}" />
Then the appropriate DataTemplate will be selected for whatever Type Currentis set to.
然后将为任何Current设置的类型选择适当的 DataTemplate 。
This is a much cleaner solution and eliminates the need for the custom selector.
这是一个更简洁的解决方案,并且不需要自定义选择器。
WPF is powerful and very flexible but can be it can be challenging to get your head wrapped around it. But once you understand what it can do, I think that you will change your opinion on the matter.
WPF 功能强大且非常灵活,但让您的头脑围绕它可能具有挑战性。但是一旦你了解了它可以做什么,我认为你会改变你对此事的看法。
Hope this helps.
希望这可以帮助。
回答by Shahdat
Here was my case - I declared ItemTemplate before DataTemplate:
这是我的情况 - 我在 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>
Then I just change the order and put Grid.Resources before the Listbox like bellow, everything fine now!!!
然后我只需更改顺序并将 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>
Is not XAML so stupid? :) :)
XAML 是不是很蠢?:) :)
回答by micksatana
I give more detail in case of styling nested components. In this example, MainWindowGrid contains UserControlGrid and PanelGrid.
在样式嵌套组件的情况下,我会提供更多细节。在本例中,MainWindowGrid 包含 UserControlGrid 和 PanelGrid。
The following code will not work.
以下代码将不起作用。
<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>
Now, if you swap the declaration sequence so the MainWindowGrid goes last, it will work. (Outer scope, goes last)
现在,如果您交换声明顺序,使 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>

