TemplatePart作用

本文详细解释了在控件设计中使用契约(如[TemplatePart]属性)的作用和意义,阐述了它们如何帮助实现控件的默认行为,并强调了在ControlTemplate中包含这些元素的重要性。

TemplatePart(Name="PART_Decrease", Type=typeof(RepeatButton))

一直没明白这是干嘛用的,搜了一下,记载一下。


以Button的定义为例:

namespace System.Windows.Controls
{
    // Summary:
    //     Represents a button control, which reacts to the Click event.
    [TemplatePart(Name = "Normal State", Type = typeof(Storyboard))]
    [TemplatePart(Name = "MouseOver State", Type = typeof(Storyboard))]
    [TemplatePart(Name = "RootElement", Type = typeof(FrameworkElement))]
    [TemplatePart(Name = "Pressed State", Type = typeof(Storyboard))]
    [TemplatePart(Name = "FocusVisualElement", Type = typeof(UIElement))]
    [TemplatePart(Name = "Disabled State", Type = typeof(Storyboard))]
    public class Button : ButtonBase
    {
        // Summary:
        //     Initializes a new instance of the Button class.
        public Button();
        // Summary:
        //     Apply a template to the Button.
        protected override void OnApplyTemplate();
        //
        // Summary:
        //     Called when the IsEnabled property changes.
        //
        // Parameters:
        //   isEnabled:
        //     New value of the IsEnabled property.
        protected override void OnIsEnabledChanged(bool isEnabled);
    }
}

 [TemplatePart(Name = "Normal State", Type = typeof(Storyboard))] 这种东东是做什么用的 , 其实这是一种契约 , 是一种推荐的控件设计模式(只是推荐) , 意思是告诉要来写ControlTemplate的用户 , 你的ControlTemplate中需要有一个x:Name为“Normal State” , 类型为Storyboard , 当然这个类型可以是继承来的, 为什么一定要包含这些契约规定的元素 , 因为逻辑部分对这些东西进行了引用,它们将对控件的默认行为起着关键作用, 可以理解为这个控件的最基本元素 , 是实现默认行为的最小集合, 自然,你的ControlTemplate中如果没有包含契约中的内容 , 则相应的逻辑将无法实现。


所以说白了,就是提示用的.....这么写比较规范。


using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Controls; using System.Windows; using System.Windows.Data; using System.Windows.Media; using System.Windows.Input; namespace PavementStructureCalculate.Common { [TemplatePart(Name = PART_TextBox, Type = typeof(TextBox))] [TemplatePart(Name = PART_Button, Type = typeof(Button))] public class PickerTextBox : Control { internal const string PART_TextBox = "PART_TextBox"; internal const string PART_Button = "PART_Button"; private Button? _button; static PickerTextBox() { // 让 WPF 去 Themes/Generic.xaml 找默认模板 DefaultStyleKeyProperty.OverrideMetadata( typeof(PickerTextBox), new FrameworkPropertyMetadata(typeof(PickerTextBox))); } public override void OnApplyTemplate() { base.OnApplyTemplate(); if (_button != null) _button.Click -= Button_Click; // 绑定内部 TextBox var tb = GetTemplateChild(PART_TextBox) as TextBox; if (tb != null) { tb.SetBinding(TextBox.TextProperty, new Binding(nameof(Text)) { Source = this, Mode = BindingMode.TwoWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }); tb.SetBinding(TextBox.IsReadOnlyProperty, new Binding(nameof(IsReadOnly)) { Source = this }); } // 绑定按钮点击 → 转成对外事件 _button = GetTemplateChild(PART_Button) as Button; if (_button != null) _button.Click += Button_Click; } private void Button_Click(object? sender, RoutedEventArgs e) { if (PickRequested == null) return; // 没人订阅就不做任何事 var args = new PickRequestedEventArgs(Text ?? string.Empty); PickRequested.Invoke(this, args); if (args.Handled && args.ResultText is not null) Text = args.ResultText; // 写回到 Text } // ---- 依赖属性:Text ---- public static readonly DependencyProperty TextProperty = DependencyProperty.Register(nameof(Text), typeof(string), typeof(PickerTextBox), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); public string Text { get => (string)GetValue(TextProperty); set => SetValue(TextProperty, value); } // ---- 依赖属性:IsReadOnly(可选) ---- public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register(nameof(IsReadOnly), typeof(bool), typeof(PickerTextBox), new PropertyMetadata(false)); public bool IsReadOnly { get => (bool)GetValue(IsReadOnlyProperty); set => SetValue(IsReadOnlyProperty, value); } // ---- 依赖属性:ButtonWidth ---- public static readonly DependencyProperty ButtonWidthProperty = DependencyProperty.Register(nameof(ButtonWidth), typeof(double), typeof(PickerTextBox), new PropertyMetadata(32d)); public double ButtonWidth { get => (double)GetValue(ButtonWidthProperty); set => SetValue(ButtonWidthProperty, value); } // ---- 依赖属性:ButtonContent ---- public static readonly DependencyProperty ButtonContentProperty = DependencyProperty.Register(nameof(ButtonContent), typeof(object), typeof(PickerTextBox), new PropertyMetadata("…")); // 默认省略号 public object? ButtonContent { get => GetValue(ButtonContentProperty); set => SetValue(ButtonContentProperty, value); } // ---- 对外事件(像 Click 一样在 XAML 里写)---- public class PickRequestedEventArgs : EventArgs { public PickRequestedEventArgs(string currentText) { CurrentText = currentText; } public string CurrentText { get; } public string? ResultText { get; set; } public bool Handled { get; set; } } public event EventHandler<PickRequestedEventArgs>? PickRequested; } } 保持原功能不变 能不能给控件四周圆角 和设置边框
最新发布
09-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值