1. 主页 > 2018世界杯阿根廷 >

WPF自定义控件完整流程(4)

在WPF中创建自定义控件的完整流程

1. 选择控件基类

根据功能需求选择合适的基类:

| 基类类型 | 适用场景 | 特点 | |--------------------|-----------------------------------|-----------------------------| | UserControl | 快速组合现有控件 | 设计器支持,不可模板化 | | Control | 需要完全自定义外观和行为的控件 | 支持模板化,高可扩展性 | | ContentControl | 包含单个子元素的容器控件 | 支持内容模型 | | ItemsControl | 展示集合数据的控件 | 支持项模板和面板定制 |

示例代码(继承Control):

public class CustomButton : Control

{

static CustomButton()

{

DefaultStyleKeyProperty.OverrideMetadata(

typeof(CustomButton),

new FrameworkPropertyMetadata(typeof(CustomButton)));

}

}

2. 定义依赖属性

使用依赖属性系统实现数据绑定支持:

public class CustomButton : Control

{

// 定义按钮角半径属性

public static readonly DependencyProperty CornerRadiusProperty =

DependencyProperty.Register(

name: "CornerRadius",

propertyType: typeof(CornerRadius),

ownerType: typeof(CustomButton),

new FrameworkPropertyMetadata(

defaultValue: new CornerRadius(4),

FrameworkPropertyMetadataOptions.AffectsRender));

// CLR属性包装器

public CornerRadius CornerRadius

{

get => (CornerRadius)GetValue(CornerRadiusProperty);

set => SetValue(CornerRadiusProperty, value);

}

}

属性注册参数说明:

name:属性名称

propertyType:属性类型(必须使用可冻结类型)

ownerType:所属控件类型

defaultValue:默认值

metadataOptions:影响渲染/布局的选项

3. 创建控件模板

在Themes/Generic.xaml中定义默认外观:

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:local="clr-namespace:YourNamespace">

模板设计要点:

使用TemplateBinding关联控件属性

命名模板部件遵循PART_前缀规范

定义视觉状态触发器实现交互效果

4. 实现控件逻辑

添加交互逻辑和事件处理:

public class CustomButton : Control

{

// 定义路由事件

public static readonly RoutedEvent SpecialClickEvent =

EventManager.RegisterRoutedEvent(

"SpecialClick",

RoutingStrategy.Bubble,

typeof(RoutedEventHandler),

typeof(CustomButton));

// 事件包装器

public event RoutedEventHandler SpecialClick

{

add => AddHandler(SpecialClickEvent, value);

remove => RemoveHandler(SpecialClickEvent, value);

}

// 重写鼠标事件

protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)

{

base.OnMouseLeftButtonDown(e);

RaiseEvent(new RoutedEventArgs(SpecialClickEvent, this));

}

// 获取模板部件

private Border _border;

public override void OnApplyTemplate()

{

base.OnApplyTemplate();

_border = GetTemplateChild("border") as Border;

if (_border != null)

{

_border.MouseEnter += OnBorderMouseEnter;

}

}

}

5. 注册资源字典

确保项目正确识别控件模板:

重要验证点:

确认程序集名称与Source路径一致

检查XAML文件的生成操作是否为Page

确保资源字典路径大小写正确

6. 使用自定义控件

在XAML中引用并配置:

xmlns:local="clr-namespace:YourNamespace;assembly=YourAssembly">

Content="Click Me"

CornerRadius="8"

Background="#FF2196F3"

BorderThickness="2"

SpecialClick="CustomButton_SpecialClick"/>

调试技巧:

使用Snoop工具检查可视化树

在代码中验证模板部件是否成功获取

检查依赖属性绑定是否正确更新

使用PresentationTraceSources.TraceLevel=High调试绑定

高级实现技巧

视觉状态管理

// 定义视觉状态组

VisualStateManager.GoToState(this, "Pressed", true);

// 在模板中添加状态动画

To="DarkBlue" Duration="0:0:0.2"/>

性能优化方案

// 使用DrawingVisual进行复杂渲染

protected override void OnRender(DrawingContext drawingContext)

{

var geometry = new StreamGeometry();

using (var context = geometry.Open())

{

context.BeginFigure(new Point(0, 0), true, true);

context.LineTo(new Point(50, 50), true, false);

}

geometry.Freeze();

drawingContext.DrawGeometry(Brushes.Black, null, geometry);

}

支持主题切换

Themes/

├─ Generic.xaml (默认主题)

├─ DarkTheme.xaml (深色主题)

└─ HighContrast.xaml (高对比度主题)