Почему Window.FindName() не обнаруживает x: Имя кнопки в дочернем UserControl? АКА, как работают NameScopes?
Поэтому в приведенном ниже примере кода я создаю 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(), описанную в посте здесь.
1 ответ
Вы правы - это связано с именными областями XAML.
Это (несколько плохо) задокументировано в разделе " API-интерфейсы, связанные с именами" на странице Namescopes XAML.
По сути, если у вас есть FrameworkElement или FrameworkContentElement, он будет определять свою собственную область имен. Если вы вызываете FindName() для типа, который не имеет области имен, WPF выполняет поиск до тех пор, пока не найдет элемент, который определяет область имен, а затем выполняет поиск в этой области имен.
В вашем случае это поиск в области имен Window (это FrameworkContentElement, поэтому он определяет свою собственную область). Он просто ищет элементы, определенные в этой области.
В вашем случае кнопка находится в области имен UserControl, поэтому Window.FindName() не находит ее. Там нет автоматического поиска вниз по дереву в области более низкого уровня.
Это хорошо - ваше "Окно" не должно знать или хотеть знать о внутренних деталях UserControl, который он использует. Если вам нужны свойства внутри UserControl, они должны быть доступны на уровне UserControl - пусть элемент управления управляет своими дочерними элементами.