Como um UserControl WPF pode herdar um UserControl WPF?

92

O seguinte UserControl WPF chamado DataTypeWholeNumber que funciona.

Agora eu quero fazer um UserControl chamado DataTypeDateTime e DataTypeEmail , etc.

Muitas das propriedades de dependência serão compartilhadas por todos esses controles e, portanto, quero colocar seus métodos comuns em um BaseDataType e fazer com que cada um desses UserControls herde desse tipo base.

No entanto, quando faço isso, recebo o erro: Declaração parcial não pode ter classes base diferentes .

Então, como posso implementar herança com UserControls para que a funcionalidade compartilhada esteja toda na classe 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
fonte
para contornar o WPF com herança visual, consulte: svetoslavsavov.blogspot.gr/2009/09/… ou para definir explicitamente a GUI no ancestral, consulte support.microsoft.com/kb/957231
George Birbilis

Respostas:

130

Certifique-se de ter alterado a primeira tag no xaml para herdar também de seu novo tipo de base

assim

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

torna-se

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

Portanto, para resumir a resposta completa, incluindo os detalhes extras dos comentários abaixo:

  • A classe base não deve incluir um arquivo xaml. Defina-o em um único arquivo cs (não parcial) e defina-o para herdar diretamente do Usercontrol.
  • Certifique-se de que a subclasse herda da classe base tanto no arquivo code-behind cs quanto na primeira tag do xaml (conforme mostrado acima).
Martin Harris
fonte
4
quando faço essa alteração, recebo o erro: "... DataTypes.BaseDataType não pode ser a raiz de um arquivo XAML porque foi definido usando XAML", como você sai dessa referência circular?
Edward Tanguay
9
Se você puder apenas tornar a classe base um tipo normal que herda de UserControl sem definir nenhum xmal (portanto, não uma classe parcial dividida em dois arquivos). O problema é que você não pode herdar xmal, então a classe base ou filha não precisa ter um arquivo xmal. Faça isso ou torne suas classes controles personalizados em vez de controles de usuário. Dessa forma, a aparência é definida fora da classe parcial, mas você perderá a facilidade de uso de um controle de usuário.
Martin Harris
1
É isso: se você tornar BaseDataType uma classe normal que herda UserControl, ele funcionará. Excelente, obrigado.
Edward Tanguay
@Martin, você pode querer atualizar sua resposta para refletir seu comentário e é a resposta real.
Bryan Anderson
Existe uma maneira de fazer com que os elementos da "base de controle" fiquem acima dos da classe que herda?
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
fonte
1

Encontrei a resposta neste artigo: http://www.paulstovell.com/xmlnsdefinition

Basicamente, o que se diz é que você deve definir um namespace XML no arquivo AssemlyInfo.cs, que pode ser usado no XAML. Funcionou para mim, no entanto, coloquei a classe de controle de usuário base em uma DLL separada ...

joelho-cola
fonte
0

Eu tive o mesmo problema, mas precisava que o controle fosse herdado de uma classe abstrata, o que não é suportado pelo designer. O que resolveu meu problema é fazer o usercontrol herdar tanto de uma classe padrão (que herda UserControl) quanto de uma interface. Assim o designer está trabalhando.

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

Existe uma definição de classe parcial criada pelo designer, você pode abri-la facilmente através da definição do método InitializeComponent (). Em seguida, basta alterar a herança de classe parcial de UserControl para BaseDataType (ou qualquer outro especificado na definição de classe).

Depois disso, você receberá um aviso de que o método InitializeComponent () está oculto na classe filha.

Portanto, você pode fazer um CustomControl como classes base em vez de UserControl para evitar a definição parcial na classe base (conforme descrito em um comentário).

Kakha Médio Ou
fonte
Não é possível converter de Controls.Login em Controls.BaseControl.
Himilou