简体   繁体   中英

WPF Child Control Inheritance

I am trying to implement a control to inherit from in WPF.

I have never been working with WPF (at least at that level though).
So I need some direction of best practice on how to solve this.

The problem I´m facing is that my control, that I want to inherit from, has some child controls that need to be accessed inside the controls base class.
I want to reuse that control with these child controls inside, because it has functions to fill the child controls from outside.
But since WPF can´t inherit a control with xaml, I can´t get my head around a solution.

Let´s say I have this control.

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

In codebehind the Button is being used for a Click event as well as the header Text, which I want to be filled from the Control that inherits from this.

And with a function the TreeView "tvNavContent" is being filled with something like this:

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

What I want to achieve is to reuse the Stackpanel with the Button and TreeView inside and with it´s functions.

I tried two things:

First I tried to create a template and applied that to the base class. After that I just tried to load the controls of the template in the base class with the FindName<>() function.

The problem here is, that the template is applied after InitializeComponent().
But during InitializeComponent() I already need access, to set the controls header property for the title from the control that inherits from the base class.

After that I tried to implement the child controls completely in the base class of the control.
Just created them in the constructor and added them to the Children Property of the stackpanel the base class inherits from.

That did (somewhat) work.
But apparently the controls behave completely different when created like that.
No matter the settings. I just couldn´t get the controls to fit correctly inside their parents.
Furthermore, this method is completely unsuitable for a larger project, when it comes to theme adjustments.

Can someone guide me in the correct direction here?

Create a class called NavigatorItem (without any .xaml file):

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

Create a ResourceDictionary called generic.xaml and put it in a folder called themes (these names are by convention) at the root of your project, and define a default template for the NavigatorItem class in there:

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

You can then override the OnApplyTemplate of the NavigatorItem class to get a reference to the elements in the template and hook up event handlers to them, eg:

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!");
}

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