为什么无法在控件的构造函数中获取资源

本文关键字:构造函数 获取 资源 控件 为什么 | 更新日期: 2023-09-27 18:35:13

Background

我知道使用 FindResource 方法获取资源在从控件的构造函数中完成时不起作用,因为它将始终返回 null。

public class MyButton : Button
{
    public MyButton()
    {
        Style = FindResource("myStyle") as Style;
    }
}

我知道这可以通过OnApplyTemplate方法完成。

public override void OnApplyTemplate()
{
    Style = FindResource("myStyle") as Style;
    base.OnApplyTemplate();
}

问题

为什么?我认为这与可视化树的加载有关,但我希望从你们 WPF 专家那里得到一个更详细和准确的答案(或者只是一个正确的答案,以防我完全不在这里)。

为什么无法在控件的构造函数中获取资源

因为查找资源最需要遍历逻辑元素树(查找与祖先关联的资源)或查看当前元素的Resources

在这两种情况下,除非ParentResources分别已设置为其"正确"值,否则这是不可能的;这些是属性,XAML 序列化引擎在构造函数运行设置它们。也就是说,当你写

<Button Height="80" Width="150" />

XAML 反序列化程序最终执行等效的

var button = new Button(); // element is instantiated
button.Height = 80;        // ...and THEN properties are set
button.Width = 150;

因此,不能在构造函数中执行任何依赖于所设置属性的操作。

为了证实上述内容,从FindResource的文档中:

如果在调用元素上找不到资源,则父元素 元素接下来搜索逻辑树中的元素,然后搜索应用程序, 然后是主题,最后是系统资源。此查找方法是 与请求资源时搜索树的方式相同 标记中的动态资源引用。

遍历逻辑树当然是通过 Parent 属性完成的;这很直观,但在LogicalTreeHelper.GetParent文档中也有明确说明:

此方法只是一个获取适当类型版本的包装器 ( FrameworkElementFrameworkContentElement ) 的 FrameworkElement.ParentFrameworkContentElement.Parent财产;所以 除非无法确定当前类型,否则可能需要 请改为检查相应的实例属性。