Hintergrund: Ich verwende WPF und C# (3.5) und arbeite an einer App, die es einem Benutzer ermöglicht, ein Formular/Fenster/usercontrol anzuzeigen, das bereits Teil einer kompilierten Assembly ist. Wenn sie es sehen, sollten sie in der Lage sein, auf ein beliebiges Steuerelement (Schaltflächen, Textfelder, sogar Etiketten) zu klicken, ein kleines Popup-Editor sollte vom Steuerelement angezeigt werden, wo sie dann einen Tooltip, helpID usw. für das Steuerelement eingeben können.Entfernen von Routingereignishandlern durch Reflektion?
Das lange und kurze: Ich muss eine grundlegende Entwurfsansicht in WPF nachahmen. Was bedeutet, ich brauche die folgenden zumindest zu tun:
- Legen Sie das Usercontrol/Fenster aus einer gegebenen Baugruppe (kein Problem)
- es die Usercontrol/Fenster (kein Problem) Instantiate
- löschen Sie alle abonnierten Eventhandler für alle seine Kontrollen
- my own „ShowEditorPopup“ Eventhandler zu jeder Kontrolle vergeben (sollte kein Problem sein)
Zunächst, wenn jemand Vorschläge für eine einfachere oder bessere Route zu nehmen, lass es mich wissen. (Anscheinend gibt es keine DesignHost Art von Komponente für WPF (wie ich .NET 2 gelesen habe), also das ist raus.)
Ich stecke auf dem fettgedruckten Artikel fest - lösche alle abonnierten EventHandler. Nachdem ich mich mit Reflector beschäftigt habe, bin ich auf diesen coolen Brocken gefährlichen Codes gestoßen (hier versuche ich nur, alle EventHandler für einen einzelnen Button namens someButton im XAML definiert zu bekommen):
<Button Name="someButton" Click="someButton_Click"/>
Hier ist der Code (Sie es von der someButton_Click Eventhandler ausführen können, wenn Sie wollen):
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);
}
es funktioniert auf die Invoke auf, die zurückgibt: Objekt nicht Zieltyp übereinstimmt (dh mein params oder Ziel Objekt sind vermurkst). Ich habe festgestellt, Sie können dieses Problem mit:
GetEventHandlers.Invoke(Activator.CreateInstance(someButton.GetType()), Params);
// Also doesn't work...
Wenn ich eine Uhr auf dem GetEventHandlers Method gesetzt, es sieht gut aus, es funktioniert einfach nicht, was ich bin es vorbei, als ich die Invoke rufen.
Ich fühle mich wie im letzten Schritt, wie man eine Liste der RoutedEvent-Handler (wie gute alte GetInvocationList(), die nicht funktioniert für WPF RoutedEvents, anscheinend). Von dort wird es einfach genug sein, diese Handler von jedem Steuerelement zu entfernen und ein ereignisloses Formular zu haben, dem ich dann meine eigenen Ereignisse hinzufügen kann.
Irgendwelche Hinweise? Wenn es einen besseren/einfacheren Weg gibt, die Aufgabe insgesamt zu erledigen, lassen Sie es mich wissen :)
Wow, Sie ein großes Werk war, war ich nur das Gleiche zu tun versuchen. Du hast mir nur den Ausgangspunkt gegeben, den ich brauchte. – orellabac