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.xaml
的 ResourceDictionary
并将其放在项目根目录下名为 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!");
}
我正在尝试在 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.
之后我尝试在控件的基础 class 中完全实现 child 控件。
刚刚在构造函数中创建它们并将它们添加到基础 class 继承自的堆栈面板的 Children 属性。
这确实(有点)奏效了。
但显然,当这样创建时,控件的行为完全不同。
不管设置。我只是无法让控件正确安装在它们的 parents.
中
而且这种方法完全不适合大项目,涉及到主题调整。
有人可以在这里指导我正确的方向吗?
创建一个名为 NavigatorItem
的 class(没有任何 .xaml
文件):
public class NavigatorItem : Control
{
static NavigatorItem()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(NavigatorItem),
new FrameworkPropertyMetadata(typeof(NavigatorItem)));
}
}
创建一个名为 generic.xaml
的 ResourceDictionary
并将其放在项目根目录下名为 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!");
}