【问题标题】:How do you inherit Dependent Properties from a base WPF User Control to a new User Control that is inherited?如何从基本 WPF 用户控件继承从属属性到继承的新用户控件?
【发布时间】:2017-02-09 16:05:22
【问题描述】:

我可以用 VB 或 C# 来回答,我都知道,但最终的解决方案将用 VB.Net 编写。本质上,我想使用一个模板在 n 次排列中重用基的从属属性,但是我正在使用带有路由后面代码的 xaml 并放弃了样式模板。基本上我想在我想用作基础的用户控件中做这样的事情:

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>

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

我想做的是这样的:

使用1:

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

使用2

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

现在我知道我可以做这样的事情(并且可能是我应该走的路)

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

但我宁愿只从基本模板继承,然后应用我需要的一切。 我是否需要使用样式模板才能做到这一点,或者我可以按原样重用 XAML 用户控件吗? 每次我尝试在后面的代码中执行“继承(基类名)”时,我都会得到这个错误:

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

所以我有点摸不着头脑,对 WPF 的语言和功能知之甚少,这是可以做到的,还是应该为此做的。

【问题讨论】:

  • 基类不应包含任何内容或 XAML 文件,因为这将被派生的 UserControl 实例覆盖。您希望能够在派生控件中使用“PART_TestLayout”网格吗?
  • 是的,大部分绘图是在后面的代码中完成的,但我仍然在传统的 MVVM 架构中绑定数据元素。我想重用常见的 Dependent 属性,而不是如何挑剔。我只是不想为不同的迭代设置 2、3 或 4 次。
  • @mm8 继承自任何东西的 XAML 用户控件必须有更多的继承。每次我尝试时,我总是得到:'为类'Test'指定的基类'BaseTest'不能与其其他部分类型之一的基类'UserControl'不同。'。我可以让它本身继承'UserControl',把这个
  • 实际上,我以前的 Visual Studio 2017 RC 看起来像是某种奇怪的随机错误。这就是我尝试使用 RC 编写生产代码的结果。
  • 我提供了一个工作示例。希望对您有所帮助。

标签: c# wpf vb.net inheritance


【解决方案1】:

您不能重用基础UserControl 的内容,因为该内容将被派生控件覆盖。基类应该只定义依赖属性并且没有任何 XAML 标记。

请参考以下示例代码:

Test.vb(基类):

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

【讨论】:

  • 这就是我一直在寻找的东西,也是我最终要走的路线。即使只是重用我的 Dependent Properties 也是一个巨大的胜利。
【解决方案2】:

UserControls 用于合成。如果你想要合理的继承,你应该使用自定义控件。

http://wpftutorial.net/HowToCreateACustomControl.html

在您的情况下,我将从 TextBlock 继承并向其添加 BottomText 依赖项属性。然后在 Generic.xaml 中设置它的样式,就像您所做的那样。

另请参阅此处了解 UserControls 和自定义控件之间的区别(后一种模式是为您的用例构建的):http://wpftutorial.net/CustomVsUserControl.html

【讨论】:

  • 我对走这条路感到好奇的问题是,通常你在 Style 中有这样的东西:'
  • @djangojazz 您继承了具有 BasedOn 属性的样式。
  • 没有看到更完整的例子,我试过了,通常你需要一个模板控件以及它绑定的数据,它也是可视元素。我不认为你所说的在这种情况下适用于继承,因为这比继承颜色或 UI 特定属性更复杂。我想继承我从定制的基础设置的东西。
  • @djangojazz - 在这种情况下,我必须让你回复我的答案。
猜你喜欢
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-08
  • 1970-01-01
  • 1970-01-01
  • 2013-09-03
  • 1970-01-01
相关资源
最近更新 更多