Как WPF UserControl может наследовать WPF UserControl?

95

Следующий пользовательский элемент управления WPF называется DataTypeWholeNumber, который работает.

Теперь я хочу создать UserControl под названием DataTypeDateTime и DataTypeEmail и т.д.

Многие из свойств зависимостей будут совместно использоваться всеми этими элементами управления, и поэтому я хочу поместить их общие методы в BaseDataType и сделать так, чтобы каждый из этих элементов управления UserControl унаследовал от этого базового типа.

Однако когда я это делаю, я получаю сообщение об ошибке: частичное объявление может не иметь разных базовых классов .

Итак, как я могу реализовать наследование с помощью UserControls, чтобы все общие функции были в базовом классе?

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



    }
}
Эдвард Тангуай
источник
для обходного пути WPF с визуальным наследованием см .: svetoslavsavov.blogspot.gr/2009/09/… или для явного определения графического интерфейса в предке см. support.microsoft.com/kb/957231
Джордж Бирбилис

Ответы:

132

Убедитесь, что вы изменили первый тег в xaml, чтобы он также унаследовал от вашего нового базового типа.

Так

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

становится

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

Итак, чтобы резюмировать полный ответ, включая дополнительные детали из комментариев ниже:

  • Базовый класс не должен включать файл xaml. Определите его в одном (неполном) файле CS и определите, чтобы он наследовал непосредственно от Usercontrol.
  • Убедитесь, что подкласс наследуется от базового класса как в файле кода программной части cs, так и в первом теге xaml (как показано выше).
Мартин Харрис
источник
4
когда я делаю это изменение, я получаю сообщение об ошибке: «... DataTypes.BaseDataType не может быть корнем файла XAML, потому что он был определен с использованием XAML». Как выйти из этой циклической ссылки?
Эдвард Тангуай
9
Если вы можете просто сделать базовый класс обычным типом, наследуемым от UserControl, без определения какого-либо xmal (то есть не разделение частичного класса на два файла). Проблема в том, что вы не можете унаследовать xmal, поэтому у базового или дочернего класса не должно быть файла xmal. Либо так, либо сделайте свои классы настраиваемыми элементами управления вместо пользовательских элементов управления. Таким образом, внешний вид определяется за пределами частичного класса, но вы потеряете простоту использования пользовательского элемента управления.
Мартин Харрис,
1
Вот и все: если вы сделаете BaseDataType обычным классом, наследующим UserControl, то он заработает. Отлично, спасибо.
Эдвард Тангуай,
@Martin, возможно, вы захотите обновить свой ответ, чтобы отразить ваш комментарий, и это настоящий ответ.
Брайан Андерсон,
Есть ли способ сделать так, чтобы элементы «контрольной базы» находились поверх элементов наследуемого класса?
Хуан М. Элосеги, 01
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

Я нашел ответ в этой статье: http://www.paulstovell.com/xmlnsdefinition

По сути, говорится, что вы должны определить пространство имен XML в файле AssemlyInfo.cs, которое можно использовать в XAML. У меня это сработало, однако я поместил базовый класс пользовательского элемента управления в отдельную DLL ...

колено
источник
0

Я столкнулся с той же проблемой, но мне нужно было наследовать элемент управления от абстрактного класса, который не поддерживается дизайнером. Что решило мою проблему, так это то, что пользовательский элемент управления унаследован как от стандартного класса (наследующего UserControl), так и от интерфейса. Так работает дизайнер.

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

Существует определение частичного класса, созданное дизайнером, вы можете легко открыть его через определение метода InitializeComponent (). Затем просто измените частичное наследование класса с UserControl на BaseDataType (или любое другое, указанное в определении класса).

После этого вы получите предупреждение о том, что метод InitializeComponent () скрыт в дочернем классе.

Поэтому вы можете сделать CustomControl в качестве базового класса вместо UserControl, чтобы избежать частичного определения в базовом классе (как описано в одном комментарии).

Каха Средний Ор
источник
Невозможно преобразовать Controls.Login в Controls.BaseControl.
Himilou