WPF Child 控件继承

WPF Child Control Inheritance

我正在尝试在 WPF 中实现一个继承自的控件。

我从未使用过 WPF(至少在那个级别)。
所以我需要一些关于如何解决这个问题的最佳实践指导。

我面临的问题是我想继承的控件有一些 child 控件需要在控件库 class.[=39= 中访问] 我想在内部使用这些 child 控件重用该控件,因为它具有从外部填充 child 控件的功能。
但是由于 WPF 无法继承带有 xaml 的控件,我无法找到解决方案。

假设我有这个控制权。

<StackPanel x:Class="Framework.UI.Controls.Base.Navigator.NavigatorItem"
             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:Framework.UI.Controls.Base.Navigator"
             mc:Ignorable="d" 
             d:DesignHeight="26" d:DesignWidth="200">
    <Button Name="btnHeader" Content="Button"/>
    <TreeView Name="tvNavContent" Height="0"/>
</StackPanel>

在代码隐藏中,按钮被用于 Click 事件以及 header 文本,我想从继承自此的控件中填充它。

并且通过一个函数,TreeView "tvNavContent" 被这样的东西填充:

<TreeViewItem x:Class="Framework.UI.Controls.Base.Navigator.NavigatorEntry"
             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:Framework.UI.Controls.Base.Navigator"
             mc:Ignorable="d" 
             d:DesignHeight="20" d:DesignWidth="200">
    <TreeViewItem.Header>
        <StackPanel Orientation="Horizontal">
            <Image Name="imgIcon" Width="16" Height="16" Stretch="Fill"/>
            <TextBlock Name="txtTitle"/>
        </StackPanel>
    </TreeViewItem.Header>
</TreeViewItem>

我想要实现的是重用 Stackpanel 及其内部的 Button 和 TreeView 及其功能。

我尝试了两件事:

首先,我尝试创建一个模板并将其应用于基础 class。之后,我只是尝试使用 FindName<>() 函数在基础 class 中加载模板的控件。

这里的问题是,模板是在 InitializeComponent() 之后应用的。
但是在 InitializeComponent() 期间,我已经需要访问权限,以便从继承自基础 class.

的控件中为标题设置控件 header 属性

之后我尝试在控件的基础 class 中完全实现 child 控件。
刚刚在构造函数中创建它们并将它们添加到基础 class 继承自的堆栈面板的 Children 属性。

这确实(有点)奏效了。
但显然,当这样创建时,控件的行为完全不同。
不管设置。我只是无法让控件正确安装在它们的 parents.
中 而且这种方法完全不适合大项目,涉及到主题调整。

有人可以在这里指导我正确的方向吗?

创建一个名为 NavigatorItem 的 class(没有任何 .xaml 文件):

public class NavigatorItem : Control
{
    static NavigatorItem()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(NavigatorItem),
            new FrameworkPropertyMetadata(typeof(NavigatorItem)));
    }
}

创建一个名为 generic.xamlResourceDictionary 并将其放在项目根目录下名为 themes 的文件夹中(这些名称是约定俗成的),并为NavigatorItem class 在那里:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WpfApp12">
    <Style TargetType="local:NavigatorItem">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:NavigatorItem">
                    <StackPanel>
                        <Button Name="btnHeader" Content="Button"/>
                        <TreeView Name="tvNavContent" Height="0"/>
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

然后您可以覆盖 NavigatorItem class 的 OnApplyTemplate 以获取对模板中元素的引用并将事件处理程序挂接到它们,例如:

public override void OnApplyTemplate()
{
    Button button = GetTemplateChild("btnHeader") as Button;
    button.Click += Button_Click;
}

private void Button_Click(object sender, RoutedEventArgs e)
{
    MessageBox.Show("button clicked!");
}