Comment un UserControl WPF peut-il hériter d'un UserControl WPF?

92

Le WPF UserControl suivant appelé DataTypeWholeNumber qui fonctionne.

Maintenant, je veux créer un UserControl appelé DataTypeDateTime et DataTypeEmail , etc.

De nombreuses propriétés de dépendance seront partagées par tous ces contrôles et je souhaite donc placer leurs méthodes communes dans un BaseDataType et que chacun de ces UserControls hérite de ce type de base.

Cependant, lorsque je fais cela, j'obtiens l' erreur: la déclaration partielle peut ne pas avoir différentes classes de base .

Alors, comment puis-je implémenter l'héritage avec UserControls pour que les fonctionnalités partagées soient toutes dans la classe de base?

using System.Windows;
using System.Windows.Controls;

namespace TestDependencyProperty827.DataTypes
{
    public partial class DataTypeWholeNumber : BaseDataType
    {
        public DataTypeWholeNumber()
        {
            InitializeComponent();
            DataContext = this;

            //defaults
            TheWidth = 200;
        }

        public string TheLabel
        {
            get
            {
                return (string)GetValue(TheLabelProperty);
            }
            set
            {
                SetValue(TheLabelProperty, value);
            }
        }

        public static readonly DependencyProperty TheLabelProperty =
            DependencyProperty.Register("TheLabel", typeof(string), typeof(BaseDataType),
            new FrameworkPropertyMetadata());


        public string TheContent
        {
            get
            {
                return (string)GetValue(TheContentProperty);
            }
            set
            {
                SetValue(TheContentProperty, value);
            }
        }

        public static readonly DependencyProperty TheContentProperty =
            DependencyProperty.Register("TheContent", typeof(string), typeof(BaseDataType),
            new FrameworkPropertyMetadata());


        public int TheWidth
        {
            get
            {
                return (int)GetValue(TheWidthProperty);
            }
            set
            {
                SetValue(TheWidthProperty, value);
            }
        }

        public static readonly DependencyProperty TheWidthProperty =
            DependencyProperty.Register("TheWidth", typeof(int), typeof(DataTypeWholeNumber),
            new FrameworkPropertyMetadata());



    }
}
Edward Tanguay
la source
pour la solution de contournement WPF avec l'héritage visuel, voir: svetoslavsavov.blogspot.gr/2009/09/… ou pour définir explicitement l'interface graphique dans l'ancêtre, voir support.microsoft.com/kb/957231
George Birbilis

Réponses:

130

Assurez-vous que vous avez changé la première balise dans le xaml pour hériter également de votre nouveau type de base

Alors

<UserControl x:Class="TestDependencyProperty827.DataTypes.DataTypeWholeNumber"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
    xmlns:s="clr-namespace:System;assembly=mscorlib"
    >

devient

<myTypes:BaseDataType x:Class="TestDependencyProperty827.DataTypes.DataTypeWholeNumber"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
    xmlns:s="clr-namespace:System;assembly=mscorlib"
    xmlns:myTypes="clr-namespace:TestDependencyProperty827.DataTypes"
    >

Donc, pour résumer la réponse complète, y compris les détails supplémentaires des commentaires ci-dessous:

  • La classe de base ne doit pas inclure de fichier xaml. Définissez-le dans un fichier cs unique (non partiel) et définissez-le pour hériter directement d'Usercontrol.
  • Assurez-vous que la sous-classe hérite de la classe de base à la fois dans le fichier code-behind cs et dans la première balise du xaml (comme indiqué ci-dessus).
Martin Harris
la source
4
lorsque j'apporte cette modification, j'obtiens l'erreur: "... DataTypes.BaseDataType ne peut pas être la racine d'un fichier XAML car il a été défini à l'aide de XAML", comment pouvez-vous sortir de cette référence circulaire?
Edward Tanguay
9
Si vous pouvez simplement faire de la classe de base un type normal qui hérite de UserControl sans définir de xmal (donc pas une classe partielle divisée sur deux fichiers). Le problème est que vous ne pouvez pas hériter de xmal, donc la classe de base ou la classe enfant ne doivent pas avoir de fichier xmal. Soit cela, soit faites de vos classes des contrôles personnalisés au lieu de contrôles utilisateur. De cette façon, l'apparence est définie en dehors de la classe partielle, mais vous perdrez la facilité d'utilisation d'un contrôle utilisateur.
Martin Harris
1
Voilà: si vous faites de BaseDataType une classe normale qui hérite de UserControl, cela fonctionne. Excellent, merci.
Edward Tanguay
@Martin vous voudrez peut-être mettre à jour votre réponse pour refléter votre commentaire et c'est la vraie réponse.
Bryan Anderson
Existe-t-il un moyen de faire en sorte que les éléments de la "base de contrôle" soient au-dessus de ceux de la classe qui hérite?
Juan M. Elosegui
2
public partial class MooringConfigurator : MooringLineConfigurator
    {
        public MooringConfigurator()
        {
            InitializeComponent();
        }
    }



<dst:MooringLineConfigurator x:Class="Wave.Dashboards.Instruments.ConfiguratorViews.DST.MooringConfigurator"
    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:dst="clr-namespace:Wave.Dashboards.Instruments.ConfiguratorViews.DST"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">

    </Grid>
</dst:MooringLineConfigurator>    
Pitka
la source
1

J'ai trouvé la réponse dans cet article: http://www.paulstovell.com/xmlnsdefinition

En gros, ce qui est dit, c'est que vous devez définir un espace de noms XML dans le fichier AssemlyInfo.cs, qui peut être utilisé dans le XAML. Cela a fonctionné pour moi, mais j'ai placé la classe de contrôle utilisateur de base dans une DLL distincte ...

genou-cola
la source
0

J'ai rencontré le même problème, mais j'avais besoin que le contrôle hérite d'une classe abstraite, qui n'est pas prise en charge par le concepteur. Ce qui a résolu mon problème est de faire en sorte que le contrôle utilisateur hérite à la fois d'une classe standard (qui hérite de UserControl) et d'une interface. De cette façon, le concepteur travaille.

//the xaml
<local:EcranFiche x:Class="VLEva.SIFEval.Ecrans.UC_BatimentAgricole" 
                  xmlns:local="clr-namespace:VLEva.SIFEval.Ecrans"
                  ...>
    ...
</local:EcranFiche>

// the usercontrol code behind
public partial class UC_BatimentAgricole : EcranFiche, IEcranFiche
{
    ...
}

// the interface
public interface IEcranFiche
{
   ...
}

// base class containing common implemented methods
public class EcranFiche : UserControl
{
    ... (ex: common interface implementation)
}
Sam L.
la source
0

Il existe une définition de classe partielle créée par le concepteur, vous pouvez l'ouvrir facilement via la définition de méthode InitializeComponent (). Ensuite, changez simplement l'héritage de classe partiel de UserControl en BaseDataType (ou tout autre que vous avez spécifié dans la définition de classe).

Après cela, vous aurez un avertissement que la méthode InitializeComponent () est masquée dans la classe enfant.

Par conséquent, vous pouvez créer un CustomControl comme classe de base au lieu de UserControl pour éviter une définition partielle dans la classe de base (comme décrit dans un commentaire).

Kakha moyen ou
la source
Impossible de convertir de Controls.Login en Controls.BaseControl.
Himilou