在WPF应用程序中,ListBox控件通常用于显示项的列表。默认情况下,ListBox只允许单选。但是,通过设置ListBox的SelectionMode属性,可以使其支持多选。本文将介绍如何实现一个橡皮筋选择行为,允许用户通过拖拽来选择ListBox中的多个项目。此外,还将展示如何通过Expression Blend工具来添加此行为。
橡皮筋选择是一种用户界面交互方式,用户可以通过拖拽一个矩形区域来选择区域内的所有项目。这种交互方式在很多应用程序中都有应用,比如Windows资源管理器、macOS Finder等。在WPF中实现橡皮筋选择,可以提高用户操作的灵活性和效率。
本示例项目的结构如下:
本文将分为三个部分。首先是在WPF4.0中创建自定义行为。其次是在窗口中渲染橡皮筋装饰器。最后是如何在Expression Blend资产中添加行为以供重用。
行为用于将简单的功能封装到一个单独的组件中,以便于重用。行为可以与任何WPF对象关联,为控件提供额外的行为。例如,拖放、输入验证、平移和缩放、重新定位元素等。可能的行为列表非常长。
可以通过继承System.Windows.Interactivity.Behavior类来创建自定义行为。
public class RubberBandBehavior : Behavior<ListBox>
{
protected override void OnAttached()
{
AssociatedObject.Loaded += new System.Windows.RoutedEventHandler(AssociatedObject_Loaded);
base.OnAttached();
}
void AssociatedObject_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
RubberBandAdorner band = new RubberBandAdorner(AssociatedObject);
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(AssociatedObject);
adornerLayer.Add(band);
}
protected override void OnDetaching()
{
AssociatedObject.Loaded -= new System.Windows.RoutedEventHandler(AssociatedObject_Loaded);
base.OnDetaching();
}
}
通过继承Adorner类创建橡皮筋装饰器。装饰器是一种特殊类型的FrameworkElement,用于向用户提供视觉提示。装饰器可以用于向元素添加功能句柄或提供控件的状态信息。
装饰器在AdornerLayer中渲染,这是一个始终位于被装饰元素或一组被装饰元素顶部的渲染表面。装饰器的渲染与它所绑定的UIElement的渲染是独立的。装饰器通常使用位于被装饰元素左上角的标准2D坐标原点相对于它所绑定的元素进行定位。
public RubberBandAdorner(UIElement adornedElement) : base(adornedElement)
{
}
// 绑定装饰器到特定的UIElement的步骤:
1. 调用静态方法GetAdornerLayer获取要装饰的UIElement的AdornerLayer对象。GetAdornerLayer从指定的UIElement开始遍历视觉树,并返回找到的第一个装饰器层。(如果没有找到装饰器层,该方法返回null。)
2. 调用Add方法将装饰器绑定到目标UIElement。
RubberBandAdorner band = new RubberBandAdorner(AssociatedObject);
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(AssociatedObject);
adornerLayer.Add(band);
订阅鼠标按下和鼠标移动事件,获取起始点和当前点。使用OnRender重写方法来渲染视觉。
protected override void OnRender(DrawingContext drawingContext)
{
Rect rect = new Rect(startpoint, currentpoint);
drawingContext.DrawGeometry(brush, new Pen(SystemColors.HighlightBrush, 1), new RectangleGeometry(rect));
base.OnRender(drawingContext);
}
基本思想是在移动鼠标时,计算鼠标的当前位置,并在ListBox上绘制橡皮筋装饰器。OnRender重写方法可以通过使用InvalidateVisual()手动调用。在每次鼠标移动时,确定橡皮筋矩形内的ListBox项,并使其被选中。
foreach (var obj in _selector.Items)
{
ListBoxItem item = _selector.ItemContainerGenerator.ContainerFromItem(obj) as ListBoxItem;
if (item != null)
{
Point point = item.TransformToAncestor(AdornedElement).Transform(new Point(0, 0));
Rect bandrect = new Rect(startpoint, currentpoint);
Rect elementrect = new Rect(point.X, point.Y, item.ActualWidth, item.ActualHeight);
if (bandrect.IntersectsWith(elementrect))
{
item.IsSelected = true;
}
else
{
item.IsSelected = false;
}
}
}
将RubberBand.dll复制到以下位置:
C:\Program Files (x86)\Microsoft SDKs\Expression\Blend\.NETFramework\v4.0\Libraries
1. 打开Expression Blend。
2. 创建一个新的WPF项目。
3. 打开Assets -> Behaviors面板。将在列表中找到RubberBandBehavior。