Silverlight中实现自定义Cursor
Silverlight不同于WPF,自定义Cursor需要通过其它方式实现。我们可以为一个元素定义一个CursorBehavior,建议使用自定义Cursor的Panel为Canvas,否则需要对自定义的Cursor做TranslateTransform。附件Behavior的时候,为Canvas添加一个Image元素,默认Visibility为Collapsed。Image元素的ZIndex值要较大,这样可以确保始终在其它元素前面。订阅Canvas的MouseMove和MouseLeave事件,MouseMove事件产生后用来定位Image的坐标,而MouseLeave事件产生后用来隐藏Image。CursorBehavior的ContentPropertyAttribute的Name为Cursor便于在XAML中声明:
<localcontrols:Tablet x:Name=”tablet” Background=”Transparent” ItemWidth=”40″ ItemHeight=”40″> <interactivity:BehaviorService.Behavior> <interactivity:BehaviorGroup> <interactivity:CursorBehavior Cursor=”{StaticResource PenCursor}” CursorWidth=”19″ CursorHeight=”20″ /> </interactivity:BehaviorGroup> </interactivity:BehaviorService.Behavior> </localcontrols:Tablet>
新增一个CursorService的静态类用来GetCursor、SetCursor,由于CursorBehavior的Cursor属性在产生变化的时候会产生OnCursorChanged以更新Image的Source属性。
1 using System.Windows.ComponentModel; 2 using System.Windows.Controls; 3 using System.Windows.Input; 4 using System.Windows.Markup; 5 using System.Windows.Media; 6 7 namespace System.Windows.Interactivity 8 { 9 /// <summary> 10 /// 光标行为 11 /// </summary> 12 [ContentProperty("Cursor")] 13 public sealed class CursorBehavior : MouseBehavior 14 { 15 /// <summary> 16 /// 原缓存模式 17 /// </summary> 18 private CacheMode m_oldCacheMode; 19 /// <summary> 20 /// 原光标 21 /// </summary> 22 private Cursor m_oldCursor; 23 /// <summary> 24 /// 光标 25 /// </summary> 26 private Object m_cursor; 27 /// <summary> 28 /// 光标图片 29 /// </summary> 30 private Image m_cursorImage; 31 32 /// <summary> 33 /// 构造函数 34 /// </summary> 35 public CursorBehavior() { } 36 37 /// <summary> 38 /// 画布 39 /// </summary> 40 public Canvas Drawing 41 { 42 get 43 { 44 return (this.AssociatedObject as Canvas); 45 } 46 } 47 48 /// <summary> 49 /// 光标宽度 50 /// </summary> 51 public Double CursorWidth { get; set; } 52 53 /// <summary> 54 /// 光标高度 55 /// </summary> 56 public Double CursorHeight { get; set; } 57 58 /// <summary> 59 /// 鼠标 60 /// </summary> 61 public Object Cursor 62 { 63 get { return m_cursor; } 64 set 65 { 66 if (m_cursor != value) 67 { 68 m_cursor = value; 69 70 OnPropertyChanged(this, p => p.Cursor); 71 OnCursorChanged(EventArgs.Empty); 72 } 73 } 74 } 75 76 /// <summary> 77 /// 附加 78 /// </summary> 79 protected override void OnAttached() 80 { 81 base.OnAttached(); 82 83 Canvas canvas = this.Drawing; 84 if ((canvas.CacheMode == null) || (canvas.CacheMode.GetType() != typeof(BitmapCache))) 85 { 86 m_oldCacheMode = canvas.CacheMode; 87 canvas.CacheMode = new BitmapCache(); 88 } 89 90 m_oldCursor = canvas.Cursor; 91 canvas.Cursor = Cursors.None; 92 m_cursorImage = new Image(); 93 m_cursorImage.Visibility = Visibility.Collapsed; 94 m_cursorImage.Width = this.CursorWidth; 95 m_cursorImage.Height = this.CursorHeight; 96 97 OnCursorChanged(EventArgs.Empty); 98 Canvas.SetZIndex(m_cursorImage, Int16.MaxValue); 99 canvas.Children.Add(m_cursorImage); 100 } 101 102 /// <summary> 103 /// 分离 104 /// </summary> 105 protected override void OnDetach() 106 { 107 base.OnDetach(); 108 109 Canvas canvas = this.Drawing; 110 111 if (m_oldCacheMode != null) 112 canvas.CacheMode = m_oldCacheMode; 113 114 canvas.Cursor = m_oldCursor; 115 116 canvas.Children.Remove(m_cursorImage); 117 } 118 119 /// <summary> 120 /// 鼠标离开 121 /// </summary> 122 /// <param name=”e”>事件参数</param> 123 protected override void OnMouseLeave(MouseEventArgs2 e) 124 { 125 m_cursorImage.Visibility = Visibility.Collapsed; 126 } 127 128 /// <summary> 129 /// 鼠标移动 130 /// </summary> 131 /// <param name=”e”>事件参数</param> 132 protected override void OnMouseMove(MouseEventArgs2 e) 133 { 134 if (m_cursorImage.Visibility == Visibility.Collapsed) 135 m_cursorImage.Visibility = Visibility.Visible; 136 137 Point pos = e.GetPosition(this.Drawing); 138 139 Canvas.SetLeft(m_cursorImage, pos.X); 140 Canvas.SetTop(m_cursorImage, pos.Y – m_cursorImage.ActualHeight); 141 } 142 143 /// <summary> 144 /// 鼠标变化 145 /// </summary> 146 /// <param name=”e”>事件参数</param> 147 private void OnCursorChanged(EventArgs e) 148 { 149 if (m_cursorImage != null) 150 m_cursorImage.Source = (this.Cursor as ImageSource); 151 } 152 } 153 }
1 using System.Linq; 2 3 namespace System.Windows.Interactivity 4 { 5 /// <summary> 6 /// 光标服务 7 /// </summary> 8 public static class CursorService 9 { 10 /// <summary> 11 /// 获得光标 12 /// </summary> 13 /// <param name=”d”>对象</param> 14 /// <returns>光标</returns> 15 public static Object GetCursor(DependencyObject d) 16 { 17 CursorBehavior cursorBehavior = GetBehavior(d); 18 19 if (cursorBehavior != null) 20 return cursorBehavior.Cursor; 21 22 return null; 23 } 24 25 /// <summary> 26 /// 设置光标 27 /// </summary> 28 /// <param name=”d”>对象</param> 29 /// <param name=”value”>光标</param> 30 public static void SetCursor(DependencyObject d, Object value) 31 { 32 CursorBehavior cursorBehavior = GetBehavior(d); 33 34 if (cursorBehavior != null) 35 cursorBehavior.Cursor = value; 36 } 37 38 /// <summary> 39 /// 获取行为 40 /// </summary> 41 /// <param name=”d”>对象</param> 42 /// <returns>光标行为</returns> 43 private static CursorBehavior GetBehavior(DependencyObject d) 44 { 45 BehaviorBase behavior = BehaviorService.GetBehavior(d); 46 CursorBehavior cursorBehavior = (behavior as CursorBehavior); 47 48 if (cursorBehavior == null) 49 { 50 BehaviorGroup group = (behavior as BehaviorGroup); 51 52 cursorBehavior = group.Children.OfType<CursorBehavior>().FirstOrDefault(); 53 } 54 55 return cursorBehavior; 56 } 57 } 58 }