背景:我正在使用 WPF 和 C# (3.5),并且正在开发一个允许用户查看已经是已编译程序集一部分的窗体/窗口/用户控件的应用程序。当他们查看它时,他们应该能够点击任何控件(按钮、文本框,甚至标签),一个小的弹出编辑器应该出现在控件旁边,然后他们可以在其中为该控件输入工具提示、帮助 ID 等。
总而言之:我需要在 WPF 中模仿一个基本的设计 View 。这意味着我至少需要执行以下操作:
- 从给定程序集加载用户控件/窗口(没问题)
- 实例化用户控件/窗口(没问题)
- 清除其所有控件的所有订阅的事件处理程序
- 为每个控件分配我自己的“ShowEditorPopup”事件处理程序(应该没有问题)
首先,如果有人对更简单或更好的路线有建议,请告诉我。 (显然没有 DesignHost 类型的 WPF 组件(就像我读过的 .NET 2 一样),所以它已经过时了。)
我被困在粗体项目上 - 清除所有订阅的 EventHandlers。在深入研究并使用 Reflector 之后,我想出了这段很酷的危险代码块(在这里,我只是试图获取 XAML 中定义的名为 someButton 的单个按钮的所有事件处理程序):
<Button Name="someButton" Click="someButton_Click"/>
这是代码(如果需要,您可以从 someButton_Click 事件处理程序运行它):
public void SomeFunction()
{
// Get the control's Type
Type someButtonType = ((UIElement)someButton).GetType();
// Dig out the undocumented (yes, I know, it's risky) EventHandlerStore
// from the control's Type
PropertyInfo EventHandlersStoreType =
someButtonType.GetProperty("EventHandlersStore",
BindingFlags.Instance | BindingFlags.NonPublic);
// Get the actual "value" of the store, not just the reflected PropertyInfo
Object EventHandlersStore = EventHandlersStoreType.GetValue(someButton, null);
// Get the store's type ...
Type storeType = EventHandlersStore.GetType();
// ... so we can pull out the store's public method GetRoutedEventHandlers
MethodInfo GetEventHandlers =
storeType.GetMethod("GetRoutedEventHandlers",
BindingFlags.Instance | BindingFlags.Public);
// Reflector shows us that the method's sig is this:
// public RoutedEventHandlerInfo[] GetRoutedEventHandlers(RoutedEvent routedEvent);
// So set up the RoutedEvent param
object[] Params = new object[] { ButtonBase.ClickEvent as RoutedEvent };
// I've also seen this for the param, but doesn't seem to make a difference:
// object[] Params = new object[] { someButton.ClickEvent };
// And invoke it ... and watch it crash!
GetEventHandlers.Invoke(someButton, Params);
}
它工作到调用,它返回:对象与目标类型不匹配(即,我的参数或目标对象被弄乱了)。我发现您可以通过以下方式解决此问题:
GetEventHandlers.Invoke(Activator.CreateInstance(someButton.GetType()), Params);
// Also doesn't work...
当我在 GetEventHandlers MethodInfo 上设置监视时,它看起来很棒,只是不喜欢我在调用 Invoke 时传递给它的内容。
我觉得我正处于如何获取 RoutedEvent 处理程序列表的最后一步(就像旧的 GetInvocationList(),显然它不适用于 WPF RoutedEvents)。从那里开始,从每个控件中删除这些处理程序并获得无事件形式就足够简单了,然后我可以向其添加自己的事件。
有什么线索吗?同样,如果有更好/更简单的方法来完成整个任务,请告诉我:)
最佳答案
如果您采用不同的方法会怎么样。您可以调用EventManager.RegisterClassHandler()对于所有事件,然后在您的处理程序中(假设该事件是针对设计表面上的控件,而不是您的 UI 的一部分)将事件标记为已处理。这应该可以防止它被转发到设计界面上的控件,因为类处理程序在标准事件处理程序之前被调用。
您仍然需要使用反射来获取控件提供的事件列表,但至少这样您就不会使用反射来删除事件。此外,如果您加载的程序集还注册了一个类处理程序(可能在您的代码注册之前),它们将首先被调用,但我猜想这种情况很少见。
关于c# - 通过反射删除路由事件处理程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/982709/