如何在 MVVM Silverlight 4.0 应用程序中禁用右键单击时出现的 Silverlight 配置对话框






4.25/5 (3投票s)
本文的目的是展示如何阻止 Silverlight 插件显示的默认对话框在右键单击 Silverlight 应用程序时显示给用户。
引言
最近在一个我参与的项目中,我们需要禁用 Silverlight 配置对话框,该对话框在用户单击 Silverlight 应用程序中的任何位置时自动出现,如下所示:

业务问题
Silverlight 配置对话框具有许多有用的功能和快速卸载应用程序的能力。 但是,在大多数情况下,您希望阻止业务用户了解实现的详细信息。 业务用户也可能会不小心更改一些设置,导致应用程序无法正常工作,或者更糟糕的是,他们可能会在不知道如何重新安装应用程序的情况下卸载该应用程序。
下面的图片显示了一个测试解决方案,它显示了默认出现的右键菜单。

解决方案
解决此问题的一种可能方法是使用 JavaScript 在插件级别禁用右键单击。 但是,这种方法会禁用整个应用程序的右键单击事件,并且在浏览器外模式下不起作用。 本文提出的解决方案使用 Silverlight 4 版本中公开的右键单击事件处理程序,并且不适用于以前版本的 Silverlight。 该解决方案是在应用程序启动方法中为鼠标右键按下事件添加一个事件处理程序。 在事件处理程序中,我们将 ishandled
属性设置为 true
。 这实际上阻止了该事件一直冒泡到 Silverlight 插件。 相应的源代码如下所示
private void Application_Startup(object sender, StartupEventArgs e)
{
Application.Current.RootVisual.MouseRightButtonDown +=
new System.Windows.Input.MouseButtonEventHandler
(RootVisual_MouseRightButtonDown);
}
void RootVisual_MouseRightButtonDown
(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
e.Handled = true;
}
private void Application_Exit(object sender, EventArgs e)
{
Application.Current.RootVisual.MouseRightButtonDown -=
new System.Windows.Input.MouseButtonEventHandler
(RootVisual_MouseRightButtonDown);
}
这似乎是一个简单的解决方法。 但是,我们仍然存在一个问题。 可以观察到,当日期选择器弹出窗口打开时,用户可以右键单击弹出控件并获取配置对话框。
问题如下所示

花了一些时间后,我从 MSDN 文档中了解到,Silverlight 中的某些对象以一种关系参与主树,从概念上讲,它就像主视觉对象上的一个覆盖层。 这些对象不属于将所有树元素连接到可视根的常用父子关系。 任何显示的 Popup 或 ToolTip 都是这种情况。 如果要处理来自 Popup 或 ToolTip 的路由事件,则应将处理程序放置在 Popup 或 ToolTip 中的特定 UI 元素上,而不是 Popup 或 ToolTip 元素本身上。 您不应依赖于为 Popup 或 ToolTip 内容执行的任何合成内部的路由。 这是因为路由事件的事件路由仅沿主可视化树工作。 Popup 或 ToolTip 不被认为是辅助 UI 元素的父级,并且永远不会接收路由事件,即使它试图使用类似 Popup 默认背景作为输入事件的捕获区域。
因此,为了完全解决问题,任何使用弹出窗口的控件(如日期选择器)都必须被重写为使用自定义控件,该控件显式重写弹出窗口的右键单击行为并将右键单击事件设置为已处理。 下面显示了一个自定义时间选择器控件的示例
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
namespace Controls
{
public class CustomTimePicker:TimePicker
{
private Canvas _canvas = null;
private Popup _p = null;
internal Canvas PopupCanvas
{
get { return _canvas; }
set
{
if (_canvas != null)
{
_canvas.MouseRightButtonDown -=
new MouseButtonEventHandler(PopupCanvas_MouseRightButtonDown);
}
_canvas = value;
if (_canvas != null)
{
_canvas.MouseRightButtonDown +=
new MouseButtonEventHandler(PopupCanvas_MouseRightButtonDown);
}
}
}
internal Popup TimepickerPopup
{
get { return _p; }
set
{
_p = value;
}
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
TimepickerPopup = GetTemplateChild("Popup") as Popup;
if (TimepickerPopup != null)
{
PopupCanvas = TimepickerPopup.Child as Canvas;
}
if (PopupCanvas != null)
{
PopupCanvas.MouseRightButtonDown += new MouseButtonEventHandler
(PopupCanvas_MouseRightButtonDown);
}
}
void PopupCanvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
}
}
}
参考
- Silverlight 中的事件概述: http://msdn.microsoft.com/en-us/library/cc189018(v=vs.95).aspx
历史
- 初始草稿版本 V1.0 (08-Feb-2011)