108 votes

Comment créer un WPF UserControl avec NOMMÉE contenu

J'ai un ensemble de commandes avec joints des commandes et de la logique, qui sont constamment réutilisés dans le même sens. J'ai décidé de créer un contrôle utilisateur qui est titulaire de tous les contrôles communs et de la logique.

Cependant j'ai aussi besoin de contrôle pour être en mesure de présenter un contenu qui peut être nommé. J'ai essayé le suivant:

<UserControl.ContentTemplate>
    <DataTemplate>
        <Button>a reused button</Button>
        <ContentPresenter Content="{TemplateBinding Content}"/>
        <Button>a reused button</Button>
    </DataTemplate>
</UserControl.ContentTemplate>

Cependant, il semble tout contenu placé à l'intérieur du contrôle de l'utilisateur ne peut pas être nommé. Par exemple si j'utilise le contrôle de la façon suivante:

<lib:UserControl1>
     <Button Name="buttonName">content</Button>
</lib:UserControl1>

Je reçois l'erreur suivante:

Impossible de définir le Nom de la valeur de l'attribut 'buttonName' sur l'élément "Bouton". "Bouton" est dans le champ d'application de l'élément 'UserControl1', qui avait déjà une dénomination enregistrée lorsqu'il a été défini en un autre champ d'application.

Si je supprime le buttonName, puis il compile, cependant j'ai besoin d'être en mesure de nommer le contenu. Comment puis-je y parvenir?

52voto

Gumpifoo Points 79

La réponse est de ne pas utiliser un UserControl pour le faire.

Créer une classe qui étend la classe ContentControl

public class MyFunkyControl : ContentControl
{
    public static readonly DependencyProperty HeadingProperty =
        DependencyProperty.Register("Heading", typeof(string),
        typeof(HeadingContainer), new PropertyMetadata(HeadingChanged));

    private static void HeadingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((HeadingContainer) d).Heading = e.NewValue as string;
    }

    public string Heading { get; set; }
}

ensuite, utilisez un style pour spécifier le contenu

<Style TargetType="control:MyFunkyControl">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="control:MyFunkyContainer">
                <Grid>
                    <ContentControl Content="{TemplateBinding Content}"/>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

et enfin l'utiliser

<control:MyFunkyControl Heading="Some heading!">            
    <Label Name="WithAName">Some cool content</Label>
</control:MyFunkyControl>

22voto

Ryan Points 415

Il semble que ce n'est pas possible lorsque le XAML est utilisé. Contrôles personnalisés semblent être exagéré quand j'ai fait tous les contrôles dont j'ai besoin, mais juste besoin de les regrouper avec un petit peu de logique et de permettre nommé le contenu.

La solution sur JD blog comme mackenir suggère, semble être le meilleur compromis. Une manière de prolonger le JD est la solution pour permettre des contrôles aux encore être définis dans le code XAML pourrait être comme suit:

    protected override void OnInitialized(EventArgs e)
    {
        base.OnInitialized(e);

        var grid = new Grid();
        var content = new ContentPresenter
                          {
                              Content = Content
                          };

        var userControl = new UserControlDefinedInXAML();
        userControl.aStackPanel.Children.Add(content);

        grid.Children.Add(userControl);
        Content = grid;           
    }

Dans mon exemple ci-dessus, j'ai créé un utilisateur contrôle appelé UserControlDefinedInXAML qui se définissent comme n'importe quel utilisateur normal des contrôles de l'utilisation de XAML. Dans mon UserControlDefinedInXAML j'ai un StackPanel appelé aStackPanel au sein de laquelle je veux que mon nom contenu à apparaître.

3voto

Rachel Points 49408

Une autre solution, que j'ai utilisé est de définir l' Name propriété dans l' Loaded événement.

Dans mon cas, j'ai eu une assez complexe de contrôle qui je ne voulais pas créer dans le code-behind, et il avait l'air d'un contrôle facultatif avec un nom spécifique pour certains comportement, et depuis j'ai remarqué que je pouvais définir le nom dans un DataTemplate j'ai pensé que je pourrais le faire dans l' Loaded événement.

private void Button_Loaded(object sender, RoutedEventArgs e)
{
    Button b = sender as Button;
    b.Name = "buttonName";
}

3voto

Dani Points 567

Parfois, vous pourriez juste besoin de faire référence à l'élément de C#. Selon le cas d'utilisation, vous pouvez ensuite définir une x:Uid au lieu d'un x:Name d'accès et les éléments en appelant un Uid méthode de recherche comme Obtenir de l'objet par son Uid dans WPF.

0voto

aliceraunsbaek Points 96

J'ai choisi de créer un supplément de propriété pour chaque élément, j'ai besoin d'obtenir:

    public FrameworkElement First
    {
        get
        {
            if (Controls.Count > 0)
            {
                return Controls[0];
            }
            return null;
        }
    }

Cela me permet d'accéder à l'enfant des éléments dans le code XAML:

<TextBlock Text="{Binding First.SelectedItem, ElementName=Taxcode}"/>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X