¿Cómo puede un UserControl de WPF heredar un UserControl de WPF?

92

El siguiente UserControl de WPF llamado DataTypeWholeNumber que funciona.

Ahora quiero hacer un UserControl llamado DataTypeDateTime y DataTypeEmail , etc.

Muchas de las propiedades de dependencia serán compartidas por todos estos controles y, por lo tanto, quiero poner sus métodos comunes en un BaseDataType y que cada uno de estos UserControls herede de este tipo base.

Sin embargo, cuando hago eso, aparece el error: Es posible que la Declaración Parcial no tenga diferentes clases base .

Entonces, ¿cómo puedo implementar la herencia con UserControls para que la funcionalidad compartida esté en la clase 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
fuente
para conocer la solución alternativa de WPF con herencia visual, consulte: svetoslavsavov.blogspot.gr/2009/09/… o para definir explícitamente la GUI en el antepasado, consulte support.microsoft.com/kb/957231
George Birbilis

Respuestas:

130

Asegúrese de haber cambiado la primera etiqueta en el xaml para heredar también de su nuevo tipo base

Entonces

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

se convierte en

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

Entonces, para resumir la respuesta completa, incluidos los detalles adicionales de los comentarios a continuación:

  • La clase base no debe incluir un archivo xaml. Defínalo en un archivo cs único (no parcial) y defínalo para heredarlo directamente de Usercontrol.
  • Asegúrese de que la subclase herede de la clase base tanto en el archivo de código subyacente cs como en la primera etiqueta del xaml (como se muestra arriba).
Martin Harris
fuente
4
cuando realizo ese cambio, aparece el error: "... DataTypes.BaseDataType no puede ser la raíz de un archivo XAML porque se definió mediante XAML", ¿cómo se sale de esta referencia circular?
Edward Tanguay
9
Si puede hacer que la clase base sea un tipo normal que herede de UserControl sin definir ningún xmal (por lo que no es una clase parcial dividida en dos archivos). El problema es que no puede heredar xmal, por lo que la clase base o secundaria no debe tener un archivo xmal. O eso o hacer que sus clases sean controles personalizados en lugar de controles de usuario. De esa manera, la apariencia se define fuera de la clase parcial, pero perderá la facilidad de uso de un Control de usuario.
Martin Harris
1
Eso es todo: si hace de BaseDataType una clase normal que hereda UserControl, entonces funciona. Excelente, gracias.
Edward Tanguay
@Martin, es posible que desee actualizar su respuesta para reflejar su comentario y es la respuesta real.
Bryan Anderson
¿Hay alguna manera de hacer que los elementos de la "base de control" estén encima de los de la clase que hereda?
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
fuente
1

Encontré la respuesta en este artículo: http://www.paulstovell.com/xmlnsdefinition

Básicamente, lo que dice es que debe definir un espacio de nombres XML en el archivo AssemlyInfo.cs, que puede usarse en el XAML. Funcionó para mí, sin embargo, coloqué la clase de control de usuario base en una DLL separada ...

rodilla-cola
fuente
0

Me encontré con el mismo problema, pero necesitaba que el control heredara de una clase abstracta, que no es compatible con el diseñador. Lo que resolvió mi problema es hacer que el control de usuario herede tanto de una clase estándar (que hereda UserControl) como de una interfaz. De esta forma trabaja el diseñador.

//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.
fuente
0

Hay una definición de clase parcial creada por el diseñador, puede abrirla de manera fácil a través de la definición del método InitializeComponent (). Luego, simplemente cambie la herencia de clase parcial de UserControl a BaseDataType (o cualquiera que haya especificado en la definición de clase).

Después de eso, tendrá una advertencia de que el método InitializeComponent () está oculto en la clase secundaria.

Por lo tanto, puede hacer un CustomControl como clase base en lugar de UserControl para evitar una definición parcial en la clase base (como se describe en un comentario).

Kakha Middle Or
fuente
No se puede convertir de Controls.Login a Controls.BaseControl.
Himilou