Microsoft.Xaml.Behaviors
是一个用于WPF(Windows Presentation Foundation)的行为库,它的主要作用是允许开发者在不修改控件源代码的情况下,为控件添加自定义的行为和交互逻辑。行为库的核心思想是通过定义可重用的行为组件,将交互逻辑与UI控件解耦,从而提高代码的可维护性和可复用性。
1. 增强控件功能
- 无需修改控件源码:在WPF中,控件的功能通常是固定的,但如果需要扩展控件的功能(例如为按钮添加双击事件、为文本框添加自动完成功能等),可以通过行为库来实现,而无需修改控件的源代码。
- 动态添加行为:行为可以动态地附加到控件上,并在运行时生效,非常适合需要灵活交互的场景。
2. 将交互逻辑与UI解耦
- 行为与UI分离:行为库使得交互逻辑与UI控件分离,开发者可以在不侵入控件代码的情况下,为控件添加自定义逻辑。
- 行为复用:一旦定义了一个行为,它可以被多次复用到不同的控件上,减少了重复代码的编写。
3. 简化复杂的交互逻辑
- 复杂交互的封装:某些复杂的交互逻辑(例如拖放操作、窗口关闭时的特殊处理、动画触发等)可以通过行为库封装为一个独立的行为,而不是直接写入控件的事件处理程序中。
- 避免事件处理代码膨胀:使用行为库可以将事件处理逻辑集中管理,避免在代码背后堆积大量的事件处理代码。
4. 支持MVVM模式
- MVVM的桥梁:在MVVM模式中,
Behavior
可以作为视图(View)和视图模型(ViewModel)之间的桥梁。行为可以直接绑定到ViewModel中的命令(ICommand
),从而将用户的交互操作(例如按钮点击、窗口关闭等)映射到ViewModel中的业务逻辑。 - 减少代码背后的复杂性:在MVVM中,行为可以代替代码背后的逻辑(例如事件处理程序),使得代码更加清晰和简洁。
5. 灵活性和可扩展性
- 自定义行为:开发者可以根据需求创建自定义的行为类,继承自
Behavior<T>
(其中T
是目标控件的类型,例如Button
、TextBox
、Window
等)。 - 内置行为:
Microsoft.Xaml.Behaviors
库还包含一些预定义的行为,例如EventTrigger
、InvokeCommandAction
等,可以直接使用。
6. 与XAML无缝集成
- 在XAML中使用行为:行为库可以与XAML无缝集成,开发者可以直接在XAML中为控件附加行为,而不需要编写C#代码。
<Button> <i:Interaction.Behaviors> <behaviors:MyCustomBehavior /> </i:Interaction.Behaviors> </Button>
- 绑定支持:行为可以绑定到ViewModel中的命令或属性,使得行为逻辑可以动态变化。
示例:使用行为库的场景
- 拖放操作:为控件添加拖放行为。
- 窗口关闭时的特殊处理:如您提供的代码示例,当窗口关闭时,可以执行自定义命令(例如隐藏窗口而不是关闭它)。
- 按钮双击事件:为按钮添加双击行为,而不需要修改按钮的默认行为。
- 动画触发:当某个事件发生时(例如鼠标悬停),触发控件的动画。
- 自动完成:为文本框添加自动完成行为。
窗口关闭时的特殊处理
附加属性快捷键 :
propdp
public static readonly DependencyProperty ClosingActionProperty =
DependencyProperty.Register(
"ClosingAction", // 属性名称
typeof(ICommand), // 属性类型
typeof(HideViewBehavior), // 属性的宿主类 这里指定依赖属性的宿主类是 HideViewBehavior,表示这个依赖属性是属于 HideViewBehavior 类的。
new PropertyMetadata(null) // 属性元数据 默认值为null
);
using CommunityToolkit.Mvvm.Input;
using Microsoft.Xaml.Behaviors;
using System.Windows;
using System.Windows.Input;
namespace BehaviorsModule
{
public class HideViewBehavior : Behavior<Window>
{
public ICommand ClosingAction
{
get { return (ICommand)GetValue(ClosingActionProperty); }
set { SetValue(ClosingActionProperty, value); }
}
public static readonly DependencyProperty ClosingActionProperty =
DependencyProperty.Register("ClosingAction", typeof(ICommand), typeof(HideViewBehavior), new PropertyMetadata(null));
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Closing += AssociatedObject_Closing;
}
private void AssociatedObject_Closing(object? sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
if (ClosingAction != null)
{
ClosingAction.Execute(new object());
}
}
}
}
给控件添加拖放操作
using Microsoft.Xaml.Behaviors;
using System.Windows;
using System.Windows.Input;
namespace BehaviorsModule
{
public class MoveViewBehavior: Behavior<Window>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.PreviewMouseDown += AssociatedObject_PreviewMouseDown;
AssociatedObject.PreviewMouseMove += AssociatedObject_PreviewMouseMove;
AssociatedObject.PreviewMouseLeftButtonUp += AssociatedObject_PreviewMouseLeftButtonUp;
}
private void AssociatedObject_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (_isDragMoved)
{
_isDragMoved = false;
e.Handled = true;
}
}
private void AssociatedObject_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (Mouse.LeftButton == MouseButtonState.Pressed && _pressedPosition != e.GetPosition(AssociatedObject))
{
_isDragMoved = true;
AssociatedObject.DragMove();
}
}
Point _pressedPosition;
bool _isDragMoved = false;
private void AssociatedObject_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
_pressedPosition = e.GetPosition(AssociatedObject);
}
}
}
初始化窗体位置
public class InitViewPostionBehavior : Behavior<Window>
{
public double xp
{
get
{
return (double)GetValue(xpProperty);
}
set { SetValue(xpProperty, value); }
}
// Using a DependencyProperty as the backing store for xp. This enables animation, styling, binding, etc...
public static readonly DependencyProperty xpProperty =
DependencyProperty.Register("xp", typeof(double), typeof(InitViewPostionBehavior), new PropertyMetadata(0.0));
public double yp
{
get
{ return (double)GetValue(ypProperty); }
set { SetValue(ypProperty, value); }
}
// Using a DependencyProperty as the backing store for yp. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ypProperty =
DependencyProperty.Register("yp", typeof(double), typeof(InitViewPostionBehavior), new PropertyMetadata(0.0));
private void InitializeFormPosition()
{
var workingArea = SystemParameters.WorkArea;
double screenWidth = workingArea.Width;
double screenHeight = workingArea.Height;
double x = screenWidth / xp;
double y = screenHeight / yp;
AssociatedObject.Left = x;
AssociatedObject.Top = y;
}
protected override void OnAttached()
{
base.OnAttached();
InitializeFormPosition();
}
}