WPF核心技术解析与使用示例
一、依赖属性(Dependency Property)详解
1. 依赖属性基础
核心概念:
- 依赖属性是WPF实现数据绑定、样式、动画等特性的基础
- 通过属性系统实现高效的内存管理和值继承
标准定义模式:
public class MyControl : Control
{
// 1. 定义依赖属性标识符
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register(
nameof(MyProperty), // 属性名称
typeof(string), // 属性类型
typeof(MyControl), // 所属类型
new PropertyMetadata("默认值")); // 默认值和回调
// 2. 定义CLR包装属性
public string MyProperty
{
get => (string)GetValue(MyPropertyProperty);
set => SetValue(MyPropertyProperty, value);
}
}
关键特性:
- 值继承:子元素可以继承父元素的属性值
- 变更通知:自动通知UI更新
- 存储优化:只在值改变时存储实际值
- 动画支持:可直接用于动画系统
2. 依赖属性元数据
new PropertyMetadata(
defaultValue: "默认值", // 默认值
propertyChangedCallback: OnValueChanged, // 值改变回调
coerceValueCallback: CoerceValue, // 值强制回调
isAnimationProhibited: false // 是否禁止动画
);
// 回调示例
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (MyControl)d;
// 处理属性变化逻辑
}
private static object CoerceValue(DependencyObject d, object baseValue)
{
if (baseValue is string str && str.Length > 10)
{
return str.Substring(0, 10); // 限制最大长度
}
return baseValue;
}
二、附加属性(Attached Property)详解
1. 附加属性概念
核心特点:
- 可由非所有者类型定义
- 可附加到任何DependencyObject上
- 常用于布局控制(Grid.Row)和行为扩展
实现示例:
public class GridHelper
{
// 定义附加属性
public static readonly DependencyProperty ColumnProperty =
DependencyProperty.RegisterAttached(
"Column",
typeof(int),
typeof(GridHelper),
new PropertyMetadata(0));
// CLR包装器
public static int GetColumn(DependencyObject obj) => (int)obj.GetValue(ColumnProperty);
public static void SetColumn(DependencyObject obj, int value) => obj.SetValue(ColumnProperty, value);
}
XAML使用:
<Grid>
<Button GridHelper.Column="1" Content="附加属性示例"/>
</Grid>
三、命令模式(Commanding)
1. RelayCommand实现
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Predicate<object> _canExecute;
public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);
public void Execute(object parameter) => _execute(parameter);
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
ViewModel中使用:
public class MainViewModel : INotifyPropertyChanged
{
private string _name;
public string Name
{
get => _name;
set { _name = value; OnPropertyChanged(); }
}
public ICommand SayHelloCommand { get; }
public MainViewModel()
{
SayHelloCommand = new RelayCommand(
execute: _ => MessageBox.Show($"Hello, {Name}!"),
can