[WPF自定义控件库] 自定义控件的代码如何与ControlTemplate交互

1. 前言

WPF有一个灵活的UI框架,用户可以轻松地使用代码控制控件的外观。例设我需要一个控件在鼠标进入的时候背景变成蓝色,我可以用下面这段代码实现:

protected override void OnMouseEnter(MouseEventArgs e)
{
    base.OnMouseEnter(e);
    Background = new SolidColorBrush(Colors.Blue);
}

但一般没人会这么做,因为这样做代码和UI过于耦合,难以扩展。正确的做法应该是使用代码告诉ControlTemplate去改变外观,或者控制ControlTemplate中可用的元素进入某个状态。

这篇文章介绍自定义控件的代码如何和ControlTemplate交互,涉及的知识包括RelativeSource、Trigger、TemplatePart和VisualState。

2. 简单的Expander

本文使用一个简单的Expander介绍UI和ControlTemplate交互的几种技术,它的代码如下:

public class MyExpander : HeaderedContentControl
{
    public MyExpander()
    {
        DefaultStyleKey = typeof(MyExpander);
    }

    public bool IsExpanded
    {
        get => (bool)GetValue(IsExpandedProperty);
        set => SetValue(IsExpandedProperty, value);
    }

    public static readonly DependencyProperty IsExpandedProperty =
        DependencyProperty.Register(nameof(IsExpanded), typeof(bool), typeof(MyExpander), new PropertyMetadata(default(bool), OnIsExpandedChanged));

    private static void OnIsExpandedChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        var oldValue = (bool)args.OldValue;
        var newValue = (bool)args.NewValue;
        if (oldValue == newValue)
            return;

        var target = obj as MyExpander;
        target?.OnIsExpandedChanged(oldValue, newValue);
    }

    protected virtual void OnIsExpandedChanged(bool oldValue, bool newValue)
    {
        if (newValue)
            OnExpanded();
        else
            OnCollapsed();
    }

    protected virtual void OnCollapsed()
    {
    }

    protected virtual void OnExpanded()
    {
    }
}

<Style TargetType="{x:Type local:MyExpander}">
    <Setter Property="HorizontalContentAlignment"
            Value="Stretch" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:MyExpander}">
                <Border Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                    <StackPanel>
                        <ToggleButton x:Name="ExpanderToggleButton"
                                      Content="{TemplateBinding Header}"
                                      IsChecked="{Binding IsExpanded,RelativeSource={RelativeSource Mode=TemplatedParent},Mode=TwoWay}" />
                        <ContentPresenter Grid.Row="1"
                                          x:Name="ContentPresenter"
                                          Horizonta
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值