在WPF中通过代码后台访问资源

89

我在我的窗口资源中定义了一个自定义集合,代码如下(这是一个Sketchflow应用程序,因此该窗口实际上是一个UserControl):

<UserControl.Resources>
    <ds:MyCollection x:Key="myKey" x:Name="myName" />
</UserControl.Resources>

我想在代码后台中引用这个集合,我原本以为可以通过 x:Name 来实现,但似乎无法访问它。

我可以使用以下方式获取对它的引用:

myRef = (MyCollection) this.FindName("myKey");

但这似乎是一种hackish的做法,这是不好的实践,有更好的方法吗?谢谢 :)

7个回答

102

您应该使用System.Windows.Controls.UserControlFindResource()TryFindResource()方法。

另外,一个好的实践是创建一个字符串常量,将您在资源字典中的键的名称映射到该字符串常量中(这样您就可以在一个地方更改它)。


8
根据上下文,您可以使用以下代码之一:Application.Current.FindResource(errorColorResourceName) as MyCollection或this.FindResource("RainbowBrush") as MyCollection。 - Tal Segal
16
你能否详细说明“另外,一个好的实践是创建一个字符串常量,将其映射到资源字典中的键名称(这样你就可以在一个地方进行更改)”?这样的字符串常量应放在哪里才能同时更改XAML键和C#代码后台中的内容? "另外,一个好的实践是创建一个字符串常量,将其映射到资源字典中的键名称(这样你就可以在一个地方进行更改)"的意思是,在使用资源字典的时候,可以先定义一个字符串常量来保存键的名称,以便将来在需要修改该键名称时只需更改一处即可。这个字符串常量可以放在与资源字典相关的任何位置,例如可以将其定义在C#代码的类中或者XAML文件的资源区域中。如果将其定义在XAML文件中,那么需要使用静态类来引用它,并且确保在C#代码中也使用同一个字符串常量来引用该键名称。 - Mike Christiansen
1
你能详细说明一下“此外,一个好的实践是创建一个字符串常量,将资源字典中键的名称映射到该常量(这样您就可以在一个地方进行更改)”吗?这样的字符串常量应该放在哪里,以便同时更改XAML键和C#代码后台? - tolache
@MikeChristiansen AdonisUI 是一个很好的例子,如果你在 src/AdonisUI/Brushes.cs 中查看,你会看到一堆在模板中使用的键,例如在 Buttons.cs 中,你会看到 {DynamicResource {x:Static adonisUi:Brushes.ForegroundBrush}} - undefined

30

你也可以使用this.Resources["mykey"]。我猜这对于您自己建议来说并没有更好。


1
这是针对Windows 8商店应用程序的。 - cederlof
3
@cederlof,您也可以在WPF中使用这个。 - user5000935
1
如果资源在另一个文件中,例如主题颜色,这种方法将无法工作。使用FindResource是正确的方法。 - John C

23

虽然不是直接回答,但与此问题密切相关:

如果资源在不同的文件中,例如ResourceDictionary.xaml

您可以简单地为其添加x:Class

<ResourceDictionary x:Class="Namespace.NewClassName"
                    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
    <ds:MyCollection x:Key="myKey" x:Name="myName" />
</ResourceDictionary>

然后在后端代码中使用它:

var res = new Namespace.NewClassName();
var col = res["myKey"];

12
为了使用资源文件中的键,需要在尝试访问键之前调用 res.InitializeComponent() 方法来初始化对象。否则,对象将不会显示任何键,而对 res["myKey"] 的调用将返回 null。+1。 - Stephen Ross
哇,太棒了...我从来不知道你可以这样做,它很快地解决了我的问题!像@StephenRoss说的那样,我确实需要调用InitializeComponent(),但除此之外,它完美地工作。 - sfaust
一个完美的解决方案,可从“转换器”中使用。 - Brains

11

如果你想从其他类(例如不是XAML Codebehind)访问资源,你可以使用

Application.Current.Resources["resourceName"];

来自 System.Windows 命名空间。


如果您需要从静态构造函数或方法访问资源,因此无法调用FindResourceTryFindResource,则这将非常有用。 - Steven Rands

9
您可以像这样使用资源键:
<UserControl.Resources>
    <SolidColorBrush x:Key="{x:Static local:Foo.MyKey}">Blue</SolidColorBrush>
</UserControl.Resources>
<Grid Background="{StaticResource {x:Static local:Foo.MyKey}}" />

public partial class Foo : UserControl
{
    public Foo()
    {
        InitializeComponent();
        var brush = (SolidColorBrush)FindResource(MyKey);
    }

    public static ResourceKey MyKey { get; } = CreateResourceKey();

    private static ComponentResourceKey CreateResourceKey([CallerMemberName] string caller = null)
    {
        return new ComponentResourceKey(typeof(Foo), caller); ;
    }
}

请注意,这取决于键的类型。例如,DataTemplate 中的键的类型为 DataTemplateKey - Mike de Klerk

1
我使用下面的代码获取了关于 C#(桌面 WPF W/ .NET Framework 4.8)的资源。
{DefaultNamespace}.Properties.Resources.{ResourceName}

0
微软文档中的一个漂亮干净的示例使它变得简单:
private void myButton_Click(object sender, RoutedEventArgs e)
{
  Button button = (Button)sender;
  button.Background = (Brush)this.FindResource("RainbowBrush");
}

1
这个问题已经得到了解答。 - Honza Pačuta

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