2009-11-19 19 views
5

Donc, dans l'exemple de code ci-dessous, je crée un UserControl UserControldChild qui est un enfant de la fenêtre principale, Window1.xaml. Pourquoi la méthode FindName() ne parvient pas à trouver le "myButton" dans le code ci-dessous?Pourquoi Window.FindName() ne découvre pas le x: Nom d'un bouton dans un UserControl enfant? AKA comment fonctionnent les NameScopes?

Cela doit avoir à voir avec le WPF XAML NameScopes, mais je n'ai pas encore trouvé une bonne explication sur le fonctionnement de NameScope. Quelqu'un peut-il m'éclairer?

//(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 ci-dessous:

//(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(); 
    } 
    } 
} 

Dans le cas où cela ne soit pas répondu correctement, je l'ai trouvé une alternative à l'utilisation FindName() documentée in the post here.

Répondre

5

Vous avez raison - cela a à voir avec XAML Namescopes.

Ceci est (plutôt mal) documenté dans le Name related APIs section of the XAML Namescopes page.

Fondamentalement, si vous avez un FrameworkElement ou FrameworkContentElement, il définira son propre champ de nom. Si vous appelez FindName() sur un type qui n'a pas de portée de nom, WPF recherche jusqu'à jusqu'à ce qu'il trouve un élément qui définit un nom de domaine, puis effectue une recherche dans cette portée.

Dans votre cas, il s'agit de rechercher le nom de portée de Window (il s'agit d'un objet FrameworkContentElement, qui définit donc sa propre portée). Il recherche uniquement les éléments définis dans cette étendue.

Dans votre cas, le bouton se trouve dans la barre de nom de UserControl, par conséquent, Window.FindName() ne le trouve pas. Il n'y a pas de recherche automatique bas l'arbre dans les étendues de niveau inférieur.

C'est une bonne chose - votre "fenêtre" ne devrait pas savoir ou ne veut rien savoir des détails internes d'un UserControl qu'il utilise. Si vous avez besoin de propriétés dans UserControl, elles doivent être exposées au niveau UserControl. Laissez le contrôle gérer ses propres enfants.

+0

Merci pour la clarification! Il semble que FindName ne soit pas le meilleur outil pour le travail dans cette situation, alias que vous ne pouvez pas facilement rechercher dans la portée. Pouvez-vous imaginer une meilleure méthode pour trouver le nom d'un bouton enfant dans l'arbre visuel autre que ma solution récursive détaillée ici? http://stackoverflow.com/questions/636383/wpf-ways-to-find-controls/1759923#1759923 – CrimsonX