使用TemplateParts进行CustomControl

时间:2014-02-12 12:29:43

标签: wpf wpf-controls

我创建了一个包含两个TemplateParts的CustomControl。

using System;
using System.Windows;
using System.Windows.Controls;

namespace WpfCustomControlLibrary1
{
    [TemplatePart(Name = "PART_ControlsLayer", Type = typeof (ContentPresenter))]
    [TemplatePart(Name = "PART_DisplayLayer", Type = typeof (ContentPresenter))]
    public class CustomControl1 : Control
    {
        public static readonly DependencyProperty ControlsLayerProperty =
            DependencyProperty.Register("ControlsLayer", typeof (object), typeof (CustomControl1),
            new UIPropertyMetadata(null));

        public static readonly DependencyProperty DisplayLayerProperty =
            DependencyProperty.Register("DisplayLayer", typeof (object), typeof (CustomControl1),
            new UIPropertyMetadata(null));

        private ContentPresenter partControlsLayer;
        private ContentPresenter partDisplayLayer;

        static CustomControl1()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof (CustomControl1),
                new FrameworkPropertyMetadata(typeof (CustomControl1)));
        }


        public object ControlsLayer
        {
            get { return GetValue(ControlsLayerProperty); }
            set { SetValue(ControlsLayerProperty, value); }
        }

        public object DisplayLayer
        {
            get { return GetValue(DisplayLayerProperty); }
            set { SetValue(DisplayLayerProperty, value); }
        }

        public override void OnApplyTemplate()
        {
            ApplyTemplate();

            partControlsLayer = GetTemplateChild("PART_ControlsLayer") as ContentPresenter;


            partDisplayLayer = GetTemplateChild("PART_DisplayLayer") as ContentPresenter;

            if (partControlsLayer == null || partDisplayLayer == null)
            {
                throw new NullReferenceException("Template parts not available");
            }
        }
    }
}

在Generic.xaml中,我为DisplayLayer(其中一个TemplateParts)定义了ControlTemplate和Default-Setter。最后我将其设置为CustomControl1的模板。

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfCustomControlLibrary1">

    <Style TargetType="{x:Type local:CustomControl1}">
        <Style.Resources>
            <ControlTemplate x:Key="DefaulTemplate" TargetType="{x:Type local:CustomControl1}">
                <Grid>
                    <ContentPresenter x:Name="PART_ControlsLayer"
                                          Content="{TemplateBinding ControlsLayer}" />
                    <ContentPresenter x:Name="PART_DisplayLayer"
                                          Content="{TemplateBinding DisplayLayer}" />
                </Grid>
            </ControlTemplate>
        </Style.Resources>

        <Setter Property="DisplayLayer">
            <Setter.Value>
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition />
                        <RowDefinition />
                        <RowDefinition />
                        <RowDefinition />
                    </Grid.RowDefinitions>
                    <Label Grid.Row="0" Content="{Binding FunctionName, FallbackValue=Functionname}" />
                    <TextBlock Grid.Row="1" Text="{Binding DisplayValue, FallbackValue=0.0dB}" Foreground="Lime"
                               Background="Black" />
                </Grid>
            </Setter.Value>
        </Setter>
        <Setter Property="Template" Value="{StaticResource DefaulTemplate}"/>
    </Style>

    <Style TargetType="{x:Type local:CustomControl2}" BasedOn="{StaticResource {x:Type local:CustomControl1}}" />
</ResourceDictionary>

现在我创建一个CustomControl2 BasedOn CustomControl1。

using System.Windows;

namespace WpfCustomControlLibrary1
{
    public class CustomControl2 : CustomControl1
    {
        static CustomControl2()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl2), new FrameworkPropertyMetadata(typeof(CustomControl2)));
        }
    }
}

然后我将两个控件放在WpfWindow上。

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wpfCustomControlLibrary1="clr-namespace:WpfCustomControlLibrary1;assembly=WpfCustomControlLibrary1"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <wpfCustomControlLibrary1:CustomControl1 Grid.Row="0"/>

        <wpfCustomControlLibrary1:CustomControl2 Grid.Row="1"/>
    </Grid>
</Window>

问题是我只在第二个控件上看到Defaulttemplate。我无法找到解决方案,请帮助。

@ gomi42 - 如果我将Generic.xaml更改为:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfCustomControlLibrary1">

    <Style x:Key="BaseStyle" TargetType="{x:Type local:CustomControl1}">
        <Style.Resources>
            <ControlTemplate x:Key="DefaulTemplate" TargetType="{x:Type local:CustomControl1}">
                <Grid>
                    <ContentPresenter x:Name="PART_ControlsLayer"
                                            Content="{TemplateBinding ControlsLayer}" />
                    <ContentPresenter x:Name="PART_DisplayLayer"
                                            Content="{TemplateBinding DisplayLayer}" />
                </Grid>
            </ControlTemplate>
        </Style.Resources>

        <Setter Property="Template" Value="{StaticResource DefaulTemplate}"/>

        <Setter Property="DisplayLayer">
            <Setter.Value>
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition />
                        <RowDefinition />
                        <RowDefinition />
                        <RowDefinition />
                    </Grid.RowDefinitions>
                    <Label Grid.Row="0" Content="{Binding FunctionName, FallbackValue=Functionname}" />
                    <TextBlock Grid.Row="1" Text="{Binding DisplayValue, FallbackValue=0.0dB}" Foreground="Lime"
                                Background="Black" />
                </Grid>
            </Setter.Value>
        </Setter>
    </Style>

    <Style TargetType="{x:Type local:CustomControl1}" BasedOn="{StaticResource BaseStyle}" />

    <Style TargetType="{x:Type local:CustomControl2}" BasedOn="{StaticResource BaseStyle}" />
