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

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

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

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

UserControl如下:

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

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

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

这在XAML Namescopes页面的Name相关API部分中 (有点差)记录。

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

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

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

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