在 WPF(Windows Presentation Foundation)中,Behavior(行为) 是一种用于封装可重用交互逻辑的机制。它允许你将 UI 元素的交互逻辑从代码后台(Code-behind)或 ViewModel 中解耦出来,从而提高代码的可维护性和复用性。
WPF 中的 Behavior 最初由 Microsoft Expression Blend SDK 引入,现在可以通过 Microsoft.Xaml.Behaviors.Wpf NuGet 包使用(适用于 .NET Core / .NET 5+ 及 .NET Framework)。
一、Behavior 的基本概念
- Behavior 是一个附加到 UI 元素(如 Button、TextBox 等)上的对象,用于监听该元素的事件并执行自定义逻辑。
- 它通过 Attached Property(附加属性) 机制实现,不破坏 MVVM 模式。
- 常见用途包括:双击选中文本、拖拽、焦点管理、输入验证、动画触发等。
二、安装依赖
在 .NET Core / .NET 5+ 项目中,需安装以下 NuGet 包:
bash
Install-Package Microsoft.Xaml.Behaviors.Wtf
注意:包名是
Microsoft.Xaml.Behaviors.Wpf(不是 Wtf 😄)
三、XAML 中使用 Behavior(声明式方式)
1. 引用命名空间
在 XAML 文件顶部添加命名空间引用:
xml
<Window xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
...>
2. 使用内置 Behavior 示例:CallMethodAction
xml
<Button Content="Click Me">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:CallMethodAction TargetObject="{Binding}" MethodName="OnButtonClick"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
注意:
CallMethodAction在较新版本中已被弃用,推荐使用InvokeCommandAction或自定义 Behavior。
四、自定义 Behavior
场景:让 TextBox 在获得焦点时自动全选文本
步骤 1:创建自定义 Behavior 类
csharp
using Microsoft.Xaml.Behaviors;
using System.Windows.Controls;
public class SelectAllTextOnFocusBehavior : Behavior<TextBox>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.GotFocus += OnGotFocus;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.GotFocus -= OnGotFocus;
}
private void OnGotFocus(object sender, System.Windows.RoutedEventArgs e)
{
AssociatedObject.SelectAll();
}
}
步骤 2:在 XAML 中使用
xml
<Window xmlns:local="clr-namespace:YourNamespace"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
<TextBox Text="Hello World">
<i:Interaction.Behaviors>
<local:SelectAllTextOnFocusBehavior />
</i:Interaction.Behaviors>
</TextBox>
</Window>
五、常用内置 Trigger 和 Action(来自 Behaviors SDK)
| 类型 | 说明 |
|---|---|
EventTrigger |
监听指定事件(如 Click、MouseEnter) |
DataTrigger |
当绑定数据满足条件时触发(需配合 Condition) |
InvokeCommandAction |
调用 ICommand(推荐替代 CallMethodAction) |
ChangePropertyAction |
修改目标对象的属性值 |
GoToStateAction |
触发 VisualStateManager 的状态切换 |
示例:点击按钮执行命令(MVVM 友好)
xml
<Button Content="Save">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding SaveCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
这比直接在 Button 上绑定
Command更灵活,可用于非 ICommand 支持的控件(如 ListView 的 SelectionChanged)。
六、Behavior 与 MVVM 的关系
- 优点 :
- 将 UI 交互逻辑从 ViewModel 中剥离,保持 ViewModel 纯净(无 UI 依赖)。
- 可复用、可测试、可组合。
- 适用场景 :
- 控件特定的交互(如自动滚动、焦点处理、拖放)。
- 无法通过标准绑定或命令实现的 UI 行为。
⚠️ 注意:不要把业务逻辑放进 Behavior,只放 UI 交互逻辑。
七、高级技巧
1. 带参数的 Behavior(依赖属性)
csharp
public class DelayedFocusBehavior : Behavior<FrameworkElement>
{
public static readonly DependencyProperty DelayProperty =
DependencyProperty.Register("Delay", typeof(int), typeof(DelayedFocusBehavior), new PropertyMetadata(0));
public int Delay
{
get => (int)GetValue(DelayProperty);
set => SetValue(DelayProperty, value);
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Loaded += OnLoaded;
}
private async void OnLoaded(object sender, RoutedEventArgs e)
{
await Task.Delay(Delay);
AssociatedObject.Focus();
}
}
XAML 使用:
xml
<TextBox>
<i:Interaction.Behaviors>
<local:DelayedFocusBehavior Delay="500" />
</i:Interaction.Behaviors>
</TextBox>
2. 多个 Behavior 组合
一个控件可以附加多个 Behavior:
xml
<TextBox>
<i:Interaction.Behaviors>
<local:SelectAllTextOnFocusBehavior />
<local:NumericInputOnlyBehavior />
<local:MaxLengthVisualFeedbackBehavior MaxLength="10" />
</i:Interaction.Behaviors>
</TextBox>
八、调试与注意事项
- Behavior 的生命周期由
OnAttached()和OnDetaching()控制,务必正确订阅/取消事件,避免内存泄漏。 - 如果 Behavior 未生效,检查:
- 是否正确引用命名空间;
- 是否安装了
Microsoft.Xaml.Behaviors.Wpf; - 控件是否已加载(某些操作需在 Loaded 后执行)。
总结
WPF 中的 Behavior 是实现 可复用、解耦的 UI 交互逻辑 的强大工具。它完美契合 MVVM 架构,让开发者既能保持 ViewModel 的纯净,又能灵活处理复杂的 UI 行为。
推荐实践:优先使用
InvokeCommandAction+ ICommand;复杂交互才自定义 Behavior。