文章目录
前言
通过反射获取到控件的路由事件时,如何获取到控件本身的事件,和通过Style设置的事件,这个问题似乎没有优美的解法。
stackoverflow中常见的方法通常是查询UIElement.EventHandlersStore获取控件对应的事件
https://stackoverflow.com/questions/44283395/copy-all-event-handlers-from-one-control-to-another-at-runtime
/// <summary>
/// Get a list of RoutedEventHandlers
/// Credit: Douglas : https://stackoverflow.com/a/12618521/3971575
/// </summary>
/// <param name="element"></param>
/// <param name="routedEvent"></param>
/// <returns></returns>
public RoutedEventHandlerInfo[] GetRoutedEventHandlers(UIElement element, RoutedEvent routedEvent)
{
// Get the EventHandlersStore instance which holds event handlers for the specified element.
// The EventHandlersStore class is declared as internal.
PropertyInfo eventHandlersStoreProperty = typeof(UIElement).GetProperty("EventHandlersStore", BF.Instance | BF.NonPublic);
object eventHandlersStore = eventHandlersStoreProperty.GetValue(element, null);
// If no event handlers are subscribed, eventHandlersStore will be null.
// Credit: https://stackoverflow.com/a/16392387/1149773
if (eventHandlersStore == null)
return null;
// Invoke the GetRoutedEventHandlers method on the EventHandlersStore instance
// for getting an array of the subscribed event handlers.
MethodInfo getRoutedEventHandlers = eventHandlersStore.GetType().GetMethod("GetRoutedEventHandlers", BF.Instance | BF.Public | BF.NonPublic);
return (RoutedEventHandlerInfo[])getRoutedEventHandlers.Invoke(eventHandlersStore, new object[] { routedEvent });
}
遇到的问题
但我在使用中发现,这种方法只能查询到直接在控件中注册的事件
//在xaml中定义的
<Button Style="{StaticResource menuButton}" MouseLeave="xxx">
//在c#代码中增加的
xxButton.MouseLeave += xxx
//其他直接作用到控件中的方式
....
如果在控件style中通过<EventSetter>
设置的事件,是无法通过上述的反射代码获取到的,在网上搜索了下相关问题,但似乎没找到,正当我一筹莫展时,发现了微软官方早就开源了.netframework
源码,这倒是给了我一点动力去探索了
浏览了下Style的源码,发现源码里也是没有把style中eventSetter设置的事件合并到tartgetType中的,Style中也有一个单独的EventHandlersStore用于存储事件(事件路由的时候,也是直接从EventHandlersStore查询并添加的FrameworkElement.AddStyleHandlersToEventRoute
)
小改进
于是就是对上述反射代码的改进了
public static RoutedEventHandlerInfo[] GetRoutedEventHandlers(UIElement element, RoutedEvent routedEvent)
{
var routedEventHandlers = default(RoutedEventHandlerInfo[]);
// Get the EventHandlersStore instance which holds event handlers for the specified element.
// The EventHandlersStore class is declared as internal.
var eventHandlersStoreProperty = typeof(UIElement).GetProperty("EventHandlersStore", BindingFlags.Instance | BindingFlags.NonPublic);
object eventHandlersStore = eventHandlersStoreProperty.GetValue(element, null);
if (eventHandlersStore != null)
{
// Invoke the GetRoutedEventHandlers method on the EventHandlersStore instance
// for getting an array of the subscribed event handlers.
var field = eventHandlersStore.GetType().GetField("_entries", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
dynamic sss = field.GetValue(eventHandlersStore);
var getRoutedEventHandlers = eventHandlersStore.GetType().GetMethod("GetRoutedEventHandlers", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
routedEventHandlers = (RoutedEventHandlerInfo[])getRoutedEventHandlers.Invoke(eventHandlersStore, new object[] { routedEvent });
}
//get style events
var frElement = element as FrameworkElement;
if (frElement != null && frElement.Style != null)
{
var styleRoutedEventHandlers = GetStyleRoutedEventHandlers(frElement.Style, routedEvent);
if (styleRoutedEventHandlers != null)
{
var tempHandlers = new List<RoutedEventHandlerInfo>();
if (routedEventHandlers != null)
{
foreach (var handler in routedEventHandlers)
{
tempHandlers.Add(handler);
}
}
if (styleRoutedEventHandlers != null)
{
foreach (var handler in styleRoutedEventHandlers)
{
tempHandlers.Add(handler);
}
}
routedEventHandlers = tempHandlers.ToArray();
}
}
return routedEventHandlers;
}
public static RoutedEventHandlerInfo[] GetStyleRoutedEventHandlers(Style style, RoutedEvent routedEvent)
{
var routedEventHandlers = default(RoutedEventHandlerInfo[]);
// Get the EventHandlersStore instance which holds event handlers for the specified element.
// The EventHandlersStore class is declared as internal.
var eventHandlersStoreProperty = typeof(Style).GetProperty("EventHandlersStore", BindingFlags.Instance | BindingFlags.NonPublic);
object eventHandlersStore = eventHandlersStoreProperty.GetValue(style, null);
if (eventHandlersStore != null)
{
// Invoke the GetRoutedEventHandlers method on the EventHandlersStore instance
// for getting an array of the subscribed event handlers.
var field = eventHandlersStore.GetType().GetField("_entries", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
dynamic sss = field.GetValue(eventHandlersStore);
var getRoutedEventHandlers = eventHandlersStore.GetType().GetMethod("GetRoutedEventHandlers", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
routedEventHandlers = (RoutedEventHandlerInfo[])getRoutedEventHandlers.Invoke(eventHandlersStore, new object[] { routedEvent });
}
return routedEventHandlers;
}
总结
并不算优美,但好歹解决了我遇到的问题了