为什么Window.FindName()没有发现x:子UserCStrol中按钮的名称? AKA NameScopes如何运作?

时间:2009-11-19 16:00:44

标签: c# wpf user-controls findname

因此,在下面的示例代码中,我创建了一个UserControl UserControldChild,它是主窗口Window1.xaml的子代。为什么FindName()方法无法在下面的代码中找到“myButton”?

这必须与WPF XAML NameScopes有关,但我还没有找到关于NameScope如何工作的好解释。有人可以开导我吗?

//(xml) Window1.xaml    
<Window x:Class="VisualTreeTestApplication.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:VisualTreeTestApp="clr-namespace:VisualTreeTestApplication"
    Title="Window1" Height="400" Width="400">
    <Grid>
        <VisualTreeTestApp:UserControlChild/>
    </Grid>
</Window>

//(c#) Window1.xaml.cs
namespace VisualTreeTestApplication
{
  /// <summary>
  /// Interaction logic for Window1.xaml
  /// </summary>
  public partial class Window1 : Window
  {
    public Window1()
    {
      InitializeComponent();
      Button btnTest = (Button)Application.Current.MainWindow.FindName("myButton");
      // btnTest is null!
    }
  }
}

下面的UserControl:

//(wpf) UserControlChild.xaml
<UserControl x:Class="VisualTreeTestApplication.UserControlChild"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300">
    <Grid x:Name="myGrid">      
        <Button x:Name="myButton" Margin="20" >Button</Button>
    </Grid>
</UserControl>

//(c#) UserControlChild.xaml.cs (no changes)
namespace VisualTreeTestApplication
{
  /// <summary>
  /// Interaction logic for UserControlChild.xaml
  /// </summary>
  public partial class UserControlChild : UserControl
  {
    public UserControlChild()
    {
      InitializeComponent();
    }
  }
}

如果没有得到正确答案,我找到了使用FindName()记录in the post here的替代方法。

1 个答案:

答案 0 :(得分:5)

你是对的 - 这与XAML Namescopes有关。

Name related APIs section of the XAML Namescopes page中记录了(有点差)。

基本上,如果您有FrameworkElement或FrameworkContentElement,它将定义自己的名称范围。如果在没有名称范围的类型上调用FindName(),WPF会搜索向上它,直到找到定义名称范围的元素,然后在该名称范围内搜索。

在你的情况下,它在Window的名称范围内搜索(它是一个FrameworkContentElement,因此它定义了自己的范围)。它只搜索该范围中定义的元素。

在您的情况下,按钮位于UserControl的名称范围内,因此Window.FindName()找不到它。没有自动搜索向下树到较低级别的范围。

这是一件好事 - 您的“窗口”不应该知道或想知道它正在使用的UserControl的内部细节。如果你需要UserControl中的属性,它们应该在UserControl级别公开 - 让控件管理自己的子级。