Silverlight 自定义鼠标

在现在的Silverlight项目中,客户要求鼠标在可拖动面板上时为手形,拖动时为抓形。无奈Silverlight还不支持这个,只能自动动手做了。

自定义鼠标的思路就是把原始鼠标隐藏,然后做一个图片,跟着鼠标的位置移动,并在事件中改变图片,就是我们想要的自定义鼠标效果了。这个东西说起来简单,做起来并不那么容易,思路总是不容易理清。特别是嵌套元素都自定义了鼠标样式时,到底取谁的样式就成了一个问题了,还要考虑效率问题。

参考了网上两篇文章:

http://www.codeproject.com/KB/silverlight/SilverlightCustomCursors.aspx

http://www.cnblogs.com/dino623/archive/2010/04/01/1702260.html

看了codeproject上的那篇文章,发现在我们的项目中很合适,主要是简单。 就是有些bug,比如在程序中改变鼠标样式都不行,嵌套元素就出问题。 嵌套的问题当然是取最上层的那个元素了。主要代码如下:

View Code
public class CursorSet
{
const string ImagePath = "/Resources/Cursors/";

internal static Point? mousePoint;
internal static Popup Popup;
internal static Canvas AdornerLayer;
internal static List<string> IDs;
internal static Dictionary<FrameworkElement, ContentControl> ActiveElements;
internal static UIElement currentElement;
internal static Point currentPoint;

#region public string ID (attached)

public static string GetID(DependencyObject d)
{
return (string)d.GetValue(IDProperty);
}

public static void SetID(DependencyObject d, string id)
{
d.SetValue(IDProperty, id);
}

public static readonly DependencyProperty IDProperty = DependencyProperty.RegisterAttached(
"ID",
typeof(string),
typeof(CursorSet),
new PropertyMetadata(new PropertyChangedCallback(OnIDPropertyChanged)));

static void OnIDPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement element
= d as FrameworkElement;
string oldId = e.OldValue as string;
string newId = e.NewValue as string;
Cursor cursor;

if (e.OldValue != null)
{
AdornerLayer.Children.Clear();
}

if(IsValidID(newId))
{
if(IsSystemType(newId, out cursor))
{
element.Cursor
= cursor;
if (ActiveElements.ContainsKey(element))
ActiveElements[element]
= null;
else
{
ActiveElements.Add(element,
null);
AddMouseEventHandlers(element);
}
}
else
{
ContentControl customCursor
= CreateControl(newId);
if(ActiveElements.ContainsKey(element))
ActiveElements[element]
= customCursor;
else
{
ActiveElements.Add(element, customCursor);
AddMouseEventHandlers(element);
}

if (mousePoint.HasValue)
{
ShowCursor(element, mousePoint.Value);
}
}
}
else
{
element.Cursor
= null;
RemoveMouseEventHandlers(element);
if(ActiveElements.ContainsKey(element))
ActiveElements.Remove(element);
}
}

#endregion

static CursorSet()
{
IDs
= new List<string>();
ActiveElements
= new Dictionary<FrameworkElement, ContentControl>();

IDs.Add(
"Cross");
IDs.Add(
"SizeAll");
IDs.Add(
"Fist");
IDs.Add(
"Palm");

Application.Current.Host.Content.Resized
+= OnContentResized;
}

static ContentControl CreateControl(string id)
{
if(string.IsNullOrEmpty(id) || IDs == null || !IDs.Contains(id))
return new ContentControl();

Image image
= new Image()
{
Margin
= new Thickness(-12, -12, 0, 0),
Source
= new BitmapImage(
new Uri(string.Format("/{0};component{1}{2}.png", typeof(CursorSet).Namespace, ImagePath, id), UriKind.Relative))
};

Canvas canvas
= new Canvas();
canvas.Children.Add(image);

return new ContentControl { Content = canvas };
}

static bool IsValidID(string id)
{
Cursor cursor;

if(IsSystemType(id, out cursor))
return true;

return IDs.Contains(id);
}

