WPF ListBox的橡皮筋选择行为

WPF应用程序中,ListBox控件通常用于显示项的列表。默认情况下,ListBox只允许单选。但是,通过设置ListBox的SelectionMode属性,可以使其支持多选。本文将介绍如何实现一个橡皮筋选择行为,允许用户通过拖拽来选择ListBox中的多个项目。此外,还将展示如何通过Expression Blend工具来添加此行为。

橡皮筋选择是一种用户界面交互方式,用户可以通过拖拽一个矩形区域来选择区域内的所有项目。这种交互方式在很多应用程序中都有应用,比如Windows资源管理器、macOS Finder等。在WPF中实现橡皮筋选择,可以提高用户操作的灵活性和效率。

项目结构

本示例项目的结构如下:

  • RubberBand项目包含相应的行为。RubberBand类持有渲染橡皮筋的UI逻辑。
  • RubberBandSelection是演示项目,其中包含支持多选的ListBox。

使用代码

本文将分为三个部分。首先是在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。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485