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

时间:2013-10-14 14:53:19

标签: c# wpf

背景

我知道使用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();
}

问题

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

1 个答案:

答案 0 :(得分:4)

因为查找资源最多涉及遍历逻辑元素树(查找与祖先关联的资源)或查看当前元素的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属性;所以   除非您无法确定当前类型,否则您可能想要   改为检查相应的实例属性。