XAML UserControl héritage

venant de Java, je suis vraiment habitué à une pratique courante quand il s'agit de faire des composants GUI: je fais habituellement une sorte de classe de base qui contient tous les objets communs pour mes composants GUI et puis je l'étend.

donc, en gros, c'est ce que j'aimerais réaliser avec C# et XAML.

pour clarifier la question, voici un exemple (qui ne fonctionne pas!) de ce que je suis en train de faire:

nous avons une classe de base avec son propre XAML

<UserControl x:Class="BaseClass"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    d:DesignHeight="480" d:DesignWidth="480">

    <Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">
        <Border BorderBrush="Aqua" BorderThickness="10" CornerRadius="10" x:Name="Border" HorizontalAlignment="Left" Height="480" VerticalAlignment="Top" Width="480"/>

    </Grid>
</UserControl>

et puis nous avons une classe qui étend la première

<base:BaseClass x:Class="DerivedClass"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:base="clr-namespace:BaseClass"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    d:DesignHeight="60" d:DesignWidth="200">

    <Grid x:Name="LayoutRoot" Margin="0" Width="200" Height="60" MaxWidth="200" MaxHeight="60" Background="{StaticResource PhoneAccentBrush}">        
        <TextBlock x:Name="dummyText" HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" Text="Dummy Plugin" VerticalAlignment="Top" Height="40" Width="180" Foreground="White" TextAlignment="Center"/>
    </Grid>
</base:BaseClass>

à partir des 2 codes XAML, ce que j'aimerais faire, c'est avoir le DerivedClass dans le conteneur BaseClass . Cela me permettra de partager des composants entre les différentes classes dérivées sans avoir à écrire le code chaque fois que j'en ai besoin.

par exemple, si je veux que tous mes composants soient arrondis frontière, j'aimerais juste le mettre dans la basse classe, puis l'ont dans tous les dérivés sans avoir à le réécrire.

bien sûr, chaque Classe c a sa propre méthode InitializeComponent() et cela signifie probablement que le composant dérivé va construire son propre contenu en supprimant la classe de base' one.

enlever la méthode du constructeur DerivedClass me donne le contenu de base même dans la classe dérivée, mais, bien sûr, je perds tout ce que j'ai fait dans la fenêtre de conception XAML du DerivedClass .

appeler le constructeur de base du DerivedClass n'a aucun effet, comme il est appelé avant le InitializeComponent() dérivé .

ainsi la question Est: Comment puis-je utiliser le modèle XAML à partir d'une classe de base dans la dérivée sans briser le modèle XAML de la classe dérivée? Est-il possible de simplement ajouter du contenu à la classe de base alors que le concepteur lui-même?

