如何从C#代码中访问WPF中的ResourceDictionary?

70

我在XAML文件中定义了一个DataTemplate,现在想通过C#代码访问它。请问如何访问? 我添加了一个新的ResourceDictionary文件,它的名称是Dictionary1.xaml。 我有一个数据模板,例如:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <DataTemplate x:Key="mytemplate">
        <TextBlock Text="Name:" Background="Blue"/>
    </DataTemplate>
</ResourceDictionary>

我有一个名为listBox1的ListBox,我想将它分配给它的Itemtemplate属性,但我不知道该如何做。

10个回答

72

由于在我的情况下 Application.Current 为空,因此我最终使用了以下代码:

    var myResourceDictionary = new ResourceDictionary();
    myResourceDictionary.Source =
        new Uri("/DllName;component/Resources/MyResourceDictionary.xaml",
                UriKind.RelativeOrAbsolute);  

然后,通过使用myResourceDictionary["KeyName"] as TypeOfItem,获取我所需要的特定键。

(来源)


5
我个人认为这是最好的方法,因为如果你要在库或其他地方定义它,它仍然可以工作。而采纳的答案则需要将所有的字典合并到应用程序中,可能会过于繁琐或不可行。 - Michal Ciechan
3
如果字典不在不同的程序集中,那么";component/Styles/Icons.xaml"就足够了。 - Shahin Dohan
所以,这里的重点是 ";component/" 指向您项目文件结构的根目录(在此示例中为当前程序集)。 - j00hi
我同意,这绝对是最好的答案,因为它总是有效的。起初我想知道是否需要将资源字典的构建属性设置为“Resources”,但实际上不需要,只需使用相对于项目的实际路径即可。例如,我的路径最终是:new Uri("/DllName;component/App/Views/aGeneralResources/StatusBadges.xaml, UriKind.RelativeOrAbsolute); - Jason Masters

60

你是在哪里定义它的?

如果你是在对象的ResourceDictionary中定义的,那么

Application.Current.Resources[typeof(yourDataTemplateTargetType)] 

应该可以工作。如果您将其定义为其他东西的成员,比如说一个ItemsControl,您需要获取对ItemsControl实例的处理并调用ItemTemplate属性。

编辑:好的,我想我们正在取得进展。所以你正在定义一个ResourceDictionary在它自己的文件中。在您可以在UI中使用它并从代码后台访问它之前,您需要将该ResourceDictionary合并到您的应用程序中。您这样做了吗?

如果是这样,那么下一步就是获取此资源。每个FrameworkElement都有一个名为FindResource的方法。这个方法很棒,因为它遍历ResourceDictionary树并尝试定位具有关键字的资源。因此,如果您想从UserControl访问此资源,可以在代码后面执行以下操作:

FindResource(typeof(yourDataTemplateTargetType));

如果这对您没有起作用,请向我们展示您如何声明此资源字典以及它如何合并到您的应用程序资源中。

4
我不明白。这个答案没有使用关键点。 - Colonel Panic
FindResource 接受一个参数,即键值。在此示例中,typeof(yourDataTemplateTargetType) 是该键值。 - Szymon Rozga
嗨。如果键不是类型,而是像OP的示例中的字符串呢? - Colonel Panic
是否应该在DataTemplate元素上设置DataType属性,而不是使用字符串键? - Colonel Panic
1
为什么这个被点赞了,它根本没有回答问题。 - Phil
显示剩余2条评论

7
如果您在App.xaml文件中的资源字典中有一个按钮模板,您可以使用以下代码访问它:

例如:

Application.Current.Resources[typeof(Button)]

4
如果您使用以下代码合并资源字典:
<Window x:Class="MainWindow">
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="DefaultStyle.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
</Window>

然后,您需要指定控件名称(在此示例中为MainWindow),而不是使用Application.Current.Resources["ResourceKey"]的方法如下所示。
var style = Application.Current.MainWindow.Resources["ResourceKey"];
// OR
var style = Application.Current.MainWindow.TryFindResource("ResourceKey");

4

如果您正在同一项目中获取资源,请尝试以下方法:

yourControl.Style = FindResource("YourResourceKey") as Style;

否则,请尝试以下方法:
ResourceDictionary res = (ResourceDictionary)Application.LoadComponent(new Uri("/ProjectName;component/FolderName/ResourceDictionaryName.xaml", UriKind.Relative)); 
yourControl.Style = (Style)res["YourResourceKey"];

1

您可以按照以下方式访问您添加到项目中的资源字典:

var rd = new ResourceDictionary();
rd.Source = new Uri("ms-appx:///Dictionary1.xaml");

然后,你就可以像这样访问存储在资源字典中的资源:
someObject.Property = rd["mytemplate"];

注意:
您需要根据资源字典相对于项目基目录的位置修改URI。


2
这不是一个WPF解决方案,ms-appx语法只在UWP中有效。 - Shahin Dohan

1
我在这里找到了答案。

https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/how-to-use-a-resourcedictionary-to-manage-localizable-string-resources

  • 创建一个资源字典 "ColorResources.xaml"
  • 添加到其中: 蓝色

  • 编辑你的 app.xml 并添加:

    <ResourceDictionary Source="ColorResources.xaml"/>

  • 从你的代码中使用颜色

    var color = (System.Windows.Media.Color)Application.Current.FindResource("ButtonColor1");

完成了

ps: 管理员能否修复代码?它没有显示出来,谢谢


0

在这里再添加另一个答案,以防您没有视图或Application.Current为空。 我意识到这可能不常见,但在我的情况下,我有一个针对父应用程序的插件,并且Application.Current为空; 我还想将我的资源之一作为ImageSource传递给父级,因此我没有创建XAML视图直接获取资源。

您还可以将字典转换为可在代码后台创建的对象。只需在XAML中设置x:Class属性,然后在代码后台中创建一个.xaml.cs文件。您更新的XAML(我们将其称为MyDictionary.xaml)看起来将类似于以下内容:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                    x:Class="Some.Namespace.MyDictionary"
                    mc:Ignorable="d">
    ...Resources...
</ResourceDictionary>

而代码背后(MyDictionary.xaml.cs)看起来会像这样:

using System.Windows;

namespace Some.Namespace
{
    public partial class MyDictionary : ResourceDictionary
    {
        public MyDictionary()
        {
            InitializeComponent();
        }
    }
}

不要忘记调用InitializeComponent(),因为这是加载资源的方法。实际上并不需要抱歉,见下面的编辑说明

在这样做之后,您可以在代码的任何地方构造类的实例,并通过键引用资源,如下所示:

var dictionary = new MyDictionary();
var resource = dictionary["whateverKey"] as WhateverResourceType;

感谢这篇文章给了我灵感。

编辑

使用这种设置时,我遇到了一个潜在的问题。我的一些控件会出现“无法重新初始化ResourceDictionary实例”的异常。经过进一步研究,发现这可能与在构造函数中调用InitializeComponent有关。因此,我从代码后台中删除了构造函数,并添加了一个静态方法来获取已初始化的实例,如下所示:

public static MyDictionary ConstructInitializedInstance()
{
    var dictionary = new MyDictionary();
    dictionary.InitializeComponent();
    return dictionary;
}

你也可以在代码后台创建并初始化。


0

以上的方法都可以根据位置获取资源,如果你正在遵循MVVMm,我建议这样做:

  1. 创建一个像ProvideDataTemplateService这样的服务(通常从Behavior继承来创建服务)
  2. 使用您选择的容器将此服务注入到您想要访问DataTemple的地方。

0

虽然我能够通过XAML加载我的资源字典,但是我无法通过C#的“代码后台”加载它。

所以我不得不让一个视图来加载它:(MyView.xaml)

  <UserControl.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="/My.Proj;component/My/Path/myResourceDictionary.xaml" />
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </UserControl.Resources>

然后通过实例化该视图并访问它在我的UT中访问它:

new MyView().Resources.MergedDictionaries[0]

有点取巧,但是有效。


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