Search code examples
.netwpf

How to get the static resource key from a control?


Wpf control can use the pre-defined resource in runtime. Is it able to get the static resource key from a control? And how?

Thanks!

<Window
    x:Class="GetResourceKeyWpf.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=System.Runtime"
    Width="800"
    Height="450"
    WindowStartupLocation="CenterScreen">
    <Window.Resources>
        <system:String x:Key="MyName">Will</system:String>
    </Window.Resources>
    <StackPanel>
        <TextBlock Loaded="MyNameTb_Loaded" Text="{StaticResource MyName}" />
    </StackPanel>
</Window>
using System.Windows;

namespace GetResourceKeyWpf;

public sealed partial class MainWindow
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void MyNameTb_Loaded(object sender, RoutedEventArgs e)
    {
        // Is it able to the static resource key "MyName" for text property?
    } 
}

I searched my question in SO, and got a similar question for get the key for dynamic resource.

How to get a dynamic resource key name programmatically?

I tried it for static resource but ReadLocalValue just returned the string value "Will" which is not my target.

PS:

My expected result is to get the string "MyName", not the content "Will".

Then, I can do some job like TextBlock.ToolTips = resourceKey, to display the key when my app is running in debug mode for checking if someone choosed the wrong resource.


Solution

  • Logically, the StaticResource Markup Extension is equivalent to the FindResource method.

    object myName = FindResource("MyName"); // return "Will"
    

    If a certain hierarchy of resources is possible and you need to get a value from a certain level of the hierarchy, then you need to execute a method from an element from this level of the hierarchy.

        <Window.Resources>
            <system:String x:Key="MyName">Will</system:String>
        </Window.Resources>
        <StackPanel>
            <StackPanel.Resources>
                <system:String x:Key="MyName">Will-StackPanel</system:String>
            </StackPanel.Resources>
            <TextBlock x:Name="tbl" Loaded="MyNameTb_Loaded" Text="{StaticResource MyName}" />
        </StackPanel>
    
    object myName = tbl.FindResource("MyName"); // return "Will-StackPanel"
    

    but ReadLocalValue just returned the string value "Will" which is not my target

    This is what I didn't understand at all in your question. The resource with the key "MyName " is the string "Will". But this doesn't suit you. And what result did you want to get? Please explain in more detail.

    Perhaps you are interested in checking if a key is in a dictionary?

    bool isContains = Resources.Contains("items");
    

    Or you can get all the keys from the dictionary:

    System.Collections.ICollection keys = Resources.Keys;
    

    To search for a key hierarchically, you can create an extension method and use it:

        public static partial class FrameworkElementHelper
        {
            public static bool FindResourceKey(this FrameworkElement? element, object key)
            {
                while (element is not null)
                {
                    if (element.Resources.Contains(key))
                    {
                        return true;
                    }
                    element = element.Parent as FrameworkElement;
                }
                return false;
            }
        }
    
    bool isFindKey = tbl.FindResourceKey("MyName"); // Return true
    

    Perhaps you need to get the value of a key from the element property to which it is set using StaticResource? If so, then it is not possible to do so. DinamicResource creates an Expression and assigns it to a DependencyProperty. That is why DinamicResource can ONLY be used with DependencyProperty. Unlike it, StaticResource returns the desired value, so it can be used with ANY property. And as a result, it is impossible to find out from the received value by which key it was obtained.

    Specifically for your task, you can replace StaticResource with DynamicResource. But in general, this will not always be possible.

    I would also advise you to change the approach to implementing the task. If you want to check the settings of its child elements from the control logic, it is better to use CustomControl with mandatory template elements.