众所周知,Silverlight默认并不支持右键点击和滚轮操作。微软曾经在它的DeepZoom解决方案中给出了一套对于滚轮操作的支持方案(包括一个Helper类,其实中含有NestedType,还有一个EventArgs类),但是至今仍然没有比较正式的对于右键的支持,所以我依照微软的思路,做了对于右键支持的通用类,希望能够对大家有所帮助。今天要介绍的,是这个通用方法的全局侦测的版本,即无论用户点击Application内的哪个元素,都全触发事件,至于是否处理,则交给程序员判断。还有一个为特定UI元素监视右键点击的模式,我会在下一篇中介绍。无疑下一个版本将更加面向对象,但是我认为这个版本也是有一定价值的。
首先,在HostPage中设置Silverlight对象的WindowLess属性为true,在asp.net中:
<
asp:Silverlight
ID
="Xaml1"
Windowless
="true"
runat
="server"
Windowless
="true"
Source
="~/ClientBin/MyApp.xap"
MinimumVersion
="2.0.31005.0"
Width
="100%"
Height
="100%"
/>
在Html中:
![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzUvMC80LzYvMjgvOTMxMGU4NWExNGFmOTlkZTQ4MTFmZjRjNzdmMWY5MTEuanBl.jpe?w=700&webp=1)
Code
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2"
width="100%" height="100%">
<param name="source" value="ClientBin/MyApp.xap" />
<param name="onerror" value="onSilverlightError" />
<param name="background" value="white" />
<param name="minRuntimeVersion" value="2.0.31005.0" />
<param name="autoUpgrade" value="true" />
<param name="Windowless" value="true" />
<a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;">
<img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none" />
</a>
</object>
这样,余下的工作就可以通过Silverlight中ManagedCode同Javascript的操作来实现了。在这里,首先提出一个类,它能帮助我们计算出任何一个UIElement从Application的RootVisual的平移值。这个类我写成了静态类,并且写成Extension Method,其实用普通的静态类,同样也是可行的。
![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzUvMC80LzYvMjgvOTMxMGU4NWExNGFmOTlkZTQ4MTFmZjRjNzdmMWY5MTEuanBl.jpe?w=700&webp=1)
Code
1
public static class GlobalTransform
2![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzAvNC83LzIvMzEvMjRhOTI0YTU3YmE2YjNmMmI1MWZjOWVkYjdlYTQxODYuanBl.jpe?w=700&webp=1)
{
3
private static readonly Point Origin = new Point(0, 0);
4
public static Point TransformFromRootVisual(this UIElement element)
5![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzQvNC82LzIvNzYvNzE1ZjJkMDU1MDNiOTlkNDFmM2I2YmEyY2RjY2M4NGQuanBl.jpe?w=700&webp=1)
{
6
UIElement uiElement = Application.Current.RootVisual;
7
if (uiElement == null)
8
throw new InvalidOperationException();
9
MatrixTransform globalTransform = (MatrixTransform)element.TransformToVisual(uiElement);
10
Point p = globalTransform.Matrix.Transform(Origin);
11
return p;
12
}
13
}
然后,我介绍一下EventArgs类。其实这个类,只不过是传递了鼠标在Silverlight Application上点击点的绝对定位值,为了方便起见,我在里面加入了几个方法,包括命中测试和被点击到的所有UIElement的可遍历集合。
1
public
sealed
class
MouseRightClickEventArgs : EventArgs
2
![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzAvNC83LzIvMzEvMjRhOTI0YTU3YmE2YjNmMmI1MWZjOWVkYjdlYTQxODYuanBl.jpe?w=700&webp=1)
{
3
internal MouseRightClickEventArgs(double x, double y)
4![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzQvNC82LzIvNzYvNzE1ZjJkMDU1MDNiOTlkNDFmM2I2YmEyY2RjY2M4NGQuanBl.jpe?w=700&webp=1)
{
5
m_XOffset = x;
6
m_YOffset = y;
7
}
8![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzgvNi8zLzQvODEvMTQwOGM1MjYwYjJmMDVlNDUwZGVlOTI5ZGI5YmU1ZjcuanBl.jpe?w=700&webp=1)
9
private double m_XOffset;
10
private double m_YOffset;
11![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzgvNi8zLzQvODEvMTQwOGM1MjYwYjJmMDVlNDUwZGVlOTI5ZGI5YmU1ZjcuanBl.jpe?w=700&webp=1)
12
public Point GetPosition(UIElement relativeTo)
13![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzQvNC82LzIvNzYvNzE1ZjJkMDU1MDNiOTlkNDFmM2I2YmEyY2RjY2M4NGQuanBl.jpe?w=700&webp=1)
{
14
if (relativeTo != null)
15![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzQvNC82LzIvNzYvNzE1ZjJkMDU1MDNiOTlkNDFmM2I2YmEyY2RjY2M4NGQuanBl.jpe?w=700&webp=1)
{
16
Point p = relativeTo.TransformFromRootVisual();
17
return new Point(m_XOffset - p.X, m_YOffset - p.Y);
18
}
19
return new Point(m_XOffset, m_YOffset);
20
}
21![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzgvNi8zLzQvODEvMTQwOGM1MjYwYjJmMDVlNDUwZGVlOTI5ZGI5YmU1ZjcuanBl.jpe?w=700&webp=1)
22
public IEnumerable<UIElement> FindElementsInHitPoint()
23![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzQvNC82LzIvNzYvNzE1ZjJkMDU1MDNiOTlkNDFmM2I2YmEyY2RjY2M4NGQuanBl.jpe?w=700&webp=1)
{
24
return VisualTreeHelper.FindElementsInHostCoordinates(GetPosition(null), Application.Current.RootVisual);
25
}
26![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzgvNi8zLzQvODEvMTQwOGM1MjYwYjJmMDVlNDUwZGVlOTI5ZGI5YmU1ZjcuanBl.jpe?w=700&webp=1)
27
public bool HitTest(UIElement relativeTo)
28![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzQvNC82LzIvNzYvNzE1ZjJkMDU1MDNiOTlkNDFmM2I2YmEyY2RjY2M4NGQuanBl.jpe?w=700&webp=1)
{
29
foreach (UIElement element in FindElementsInHitPoint())
30![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzQvNC82LzIvNzYvNzE1ZjJkMDU1MDNiOTlkNDFmM2I2YmEyY2RjY2M4NGQuanBl.jpe?w=700&webp=1)
{
31
if (element == relativeTo)
32
return true;
33
}
34
return false;
35
}
36![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzgvNi8zLzQvODEvMTQwOGM1MjYwYjJmMDVlNDUwZGVlOTI5ZGI5YmU1ZjcuanBl.jpe?w=700&webp=1)
37
private bool m_Handled;
38
// Summary:
39
// If you don't want to see the Silverlight Configuration,
40
// set it as true
41
public bool Handled
42![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzQvNC82LzIvNzYvNzE1ZjJkMDU1MDNiOTlkNDFmM2I2YmEyY2RjY2M4NGQuanBl.jpe?w=700&webp=1)
{
43![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzQvNC82LzIvNzYvNzE1ZjJkMDU1MDNiOTlkNDFmM2I2YmEyY2RjY2M4NGQuanBl.jpe?w=700&webp=1)
get
{ return this.m_Handled; }
44![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzQvNC82LzIvNzYvNzE1ZjJkMDU1MDNiOTlkNDFmM2I2YmEyY2RjY2M4NGQuanBl.jpe?w=700&webp=1)
set
{ this.m_Handled = value; }
45
}
46
}
剩余的任务,就是向Javascript中AttachEvent:
1
public
sealed
class
RightClickHelper:IDisposable
2
![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzAvNC83LzIvMzEvMjRhOTI0YTU3YmE2YjNmMmI1MWZjOWVkYjdlYTQxODYuanBl.jpe?w=700&webp=1)
{
3
public event EventHandler<MouseRightClickEventArgs> RightClick;
4
public RightClickHelper()
5![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzQvNC82LzIvNzYvNzE1ZjJkMDU1MDNiOTlkNDFmM2I2YmEyY2RjY2M4NGQuanBl.jpe?w=700&webp=1)
{
6
//if (!(Application.Current.Host.Settings.Windowless && HtmlPage.IsEnabled))
7
//throw new NotSupportedException("Must set the Windowless of the plug-in as true");
8
HtmlPage.Document.AttachEvent("oncontextmenu", this.OnContextMenu);
9
}
10![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzgvNi8zLzQvODEvMTQwOGM1MjYwYjJmMDVlNDUwZGVlOTI5ZGI5YmU1ZjcuanBl.jpe?w=700&webp=1)
11
private void OnContextMenu(object sender, HtmlEventArgs e)
12![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzQvNC82LzIvNzYvNzE1ZjJkMDU1MDNiOTlkNDFmM2I2YmEyY2RjY2M4NGQuanBl.jpe?w=700&webp=1)
{
13
if (RightClick != null)
14![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzQvNC82LzIvNzYvNzE1ZjJkMDU1MDNiOTlkNDFmM2I2YmEyY2RjY2M4NGQuanBl.jpe?w=700&webp=1)
{
15
MouseRightClickEventArgs evtArgs = new MouseRightClickEventArgs(e.OffsetX, e.OffsetY);
16
RightClick(this, evtArgs);
17
if (evtArgs.Handled)
18
e.PreventDefault();
19
}
20
}
21![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzgvNi8zLzQvODEvMTQwOGM1MjYwYjJmMDVlNDUwZGVlOTI5ZGI5YmU1ZjcuanBl.jpe?w=700&webp=1)
22![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzUvNS81LzcvNzMvZTA4M2RmZGU1YTkxZjUwOTc5ZmU4OTc5YjQwMTJiOWQuanBl.jpe?w=700&webp=1)
IDisposable Members#region IDisposable Members
23
public void Dispose()
24![My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本) My Silverlight系列(11)—— Silverlight中的右键事件点击模拟(全局版本)](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9pbWdzLzQvNC82LzIvNzYvNzE1ZjJkMDU1MDNiOTlkNDFmM2I2YmEyY2RjY2M4NGQuanBl.jpe?w=700&webp=1)
{
25
HtmlPage.Document.DetachEvent("oncontextmenu", this.OnContextMenu);
26
}
27
#endregion
28
}
这样,创建一个RightClickHelper的对象,它将侦测全局的右键点击事件,然后将它们提交给程序员,程序员可调用RightClickEventArgs中的方法进行命中测试,并且判断这次点击是否受理。上面提到的为特点的UI元素加入右键点击的帮助类,只是将EventArgs中的相应方法封装进去,在类内部做出判断后再提交给程序员。这种更加面向对象的方式,我将会在下一篇文章中给出。