情况:

我有一个像这样的“包装面板”UserControl(为简洁起见,删除了命名空间和视觉细节):

<UserControl ...>
<Grid x:Name="LayoutRoot" Background="White">
    <ContentPresenter x:Name="integratedPanelContent" Margin="5" />
</Grid>
</UserControl>

然后在代码隐藏中我注册了一个依赖属性
public FrameworkElement PanelContent
{
    get { return (FrameworkElement)GetValue(PanelContentProperty); }
    set { SetValue(PanelContentProperty, value); }
}
public static readonly DependencyProperty PanelContentProperty =
    DependencyProperty.Register("PanelContent", typeof(FrameworkElement), typeof(MyWrapperPanel),
      new PropertyMetadata(null, OnPanelContentChanged));

private static void OnPanelContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    ((MyWrapperPanel)d).OnSetContentChanged(e);
}

protected virtual void OnSetContentChanged(DependencyPropertyChangedEventArgs e)
{
    if (PanelContent != null)
        integratedPanelContent.Content = PanelContent;
}

现在我可以将任何内容包装到我的控件中:
<my:MyWrapperPanel x:Name="myWrap">
    <my:MyWrapperPanel.PanelContent>
        <TextBlock x:Name="tbxNothing" Text="Nothing" />
    </my:MyWrapperPanel.PanelContent>
</my:MyWrapperPanel>

问题描述:

每当我尝试在代码隐藏中使用引用 tbxNothing 时,系统都会抛出 NullReferenceException ,因为 tbxNothing 虽然作为引用存在,但并不指向 XAML 中定义的 TextBlock,而是 null

可能(但不方便)的解决方法:

有一种解决方法,我从 TextBlock 中删除 x:Name,然后我明确定义名为 tbxNothing 的私有(private) TextBlock。然后在 OnNavigatedTo 事件处理程序中,我按以下方式分配值:
tbxNothing = myWrap.PanelContent as TextBlock;

这有效但不是正确的方法,因为如果内容是包含所需控件的堆栈面板,我将不得不遍历树以找到我需要的内容,这非常不方便。

问题:

为什么文本块在包装在用户控件中时不再可见(描述的方式),以及如何在代码隐藏中通过其 x:Name 获取它?

最佳答案

问题是您的面板内容落在两个凳子之间。一方面,名称为“tbxNothing”的内容是在主页的名称范围中创建的。但是,此时它没有添加到对象树中。另一方面,作为 UserControl 的 MyWrapperPanel 有它自己的名称范围,并且它在下面的对象树中添加了名称为“tbxNothing”的项目。主页上的 FindName 在 MyWrapperPanel 中找不到任何内容,因为它有自己的名称范围,而 MyWrapperPanel 上的 FindName 找不到“tbxNothing”,因为它在其名称范围中不存在(实际上是在主页中创建的)。

答案是不要使用 UserControl 作为 MyWrapperPanel 的基础。而是创建一个 Silverlight 模板控件。将它继承的基类修改为 ContentControl 并调整其默认模板以包含 ContentPresenter 。应该看起来像这样:-

public class MyWrapperPanel : ContentControl
{
    public MyWrapperPanel ()
    {
        this.DefaultStyleKey = typeof(MyWrapperPanel );
    }
}

然后在 themes/generic.xaml 中,样式看起来像这样:-
<Style TargetType="local:MyWrapperPanel">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:MyWrapperPanel">
                <Grid>
                    <ContentPresenter />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

您的主页 xaml 将如下所示:-
<my:MyWrapperPanel x:Name="myWrap">
    <TextBlock x:Name="tbxNothing" Text="Nothing" />
</my:MyWrapperPanel>

请注意,从 ContentControl 派生为您提供 Content 属性,ContentPresenter 会自动连接到该属性。

关于silverlight - x :Name not working if element wrapped in UserControl's content (Silverlight),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/6355217/

10-10 13:08