简体   繁体   中英

How do you inherit Dependent Properties from a base WPF User Control to a new User Control that is inherited?

I would be fine with an answer in VB or C#, I know both, ultimate solution will be written in VB.Net though. Essentially I want to use a template for reuse of the Dependent Properties of the base in n numbers of permutations but I was going a xaml with code behind route and abandoned a Style template. Basically I want to do something like this in a user control I would want to use for a base:

XAML:

<UserControl x:Class="Test"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WPFControls"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid Name="PART_TestLayout">
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <TextBlock Text="{Binding TestTitle}" Height="30" Background="White" Foreground="Black" />
    <TextBlock Name="PART_Text2" Grid.Row="1" Background="White" />
  </Grid>
</UserControl>

Code Behind of XAML:

Imports System.ComponentModel

Public Class Test


  Public Sub New()
    InitializeComponent()
    PART_TestLayout.DataContext = Me
  End Sub

  Public Shared ReadOnly TestTitleProperty As DependencyProperty = DependencyProperty.Register("TestTitle", GetType(String), GetType(Test), New UIPropertyMetadata(String.Empty, AddressOf TestChanged))

  Public Property TestTitle As String
    Get
      Return CType(GetValue(TestTitleProperty), String)
    End Get
    Set
      SetValue(TestTitleProperty, Value)
    End Set
  End Property

  Private Shared Sub TestChanged(d As DependencyObject, e As DependencyPropertyChangedEventArgs)
    Dim m = DirectCast(d, Test)
    m.PART_Text2.Text = $"Changed {DateTime.Now.ToLongTimeString}"
  End Sub
  Public MustOverride Sub DoThing()
End Class

What I would like to do is something like this:

Use1:

<local:Test x:Class="TestInheritance"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WPFControls"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
    <Label Content="I am the first implentation"/>
    <local:Test TestTitle="{Binding TestText}" />
  </Grid>
</local:Test>

Use2

<local:Test x:Class="TestInheritance2"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WPFControls"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
    <Label Content="I am the second implentation"/>
    <local:Test TestTitle="{Binding TestText}" />
  </Grid>
</local:Test>

Now I know I could do something like this (and may be the way I should go)

<UserControl x:Class="TestInheritance"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WPFControls"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
    <local:Part1 TestTitle="{Binding TestText}" />
    <!-- myproprietaryContent -->
    <local:Part2 TestLegend="{Binding TestText2}" />
  </Grid>
</local:Test>

But I would rather just inherit from a base template and just apply everything I need from that. Do I need to use a Style Template to have to do that or can I reuse a XAML UserControl ALMOST EXACTLY as is? Everytime I try to do 'inherits (baseclassname)' in the code behind I get this error:

'Base class 'Test' specified for class 'TestInheritance' cannot be different from the base class 'UserControl' of one of its other partial types.'

So I am kind of stuck scratching my head not knowing enough on the language and capabilities of WPF is this can be done, or should be done for that matter.

You cannot reuse the content of the base UserControl as the content will be overridden by the derived controls. The base class should only define the dependency properties and don't have any XAML markup.

Please refer to the following sample code:

Test.vb (the base class):

Public MustInherit Class Test
    Inherits UserControl

    Public Shared ReadOnly TestTitleProperty As DependencyProperty = DependencyProperty.Register("TestTitle", GetType(String), GetType(Test), New UIPropertyMetadata(String.Empty, AddressOf TestChanged))

    Public Property TestTitle As String
        Get
            Return CType(GetValue(TestTitleProperty), String)
        End Get
        Set
            SetValue(TestTitleProperty, Value)
        End Set
    End Property

    Private Shared Sub TestChanged(d As DependencyObject, e As DependencyPropertyChangedEventArgs)
        '...
    End Sub
    Public MustOverride Sub DoThing()
End Class

UserControl1.xaml:

<local:Test x:Class="UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WpfApplicationVb1"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>

    </Grid>
</local:Test>

UserControl1.xaml.vb:

Public Class UserControl1
    Inherits Test

    Public Overrides Sub DoThing()
        '...
    End Sub
End Class

UserControls are for composition. If you want sensible inheritance you should use custom controls.

http://wpftutorial.net/HowToCreateACustomControl.html

In your case I would inherit from TextBlock and add a BottomText dependency property to it. Then style it in Generic.xaml largely as you have done.

See also here for the difference between UserControls and Custom Controls (the latter pattern was built for your use case): http://wpftutorial.net/CustomVsUserControl.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM