您的位置:首页 > 产品设计 > UI/UE

使用扩展方法对代码的行为进行封装的例子:封装UIElement的“拖动”

2010-11-10 17:22 891 查看
很多情况下,我们需要对界面上的元素进行拖动,用鼠标在VS中biaji,biaji,biaji,点几个事件,然后再写出一堆代码,浪费时间不说,由IDE自动生成的那些代码实在是太难看,影响心情。本文使用扩展方法,对于这类行为需要进行封装,以使代码更简单简洁。

封装原则如下:

(1)要简单,最好是一行代码就搞定;

(2)要强大,能用于尽量多的类;

(3)要灵活,可适用于尽量多的场景。

在本文的末尾添加了修改版,修改版代码更简洁,操作更简单,且可以设置多个拖动逻辑。

====

设计下面的扩展方法原型:


public static void SetDraggable(this UIElement element, IInputElement relativeTo, Action<DraggableContext> moveCallback = null, Action<DraggableContext> beforeDragCallback = null, Action<DraggableContext> afterDragCallback = null)


element 是拖动的界面元素,relativeTo 是参照物,moveCallback 是移动过程中的回调方法。DraggableContext 是一个类,包装了调用方所需要的信息。beforeDragCallback 是拖动前的处理,假设要拖动一个TextBlock,拖动前可以将它改变颜色,以示醒目。afterDragCallback 是拖动结束后的处理。

DraggableContext 的代码为:


public class DraggableContext
{
public DependencyObject Owner { get; private set; }
public IInputElement RelativeTo { get; private set; }
public Point StartPoint { get; internal set; }
public Point EndPoint { get; internal set; }

public Point Offset
{
get { return new Point { X = EndPoint.X - StartPoint.X, Y = EndPoint.Y - StartPoint.Y }; }
}

private Boolean _dragging;

public Boolean Dragging
{
get { return _dragging; }
internal set
{
if (value != _dragging)
{
_dragging = value;
if (value == true)
{
if (BeforeDragCallback != null)
BeforeDragCallback(this);
}
else
{
if (AfterDragCallback != null)
AfterDragCallback(this);
}
}
}
}

public Action<DraggableContext> MoveCallback { get; private set; }

public Action<DraggableContext> BeforeDragCallback { get; private set; }

public Action<DraggableContext> AfterDragCallback { get; private set; }

public DraggableContext(DependencyObject owner, IInputElement relativeTo, Action<DraggableContext> moveCallback = null, Action<DraggableContext> beforeDragCallback = null, Action<DraggableContext> afterDragCallback = null)
{
Owner = owner;
RelativeTo = relativeTo;
MoveCallback = moveCallback;
BeforeDragCallback = beforeDragCallback;
AfterDragCallback = afterDragCallback;
}

public override int GetHashCode()
{
return Owner.GetHashCode();
}
}


然后,还需要一个Dictionary,来储存所有的调用者:

  private static Dictionary<Object, DraggableContext> _dicDragContext = new Dictionary<Object, DraggableContext>();

然后,是对拖动逻辑的实现:


public static void SetDraggable(this UIElement element, IInputElement relativeTo, Action<DraggableContext> moveCallback = null, Action<DraggableContext> beforeDragCallback = null, Action<DraggableContext> afterDragCallback = null)
{
if (element == null) throw new ArgumentNullException("element");

_dicDragContext[element] = new DraggableContext(element, relativeTo, moveCallback, beforeDragCallback, afterDragCallback);
element.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(element_MouseLeftButtonDown);
element.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(element_MouseLeftButtonUp);
element.MouseLeave += new System.Windows.Input.MouseEventHandler(element_MouseLeave);
element.MouseMove += new System.Windows.Input.MouseEventHandler(element_MouseMove);
}

private static void element_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
_dicDragContext[sender].Dragging = false;
}

private static void element_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
DraggableContext ctx = _dicDragContext[sender];
ctx.Dragging = true;
ctx.StartPoint = e.GetPosition(ctx.RelativeTo);
ctx.EndPoint = ctx.StartPoint;
}

private static void element_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
_dicDragContext[sender].Dragging = false;
}

private static void element_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
DraggableContext ctx = _dicDragContext[sender];
if (ctx.Dragging == true)
{
ctx.Dragging = true;
ctx.EndPoint = e.GetPosition(ctx.RelativeTo);
if (ctx.MoveCallback != null)
{
ctx.MoveCallback(ctx);
}
ctx.StartPoint = ctx.EndPoint;
}
}


最后,还需要提供一个扩展方法清除对对象和事件的引用,以避免出现内存泄漏。这个方法需要显示调用。


public static void UnsetDraggable(this UIElement element)
{
element.MouseLeftButtonDown -= new System.Windows.Input.MouseButtonEventHandler(element_MouseLeftButtonDown);
element.MouseLeftButtonUp -= new System.Windows.Input.MouseButtonEventHandler(element_MouseLeftButtonUp);
element.MouseLeave -= new System.Windows.Input.MouseEventHandler(element_MouseLeave);
element.MouseMove -= new System.Windows.Input.MouseEventHandler(element_MouseMove);

if (_dicDragContext.ContainsKey(element)) _dicDragContext.Remove(element);
}


完整代码如下:

代码

1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Windows;
6 using System.Windows.Controls;
7
8 namespace Orc.Util
9 {
10 public class DraggableContext
11 {
12 public DependencyObject Owner { get; private set; }
13 public IInputElement RelativeTo { get; private set; }
14 public Point StartPoint { get; internal set; }
15 public Point EndPoint { get; internal set; }
16
17 public Point Offset
18 {
19 get { return new Point { X = EndPoint.X - StartPoint.X, Y = EndPoint.Y - StartPoint.Y }; }
20 }
21
22 private Boolean _dragging;
23
24 public Boolean Dragging
25 {
26 get { return _dragging; }
27 internal set
28 {
29 if (value != _dragging)
30 {
31 _dragging = value;
32 if (value == true)
33 {
34 if (BeforeDragCallback != null)
35 BeforeDragCallback(this);
36 }
37 else
38 {
39 if (AfterDragCallback != null)
40 AfterDragCallback(this);
41 }
42 }
43 }
44 }
45
46 internal void element_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
47 {
48 this.Dragging = false;
49 }
50
51 internal void element_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
52 {
53 this.Dragging = true;
54 this.StartPoint = e.GetPosition(this.RelativeTo);
55 this.EndPoint = this.StartPoint;
56 }
57
58 internal void element_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
59 {
60 this.Dragging = false;
61 }
62
63 internal void element_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
64 {
65 if (this.Dragging == true)
66 {
67 this.Dragging = true;
68 this.EndPoint = e.GetPosition(this.RelativeTo);
69 if (this.MoveCallback != null)
70 {
71 this.MoveCallback(this);
72 }
73 this.StartPoint = this.EndPoint;
74 }
75 }
76
77 public Action<DraggableContext> MoveCallback { get; private set; }
78
79 public Action<DraggableContext> BeforeDragCallback { get; private set; }
80
81 public Action<DraggableContext> AfterDragCallback { get; private set; }
82
83 public DraggableContext(DependencyObject owner, IInputElement relativeTo, Action<DraggableContext> moveCallback = null, Action<DraggableContext> beforeDragCallback = null, Action<DraggableContext> afterDragCallback = null)
84 {
85 Owner = owner;
86 RelativeTo = relativeTo;
87 MoveCallback = moveCallback;
88 BeforeDragCallback = beforeDragCallback;
89 AfterDragCallback = afterDragCallback;
90 }
91
92 public override int GetHashCode()
93 {
94 return Owner.GetHashCode();
95 }
96
97 public static void MoveOnCanvas(DraggableContext ctx)
98 {
99 Canvas cvs = ctx.RelativeTo as Canvas;
100 if (cvs == null) throw new NotSupportedException("RelativeTo 必须是 Canvas");
101 ctx.Owner.SetValue(Canvas.TopProperty, (double)(ctx.Owner.GetValue(Canvas.TopProperty)) + ctx.Offset.X);
102 ctx.Owner.SetValue(Canvas.LeftProperty, (double)(ctx.Owner.GetValue(Canvas.LeftProperty)) + ctx.Offset.Y);
103 }
104 }
105
106 public static class ClassHelper
107 {
108 public static void SetDraggable(this UIElement element, IInputElement relativeTo, Action<DraggableContext> moveCallback = null, Action<DraggableContext> beforeDragCallback = null, Action<DraggableContext> afterDragCallback = null)
109 {
110 if (element == null) throw new ArgumentNullException("element");
111 DraggableContext ctx = new DraggableContext(element, relativeTo, moveCallback, beforeDragCallback, afterDragCallback);
112 element.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(ctx.element_MouseLeftButtonDown);
113 element.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(ctx.element_MouseLeftButtonUp);
114 element.MouseLeave += new System.Windows.Input.MouseEventHandler(ctx.element_MouseLeave);
115 element.MouseMove += new System.Windows.Input.MouseEventHandler(ctx.element_MouseMove);
116 }
117 }
118 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