Rendre accessible un contrôle enfant en XAML

Lorsque l’on crée un UserControl en XAML (UWP ou WPF) il est parfois intéressant de laisser le développeur prendre la main sur les contrôle internes.

Dans l’exemple suivant le UserControl comporte un bouton.

<UserControl>
    <Grid>
        <Button x:Name="Button1"></Button>
    </Grid>
</UserControl>

Ce UserControl est ensuite instancié dans une page XAML :

<Page>
<local:ControlUtilisateur x:Name="ControlUtilisateur"/>
</Page>

On peut donc s’attendre à ce que le développeur de la page puisse appeler en C# le bouton Button1 à partir du UserControl de la manière suivante :

this.ControlUtilisateur.Button1.Content = "Hello";

Mais il n’en est rien.

En effet lorsque l’on crée un nouveau contrôle dans la page XAML à partir de l’éditeur et que celui-ci est nommé (x:Name=”Button1″), Visual Studio va générer automatiquement du code C# correspondant à ce bouton. Ce code généré est un raccourci qui nous évite de déclarer nos propres variables pour pouvoir accéder aux éléments XAML, ce qui est plutôt pratique.

/*exemple du code qu'il nous faudrait écrire (merci VS)*/
private Button Button1 = this.FindName("Button1") as Button;

Mais voila, le bouton “Button1” est généré en private par défaut. Il n’est donc pas accessible au delà de son parent, le UserControl “ControlUtilisateur”. Dans la plupart des cas, c’est le comportement attendu. Si l’on a besoin d’accéder à une propriété du Bouton, à partir du UserControl, on aura tendance à créer une propriété wrappant la propriété du bouton. Par exemple une propriété ButtonStyle dans le UserControl qui sera affectée à la propriété Style du bouton.

Mais parfois il peut arriver que l’accès complet au contrôle interne (Button1) soit nécessaire. Dans ce cas il existe deux solutions :

  • Créer une propriété de type Button nommée “Button1Bis” dans le contrôle et renvoyer l’instance de “Button1”. On doit avoir deux noms pour désigner le même contrôle :/
  • Ajouter une balise dans XAML permettant de changer l’accessibilité de l’objet “Button1” généré dans VisualStudio.

<UserControl x:Class="Blog.ControlUtilisateur">
    <Grid>
        <Button x:Name="Button1" x:FieldModifier="public"></Button>
    </Grid>
</UserControl>

Dans cette dernière solution “Button1” sera déclaré comme public et l’on pourra y accéder directement à partir de “ControlUtilisateur” mais seulement à partir du code behind C# (et pas de XAML).

Tous les modificateurs d’accès sont présents : public, protected, internal, private (par défaut) ce qui permet de définir un niveau d’accessibilité de votre contrôle enfant relatif au besoin des contrôles parents. Il semble intéressant par exemple d’éviter le modificateur public au profit d’internal/protected afin que le monde entier ne puisse pas accéder aux controles internes de vos UserControls.

Leave a Reply

Your email address will not be published. Required fields are marked *