</ResourceDictionary>
没有什么变化!它仅在第二个控件中可见。

2 个答案:

答案 0 :(得分:0)

您创建的样式仅适用于CustomControl1:

<Style TargetType="{x:Type local:CustomControl1}">
...

您需要为CustomControl2创建一个新样式,例如通过继承:

<Style x:Key="MyBase" TargetType="{x:Type local:CustomControl1}">
...
</Style>

<Style TargetType="{x:Type local:CustomControl1}" BasedOn={StaticResource MyBase} />
<Style TargetType="{x:Type local:CustomControl2}" BasedOn={StaticResource MyBase} />

答案 1 :(得分:0)

我找到了它!

导致问题的是DependencyProperty。我像本网站上的示例一样实现了CustomControl: http://www.kunal-chowdhury.com/2011/04/how-to-implement-template-binding-in.html

我该怎么说这个例子是错的!

以下是它的工作原理。

第一个CustomControl.cs

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using WpfCustomControlLibrary1.Annotations;

namespace WpfCustomControlLibrary1
{
    [TemplatePart(Name = "PART_ControlsLayer", Type = typeof (Grid))]
    [TemplatePart(Name = "PART_DisplayLayer", Type = typeof(ContentControl))]
    public class CustomControl1 : Control
    {
        private Grid partControlsLayer;
        private ContentControl partDisplayLayer;

        static CustomControl1()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof (CustomControl1),
                new FrameworkPropertyMetadata(typeof (CustomControl1)));
        }

        public CustomControl1()
        {
            DataContext = this;
        }


        public override void OnApplyTemplate()
        {
            ApplyTemplate();

            partControlsLayer = GetTemplateChild("PART_ControlsLayer") as Grid;


            partDisplayLayer = GetTemplateChild("PART_DisplayLayer") as ContentControl;

            if (partControlsLayer == null || partDisplayLayer == null)
            {
                //throw new NullReferenceException("Template parts not available");
            }
        }
    }
}

然后是Generic.xaml

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfCustomControlLibrary1">

    <Style x:Key="DefaultTemplate" TargetType="{x:Type ContentControl}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ContentControl}">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition />
                            <RowDefinition />
                        </Grid.RowDefinitions>
                        <Label Grid.Row="0" Content="{Binding FunctionName, FallbackValue=Functionname}" />
                        <TextBlock Grid.Row="1" Text="{Binding DisplayValue, FallbackValue=0.0dB}" Foreground="Lime"
                                   Background="Black" />
                    </Grid>

                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>


    <Style TargetType="{x:Type local:CustomControl1}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition />
                            <RowDefinition />
                        </Grid.RowDefinitions>
                        <ContentControl x:Name="PART_DisplayLayer" Style="{StaticResource DefaultTemplate}" />
                        <Grid x:Name="PART_ControlsLayer" Grid.Row="1">
                            <Grid.RowDefinitions>
                                <RowDefinition />
                                <RowDefinition />
                            </Grid.RowDefinitions>
                            <Button Grid.Row="0" Content="{Binding FunctionName, FallbackValue=Functionname}" />
                            <Button Grid.Row="1" Content="{Binding DisplayValue, FallbackValue=0.5dB}" />
                        </Grid>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style TargetType="{x:Type local:CustomControl2}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition />
                            <RowDefinition />
                        </Grid.RowDefinitions>
                        <ContentControl x:Name="PART_DisplayLayer" Style="{StaticResource DefaultTemplate}" />
                        <Grid x:Name="PART_ControlsLayer" Grid.Row="1">
                            <Grid.RowDefinitions>
                                <RowDefinition />
                                <RowDefinition />
                            </Grid.RowDefinitions>
                            <Button Grid.Row="0" Content="Depp" />
                            <Button Grid.Row="1" Content="{Binding DisplayValue, FallbackValue=1.0dB}" />
                        </Grid>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

CustomControl2.cs作为Derived-Class

using System.Windows;

namespace WpfCustomControlLibrary1
{
    public class CustomControl2 : CustomControl1
    {
        static CustomControl2()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl2), new FrameworkPropertyMetadata(typeof(CustomControl2)));
        }

        public CustomControl2()
        {
            DataContext = this;
        }
    }
}

MainWindow仍然是一样的。

这是有效的,因为没有任何内容是静态的。