W jaki sposób WPF UserControl może dziedziczyć WPF UserControl?

95

Następująca kontrola użytkownika WPF o nazwie DataTypeWholeNumber, która działa.

Teraz chcę utworzyć kontrolę użytkownika o nazwie DataTypeDateTime i DataTypeEmail itp.

Wiele właściwości zależności będzie współużytkowanych przez wszystkie te kontrolki, dlatego chcę umieścić ich wspólne metody w BaseDataType i aby każda z tych kontrolek użytkownika dziedziczyła z tego typu podstawowego.

Jednak gdy to robię, pojawia się błąd: Deklaracja częściowa może nie mieć różnych klas bazowych .

Jak więc zaimplementować dziedziczenie za pomocą UserControls, aby wspólna funkcjonalność znajdowała się w klasie bazowej?

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
źródło
aby obejść WPF z dziedziczeniem wizualnym, zobacz: svetoslavsavov.blogspot.gr/2009/09/… lub aby jawnie zdefiniować GUI w przodku, zobacz support.microsoft.com/kb/957231
George Birbilis

Odpowiedzi:

132

Upewnij się, że zmieniłeś pierwszy znacznik w xaml, aby dziedziczył również z nowego typu podstawowego

Więc

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

staje się

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

Podsumowując pełną odpowiedź, w tym dodatkowe szczegóły z poniższych komentarzy:

  • Klasa bazowa nie powinna zawierać pliku XAML. Zdefiniuj go w pojedynczym (nie częściowym) pliku cs i zdefiniuj, aby dziedziczał bezpośrednio po Usercontrol.
  • Upewnij się, że podklasa dziedziczy z klasy bazowej zarówno w pliku związanym z kodem cs, jak iw pierwszym tagu xaml (jak pokazano powyżej).
Martin Harris
źródło
4
kiedy wprowadzam tę zmianę, pojawia się błąd: „... DataTypes.BaseDataType nie może być katalogiem głównym pliku XAML, ponieważ został zdefiniowany przy użyciu XAML”, jak wyjść z tego cyklicznego odwołania?
Edward Tanguay
9
Jeśli możesz po prostu uczynić klasę bazową normalnym typem, który dziedziczy po UserControl bez definiowania żadnego xmal (a więc nie częściowego podziału klasy na dwa pliki). Problem polega na tym, że nie można dziedziczyć xmal, więc ani klasa podstawowa, ani klasa potomna nie muszą mieć pliku xmal. Albo to, albo utwórz własne kontrolki klas zamiast kontrolek użytkownika. W ten sposób wygląd jest zdefiniowany poza klasą częściową, ale stracisz łatwość użycia Kontroli użytkownika.
Martin Harris
1
To wszystko: jeśli uczynisz BaseDataType normalną klasą, która dziedziczy UserControl, to działa. Wspaniale dzięki.
Edward Tanguay
@Martin możesz zaktualizować swoją odpowiedź, aby odzwierciedlić Twój komentarz i to jest prawdziwa odpowiedź.
Bryan Anderson
Czy istnieje sposób, aby elementy z „bazy kontrolnej” znajdowały się nad tymi w klasie, która dziedziczy?
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
źródło
1

Odpowiedź znalazłem w tym artykule: http://www.paulstovell.com/xmlnsdefinition

Zasadniczo mówi się, że należy zdefiniować przestrzeń nazw XML w pliku AssemlyInfo.cs, której można użyć w pliku XAML. U mnie zadziałało, jednak podstawową klasę kontroli użytkownika umieściłem w osobnej bibliotece DLL ...

cola kolana
źródło
0

Napotkałem ten sam problem, ale musiałem mieć kontrolę dziedziczącą z klasy abstrakcyjnej, która nie jest obsługiwana przez projektanta. To, co rozwiązało mój problem, to spowodowanie, że kontrola użytkownika dziedziczy zarówno klasę standardową (która dziedziczy UserControl), jak i interfejs. W ten sposób pracuje projektant.

//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.
źródło
0

Istnieje częściowa definicja klasy utworzona przez projektanta, którą można łatwo otworzyć za pomocą definicji metody InitializeComponent (). Następnie po prostu zmień częściowe iheritence klasy z UserControl na BaseDataType (lub dowolną określoną w definicji klasy).

Następnie pojawi się ostrzeżenie, że metoda InitializeComponent () jest ukryta w klasie potomnej.

Dlatego możesz ustawić CustomControl jako klasę podstawową zamiast UserControl, aby uniknąć częściowej definicji w klasie bazowej (jak opisano w jednym komentarzu).

Kakha Middle Or
źródło
Nie można dokonać konwersji z Controls.Login do Controls.BaseControl.
Himilou