介绍
在讲解到样式的时候我们说,样式是为了一系列元素共享一些属性而存在的,归根结底是为了复用代码和逻辑,而我们学习了触发器之后,发现我们可以用触发器写一些简单的逻辑到样式中,但是这种简单的逻辑有时候远远不够。
当我们要实现一堆元素支持在Cancas上面拖放,停靠,缩放等功能的时候,触发器就显得不是那么够用了。
我们在复用代码的时候,有下面三种方法,他们互相补充,构建了WPF的属性重用架构,在合适的场景下选择合适的方法可以极大的简化我们的开发工作
- 样式,主要是属性的设置,用触发器写的简单的控件行为
- 自定义控件,为了满足某一功能编写的可以公用的专职控件
- 行为,封装了一些通用的用户界面功能的行为,可以是十分复杂的功能的集合,一旦创建成功,可以将这种构建好的行为用于任意一个其他控件中,十分的强大
依赖
行为的必须依赖 System.Windows.Interactivity,我们在使用的时候可以从网上下载后,添加打项目中,通过引用该dll,引入对于System.Windows.Interactivity的依赖。这一步也是必须的
编写行为
我们通过一个例子,直观的看一下行为能够做什么,为什么它比触发器更加的强大
我们就编写之前提到过的,我们要通过写一个行为,让一些原本很普通的控件具备在Canvas上被拖动的能力,行为的编写如下
public class DragInCanvasBehavior : Behavior<UIElement>
{
private Canvas canvas;
private bool isDragging = false;
private Point mouseOffset;
protected override void OnAttached()
{
base.OnAttached();
// 绑定事件处理
this.AssociatedObject.MouseLeftButtonDown += AssociatedObject_MouseLeftButtonDown;
this.AssociatedObject.MouseMove += AssociatedObject_MouseMove;
this.AssociatedObject.MouseLeftButtonUp += AssociatedObject_MouseLeftButtonUp;
}
private void AssociatedObject_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if (isDragging)
{
// 释放鼠标捕获
AssociatedObject.ReleaseMouseCapture();
isDragging = false;
}
}
private void AssociatedObject_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (isDragging)
{
// 获取控件在canvas上的位置
Point point = e.GetPosition(canvas);
// 移动鼠标的时候确定元素的新位置
AssociatedObject.SetValue(Canvas.TopProperty, point.Y - mouseOffset.Y);
AssociatedObject.SetValue(Canvas.LeftProperty, point.X - mouseOffset.X);
}
}
private void AssociatedObject_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
// 如果canvas不存在,查找canvas
if (canvas == null)
{
canvas = (Canvas)VisualTreeHelper.GetParent(this.AssociatedObject);
}
//开始拖动
isDragging = true;
// 获取鼠标点击控件开始拖动的起始位置
mouseOffset = e.GetPosition(AssociatedObject);
// 使得我们要拖动的元素持续的获取MouseMove事件
AssociatedObject.CaptureMouse();
}
protected override void OnDetaching()
{
base.OnDetaching();
// 移除事件处理
this.AssociatedObject.MouseLeftButtonDown -= AssociatedObject_MouseLeftButtonDown;
this.AssociatedObject.MouseMove -= AssociatedObject_MouseMove;
this.AssociatedObject.MouseLeftButtonUp -= AssociatedObject_MouseLeftButtonUp;
}
}
需要注意:
- 要使用行为,必须依赖 System.Windows.Interactivity
- 我们一般都是要复写 OnAttach 和 OnDetaching 两个方法,用于在组件关联以及解除关联的时候,进行事件的监听和移除监听
- 监听了我们感兴趣的事件之后,就可以在事件的处理方法之中写上控件的行为
写出了行为之后,我们需要将行为附加到元素上去,使用下面的方法
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d" Unloaded="Window_Unloaded"
Title="MainWindow" Height="450" Width="800">
<Canvas>
<Rectangle Canvas.Left="10" Canvas.Top="10" Fill="Yellow" Width="40" Height="60"></Rectangle>
<Ellipse Canvas.Left="10" Canvas.Top="70" Fill="Blue" Width="80" Height="60">
<i:Interaction.Behaviors>
<local:DragInCanvasBehavior></local:DragInCanvasBehavior>
</i:Interaction.Behaviors>
</Ellipse>
</Canvas>
</Window>
需要注意的是:
- xaml中同样需要引入 Interactivity
- 只需要简单的将行为附加于控件,就实现了行为中写入的功能,十分的方便
Blend 支持
我们在编程的时候,如果使用Blend构建页面,如果写过一个行为之后,可以在Blend的资产面板中找到这个行为,直接拖放,就可以给一个元素添加我们新写的行为。
版权声明:本文为nxy_wuhao原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。