Title

WPF 自定义控件学习二,控件基础知识

 官方文档:控件编写概述 - WPF | Microsoft Learn

可以先参考

1、WPF 自定义控件学习一,前期工作准备 - 宇一心途 - 博客园

2.1. 依赖属性(Dependency Properties)

2.2. 路由事件(Routed Events)

2.3. 控件模板(Control Templates)

2.4. 样式和主题(Styles and Themes)

2.5. 内容呈现(Content Presentation)

 

2、依赖属性:WPF 属性系统支持的属性称为依赖属性。可以支持以下内容

  1)设置样式中的属性。
  2)将属性绑定到数据源。
  3)使用动态资源作为属性值。
  4)对属性进行动画处理。

2.1、使用标识符DependencyProperty定义,通过调用 DependencyProperty.Register向属性系统注册属性名称,以指定以下内容:

  属性的名称。
  属性类型。
  拥有该属性的类型。
  属性的元数据。元数据包含属性的默认值、 CoerceValueCallback 和 PropertyChangedCallback
  属性校验(可选)。

如下图代码所示、以及对应的注释。注册一个为Value的依赖属性。其中默认值:2,限制值为0-100,且只为非负数。(注意后面会用到)

image

 

对应依赖属性完整代码

 // 注册“Value”依赖属性。
 public static readonly DependencyProperty ValueProperty =
     DependencyProperty.Register(
         "Value",                   // 属性名称
         typeof(int),               // 属性类型
         typeof(MyButton),          // 拥有该属性的控件类型 
                                    // 属性的元数据
         new FrameworkPropertyMetadata(
             2,             // 默认值
             new PropertyChangedCallback(OnValueChanged),   // 属性更改回调,并指定对应的函数
             new CoerceValueCallback(CoerceValue)           // 强制回调,并指定对应的函数
             ),
         new ValidateValueCallback(ValidateValue) // 属性值验证回调 (可选),并指定对应的函数
         );

 // 获取或设置分配给控件的值。CLR包装器
 public int Value
 {
     get { return (int)GetValue(ValueProperty); }
     set { SetValue(ValueProperty, value); }
 }

 // 验证回调
 private static bool ValidateValue(object value)
 {
     int val = (int)value;
     return !int.IsNegative(val);  // 不允许负值
 }

 // 强制回调允许你在属性值被设置前对其进行修正或强制转换,确保值在特定范围内。
 private static object CoerceValue(DependencyObject element, object value)
 {
     int newValue = (int)value;
     if (newValue < 0)
     {
         newValue = 0;
     }
     if (newValue > 100)
     {
         newValue = 100;
     }
     return newValue;
 }
 // 属性变更回调在依赖属性的值发生变化时被调用,可以在这里执行相关的响应逻辑。
 private static void OnValueChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
 {
     MyButton control = (MyButton)obj;
     int newValue = (int)args.NewValue;
     int oldValue = (int)args.OldValue;
     // 在这里处理属性值更改的逻辑
     control.OnValueChanged(oldValue, newValue);
 }

 protected virtual void OnValueChanged(double oldValue, double newValue)
 {
     // 可以触发事件或执行其他操作
 }
View Code

 

3、路由事件:可以支持以下内容:

  1)、可以在多个控件的父级上处理事件。
  2)、路由事件可在一个 EventSetter对象中使用,这使应用程序开发人员能够在样式中指定事件的处理程序。
  3)、路由事件可用于 EventTrigger,这对于使用XAML对属性进行动画处理非常有用。

3.1、路由事件的类型:
  1)、冒泡路由(Bubbling Routing) : 事件从触发元素开始,沿着元素树向上冒泡,依次触发父元素、祖父元素...直到根元素的事件处理程序。这是最常见的路由类型。
  2)、隧道路由(Tunneling Routing) : 事件从元素树的根元素开始,沿着元素树向下隧道,依次触发祖父元素、父元素...直到触发元素的事件处理程序。隧道路由事件通常以 "Preview" 开头,例如 PreviewMouseDown。
  3)、直接路由(Direct Routing) : 事件只在触发元素自身上触发,不进行路由传播。CLR 事件通常是直接路由事件。

3.2、使用标识符RoutedEvent定义对应的事件,通过调用 EventManager.RegisterRoutedEvent 方法注册路由事件,以指定以下内容:

  事件的名称
  路由策略
  事件处理程序的类型
  事件所属的控件类型

如下图代码所示、以及对应的注释。注册一个为ValueChanged的路由事件。

image

 对应路由事件完整代码

// 注册 ValueChanged 的路由事件
public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent(
    "MyValueChanged",                                   // 事件名称
    RoutingStrategy.Bubble,                             // 路由策略 (冒泡)
    typeof(RoutedPropertyChangedEventHandler<int>),     // 事件处理程序的类型
    typeof(MyButton)                                    // 事件所属的控件类型
);

// 当Value属性发生更改时触发。创建CLR事件包装器(供XAML绑定)
public event RoutedPropertyChangedEventHandler<int> MyValueChanged
{
    add { AddHandler(ValueChangedEvent, value); }
    remove { RemoveHandler(ValueChangedEvent, value); }
}

// 当值改变、引发ValueChanged事件。
protected virtual void OnValueChanged(int oldValue, int newValue)
{
    //  创建已注册和包装的本身的路由事件实例,并引发它
    RoutedPropertyChangedEventArgs<int> args = new RoutedPropertyChangedEventArgs<int>(oldValue, newValue);
    args.RoutedEvent = ValueChangedEvent;
    RaiseEvent(args); // 触发自定义路由事件
}
View Code

 

4、示例、学习完依赖属性与路由事件,想给出一个示例以便于大家理解,

  1)给MainWindow.xaml中的自定义控件绑定依赖属性与路由事件,如下图所示。

image

  2)写后台代码的逻辑,自定义按键双击事件触发后,修改他的值为102超过100,并输出对应的值

image

   3)运行结果

    可以看到,提示框的值为100,可知在触发依赖属性的强制回调时候,会把值限制为0-100

image

 完整项目源码:https://files.cnblogs.com/files/blogs/721038/UpperComputer-%E4%BE%9D%E8%B5%96%E5%B1%9E%E6%80%A7%E4%B8%8E%E8%B7%AF%E7%94%B1%E4%BA%8B%E4%BB%B6%E9%9B%86%E5%90%88.7z?t=1767278960&download=true

 

posted @ 2026-01-01 17:49  宇一心途  阅读(4)  评论(0)    收藏  举报