Wie kann ein WPF UserControl ein WPF UserControl erben?


92

Das folgende WPF UserControl heißt DataTypeWholeNumber und funktioniert.

Jetzt möchte ich ein UserControl mit den Namen DataTypeDateTime und DataTypeEmail usw. erstellen .

Viele der Abhängigkeitseigenschaften werden von all diesen Steuerelementen gemeinsam genutzt. Daher möchte ich ihre allgemeinen Methoden in einen BaseDataType einfügen und jedes dieser UserControls von diesem Basistyp erben lassen.

Wenn ich das mache, erhalte ich jedoch die Fehlermeldung: Teildeklaration hat möglicherweise keine unterschiedlichen Basisklassen .

Wie kann ich die Vererbung mit UserControls implementieren, sodass alle gemeinsam genutzten Funktionen in der Basisklasse enthalten sind?

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



    }
}

Informationen zur WPF-Problemumgehung mit visueller Vererbung finden Sie unter: svetoslavsavov.blogspot.gr/2009/09/… oder zur expliziten Definition der GUI im Vorfahren unter support.microsoft.com/kb/957231
George Birbilis

Antworten:


130

Stellen Sie sicher, dass Sie das erste Tag in der xaml so geändert haben, dass es auch von Ihrem neuen Basistyp erbt

So

<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"
    >

wird

<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"
    >

Um die vollständige Antwort einschließlich der zusätzlichen Details aus den Kommentaren unten zusammenzufassen:

  • Die Basisklasse sollte keine xaml-Datei enthalten. Definieren Sie es in einer einzelnen (nicht partiellen) cs-Datei und definieren Sie es so, dass es direkt von Usercontrol erbt.
  • Stellen Sie sicher, dass die Unterklasse sowohl in der cs-CodeBehind-Datei als auch im ersten Tag der xaml (wie oben gezeigt) von der Basisklasse erbt.

4
Wenn ich diese Änderung vornehme, wird folgende Fehlermeldung angezeigt: "... DataTypes.BaseDataType kann nicht das Stammverzeichnis einer XAML-Datei sein, da sie mit XAML definiert wurde." Wie kommen Sie aus diesem Zirkelverweis heraus?
Edward Tanguay

9
Wenn Sie die Basisklasse nur zu einem normalen Typ machen können, der von UserControl erbt, ohne xmal zu definieren (also keine Teilklasse, die auf zwei Dateien aufgeteilt ist). Das Problem ist, dass Sie xmal nicht erben können, sodass entweder die Basis- oder die untergeordnete Klasse keine xmal-Datei haben muss. Entweder das oder Sie machen Ihre Klassen zu benutzerdefinierten Steuerelementen anstelle von Benutzersteuerelementen. Auf diese Weise wird das Erscheinungsbild außerhalb der Teilklasse definiert, Sie verlieren jedoch die Benutzerfreundlichkeit eines Benutzersteuerelements.
Martin Harris

1
Das war's: Wenn Sie BaseDataType zu einer normalen Klasse machen, die UserControl erbt, funktioniert es. Großartig, danke.
Edward Tanguay

@Martin Vielleicht möchten Sie Ihre Antwort aktualisieren, um Ihren Kommentar wiederzugeben, und es ist die wahre Antwort.
Bryan Anderson

Gibt es eine Möglichkeit, die Elemente aus der "Kontrollbasis" über die Elemente der Klasse zu stellen, die erbt?
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>    

1

Ich habe die Antwort in diesem Artikel gefunden: http://www.paulstovell.com/xmlnsdefinition

Grundsätzlich heißt es, dass Sie in der Datei AssemlyInfo.cs einen XML-Namespace definieren sollten, der in der XAML verwendet werden kann. Es hat bei mir funktioniert, aber ich habe die Basis-Benutzersteuerungsklasse in einer separaten DLL platziert ...


0

Ich bin auf dasselbe Problem gestoßen, musste aber das Steuerelement von einer abstrakten Klasse erben lassen, die vom Designer nicht unterstützt wird. Was mein Problem gelöst hat, ist, dass die Benutzersteuerung sowohl von einer Standardklasse (die UserControl erbt) als auch von einer Schnittstelle erbt. Auf diese Weise arbeitet der Designer.

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

0

Es gibt eine teilweise Klassendefinition, die vom Designer erstellt wurde. Sie können sie einfach über die Methodendefinition InitializeComponent () öffnen. Ändern Sie dann einfach die teilweise Klassenvererbung von UserControl in BaseDataType (oder eine in der Klassendefinition angegebene).

Danach erhalten Sie eine Warnung, dass die InitializeComponent () -Methode in der untergeordneten Klasse ausgeblendet ist.

Daher können Sie ein CustomControl als Basisklasse anstelle von UserControl erstellen, um eine teilweise Definition in der Basisklasse zu vermeiden (wie in einem Kommentar beschrieben).


Konvertierung von Controls.Login in Controls.BaseControl nicht möglich.
Himilou
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.