为什么 Window.FindName() 没有发现子 UserControl 中按钮的 x:Name?又名名称范围如何工作?
因此,在下面的示例代码中,我创建了一个 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() 记录的替代方法 在此处的帖子。
So in the example code below, I create a UserControl UserControldChild which is a child of the main Window, Window1.xaml. Why does the FindName()
method fail to find the "myButton" in the code below?
This must have to do with the WPF XAML NameScopes, but I have yet to find a good explanation as to how NameScope works. Can someone enlighten me?
//(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 below:
//(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();
}
}
}
In case this doesn't get answered properly, I found an alternative to using FindName() documented in the post here.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您是对的 - 这与 XAML 名称范围有关。
这在 XAML 名称范围的 与名称相关的 API 部分中进行了记录(有点糟糕)页面。
基本上,如果您有 FrameworkElement 或 FrameworkContentElement,它将定义自己的名称范围。如果您对没有名称范围的类型调用 FindName(),WPF 将向上搜索,直到找到定义名称范围的元素,然后在该名称范围内进行搜索。
在您的情况下,它在 Window 的名称范围中搜索(它是一个 FrameworkContentElement,因此它定义了自己的范围)。它只搜索该范围内定义的元素。
不过,就您而言,该按钮位于 UserControl 的名称范围内,因此 Window.FindName() 找不到它。不会自动在树中向下搜索到较低级别的范围。
这是一件好事 - 您的“窗口”不应该知道或不想知道有关它正在使用的 UserControl 的内部细节的任何信息。如果您需要 UserControl 中的属性,则应在 UserControl 级别公开它们 - 让控件管理其自己的子级。
You are correct - this has to do with XAML Namescopes.
This is (somewhat poorly) documented in the Name related APIs section of the XAML Namescopes page.
Basically, if you have a FrameworkElement or FrameworkContentElement, it will define its own name scope. If you call FindName() on a type that doesn't have a namescope, WPF searches up thet ree until it finds an element that does define a namescope, then searches within that namescope.
In your case, it's searching at Window's namescope (it's a FrameworkContentElement, so it defines its own scope). It just searches elements defined in that scope.
In your case, the button is in the UserControl's namescope, though, so Window.FindName() doesn't find it. There is no automatically searching down the tree into lower level scopes.
This is a good thing - your "Window" shouldn't know or want to know anything about internal details of a UserControl it's using. If you need properties within the UserControl, they should be exposed at the UserControl level - let the control manage its own children.