static bool IsSystemType(string id, out Cursor cursor)
{
cursor
= null;

if(string.IsNullOrEmpty(id))
return true;

switch(id)
{
case "Arrow":
cursor
= Cursors.Arrow;
return true;
case "Eraser":
cursor
= Cursors.Eraser;
return true;
case "Hand":
cursor
= Cursors.Hand;
return true;
case "IBeam":
cursor
= Cursors.IBeam;
return true;
case "None":
cursor
= Cursors.None;
return true;
case "SizeNS":
cursor
= Cursors.SizeNS;
return true;
case "SizeWE":
cursor
= Cursors.SizeWE;
return true;
case "Stylus":
cursor
= Cursors.Stylus;
return true;
case "Wait":
cursor
= Cursors.Wait;
return true;
}

return false;
}

static void OnContentResized(object sender, EventArgs e)
{
if(AdornerLayer != null)
{
AdornerLayer.Width
= Application.Current.Host.Content.ActualWidth;
AdornerLayer.Height
= Application.Current.Host.Content.ActualHeight;
}
}

static void EnsurePopup()
{
if(Popup == null || AdornerLayer == null)
{
AdornerLayer
= new Canvas()
{
IsHitTestVisible
= false,
Width
= Application.Current.Host.Content.ActualWidth,
Height
= Application.Current.Host.Content.ActualHeight
};

Popup
= new Popup
{
IsHitTestVisible
= false,
Child
= AdornerLayer
};
}
}

static void AddMouseEventHandlers(FrameworkElement element)
{
element.MouseEnter
+= OnElementMouseEnter;
element.MouseMove
+= OnElementMouseMove;
element.MouseLeave
+= OnElementMouseLeave;
}

static void RemoveMouseEventHandlers(FrameworkElement element)
{
element.MouseEnter
-= OnElementMouseEnter;
element.MouseMove
-= OnElementMouseMove;
element.MouseLeave
-= OnElementMouseLeave;
}

static void OnElementMouseEnter(object sender, MouseEventArgs e)
{
ShowCursor(sender
as FrameworkElement, e.GetPosition(null));
}

static void OnElementMouseMove(object sender, MouseEventArgs e)
{
FrameworkElement element
= sender as FrameworkElement;
Point newPoint
= e.GetPosition(null);
//Debug.WriteLine(string.Format("{0}:{1} - {2}", element.Name, CursorSet.GetID(element), newPoint));

if (newPoint != currentPoint)
{
currentPoint
= newPoint;
currentElement
= VisualTreeHelper.FindElementsInHostCoordinates(newPoint, element).Where(f => { return !string.IsNullOrEmpty(CursorSet.GetID(f)); }).FirstOrDefault();
}

if (currentElement == element)
{
ShowCursor(element, newPoint);
}
}

static void OnElementMouseLeave(object sender, MouseEventArgs e)
{
FrameworkElement element
= sender as FrameworkElement;
ContentControl control
= ActiveElements[element];
if (control == null) return;

element.Cursor
= null;
AdornerLayer.Children.Remove(control);

Popup.IsOpen
= false;
mousePoint
= null;
}

static void ShowCursor(FrameworkElement element, Point point)
{
ContentControl customCursor
= ActiveElements[element];
if (customCursor == null) return;

EnsurePopup();
element.Cursor
= Cursors.None;
if (!AdornerLayer.Children.Contains(customCursor))
{
AdornerLayer.Children.Clear();
AdornerLayer.Children.Add(customCursor);
}

Canvas.SetTop(customCursor, point.Y);
Canvas.SetLeft(customCursor, point.X);

Popup.IsOpen
= true;
mousePoint
= point;
}
}

不知道博客园的silveright demo 是如何插入的,我在html中编辑之后发布,总是被改掉了,无法显示。

源代码下载

posted @ 2011-05-09 01:15  DevinShaw  阅读(605)  评论(1编辑  收藏  举报