(Je sais que je peux supprimer le XAML pour la classe dérivée et faire ce que je veux faire par code, mais je veux savoir si je peux le faire juste avec le concepteur que je ne veux pas écrire mon GUI quand j'ai un concepteur disponible)

EDIT:

suite à la réponse de HighCore, j'ai fait quelque chose qui fonctionne sur Windows Phone mais je ne suis pas sûr de faire la bonne chose (oui, ça fonctionne, mais peut-être est juste mal!).

voici ce que j'ai fait:

BaseControl.xaml

<UserControl x:Class="TestInheritance.BaseControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    d:DesignHeight="480" d:DesignWidth="480">


     <Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">        
        <TextBlock HorizontalAlignment="Center">BASE</TextBlock>        
        <ContentPresenter Name="Presenter" Content="{Binding PresenterContent}"/>
    </Grid>
</UserControl>

BaseControl.XAML.cs

namespace TestInheritance
{
    public partial class BaseControl : UserControl
    {

        public Grid PresenterContent { get; set; }        

        public BaseControl()
        {
            DataContext = this;
            InitializeComponent();            
        }
    }
}

DerivedControl.xaml

<local:BaseControl x:Class="TestInheritance.DerivedControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:TestInheritance"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    d:DesignHeight="480" d:DesignWidth="480">

    <local:BaseControl.PresenterContent>
        <Grid>
            <TextBlock VerticalAlignment="Bottom" HorizontalAlignment="Center">DERIVED</TextBlock>
        </Grid>
    </local:BaseControl.PresenterContent>
</local:BaseControl>

veuillez noter que le DerivedClass est une instance de BaseClass car j'ai besoin qu'ils aient des propriétés/méthodes communes pour d'autres raisons.

Que pensez-vous de ma solution? Est-il judicieux?

21
demandé sur StepTNT 2013-08-31 13:10:28

2 réponses

OK, permettez-moi de diviser cela en parties:

en provenance de Java

oubliez java. C'est une langue très ancienne qui n'a pas évolué depuis les années 90. C# est un million de fois mieux et WPF est le meilleur cadre D'assurance-chômage à ce jour.

d'après ce que j'ai vu, les cadres D'interface Java tels que swing sont conceptuellement similaires aux winforms de .Net, qui a également été remplacé par WPF.

WPF (et it's XAML-based brethren) sont fondamentalement différents de tous les autres cadres autour en raison de leur capacité améliorée pour la personnalisation via Styles and Templates et le soutien pour DataBinding .

pour cette raison, un important Mindshift est nécessaire à partir de WPF.


je fais habituellement une sorte de classe de base qui contient tous les objets pour mes composants GUI et ensuite je l'étend.

dans WPF , il y a le Content Model , qui supprime le besoin d'héritage et d'autres pratiques inutiles gonflées, en introduisant la capacité de mettre"n'importe quoi dans n'importe quoi".

par exemple, un Button peut être défini comme ceci:

<Button>
    <Button.Content>
        <StackPanel Orientation="Horizontal">
            <Ellipse Fill="Red" Height="10" Width="10" Margin="2"/>
            <TextBlock Text="Click Me"/>
        </StackPanel>
    <Button.Content>
 </Button>

ce qui donne

A button with a red dot

il n'y a pas besoin d'hériter de bouton juste pour définir son contenu.

il y a un avantage supplémentaire que WPF fournit et est vraiment pratique, L'attribut ContentProperty qui définit ce que représente le contenu des étiquettes XAML <Button> </Button> . Button est dérivé de ContentControl , qui est déclaré comme ceci:

//Declaration of the System.Windows.Control.ContentControl class,
//inside the PresentationFramework.dll assembly
//...  
[ContentProperty("Content")]
public class ContentControl: Control //...
{
   //...
}

cela signifie que le XAML suivant est fonctionnellement identique à ce qui précède:

<Button>
   <StackPanel Orientation="Horizontal">
       <Ellipse Fill="Red" Height="10" Width="10" Margin="2"/>
       <TextBlock Text="Click Me"/>
    </StackPanel>
</Button>
  • avis nous avons supprimé l'étiquette <Button.Content> , parce que l'attribut ContentProperty prend soin de cela.

tout cela est rendu possible grâce à une fonctionnalité appelée ControlTemplates , qui définit l'apparence visuelle d'une commande, indépendamment de son comportement.


ce que je voudrais faire est d'avoir la classe dérivée dans la classe de base conteneur.

il y a plusieurs façons d'y parvenir, l'une d'entre elles est de tirer parti de ControlTemplates et de définir un conteneur spécifique à l'intérieur du XAML qui hébergera le contenu:

<UserControl x:Class="BaseClass">
    <UserControl.Template>
        <ControlTemplate TargetType="UserControl">
            <DockPanel>
                <TextBlock DockPanel.Dock="Top" Text="I'm the Container"/>

                <!-- This is where the Hosted Content will be placed -->
                <ContentPresenter ContentSource="Content"/>
            </DockPanel>
        </ControlTemplate>
     </UserControl.Template>
</UserControl>

alors vous pouvez réutiliser ce modèle comme ceci:

<Window>
   <my:BaseClass>
       <Border Background="Gray" BorderBrush="Blue" BorderThickness="2"
               VerticalAlignment="Center" HorizontalAlignment="Center">
           <TextBlock Text="Im the Hosted Content" Foreground="AliceBlue"/>
       </Border>
   </my:BaseClass>
</Window>

qui se traduit par:

An application window

pas besoin d'héritage ni de code de procédure.


"un autre aspect très important à partir de WPF, qui est expliqué en détail dans le lien" changement de mentalité significatif "ci-dessus, est ce que je dis à tout le monde ici:

apprendre MVVM avant d'écrire une seule ligne de code dans WPF


un autre concept qui permet une grande flexibilité quand il s'agit de montrer des données dans L'IU est celui de la WPF. DataTemplates , qui vous permettent de définir une interface utilisateur spécifique à utiliser lorsqu'un Type de données est "rendu" à l'écran.


en raison de tout ce qui précède, WPF est fondamentalement différent de la plupart des cadres D'UI là-bas, et élimine ainsi le besoin de tous les horribles bouilloire et les piratages qui sont communs dans d'autres cadres, " 151917090920"

je vous suggère de lire sur tous les liens fournis et gardez à l'esprit tous ces concepts et pratiques lorsque vous définissez la structure d'une application et L'assurance-chômage en général.

Laissez-moi savoir si vous avez besoin d'aide.

59
répondu Federico Berasategui 2018-02-20 14:28:48

autant que je sache, dériver L'UI telle quelle, n'est pas disponible à moins que pour les ressources XAML (styles pour ex). Peut-être que la raison est que le gestionnaire D'UI ne peut pas deviner où mettre le code XAML étendu:

<UserControl > 
 <Grid>
  <Border/>
 </Grid>
</UserControl>

et L'UI dérivée:

<UserControl> 
 <DockPanel>
  <Button/>
 </DockPanel>
</UserControl>

Quel serait le résultat après le mélange?

un simple réponse pourrait être:

  <UserControl > 
    <Grid>
     <Border/>
    </Grid>
    <DockPanel>
     <Button/>
    </DockPanel>
  </UserControl>

ce qui n'est pas possible.

Qu'en est-il des problèmes d'intégration/compatibilité des contrôles ?

0
répondu HichemSeeSharp 2013-08-31 10:32:47