Frage

Hintergrund: Ich bin mit WPF und C # (3.5) und arbeite an einer Anwendung, die ein Benutzer ein Formular / Fenster / Usercontrol anzeigen kann, die bereits Teil einer kompilierten Assembly ist. Wenn sie es sehen, sollte sie in der Lage sein, auf jede Kontrolle (Schaltflächen, Textfelder, auch Etiketten) zu klicken, sollte ein wenig Pop-up-Editor von der Steuerung erscheinen, wo sie dann ein Tooltip eingeben können, helpID usw., für das Steuerelement.

Die lange Rede kurzer Sinn: Ich brauche eine grundlegende Entwurfsansicht in WPF zu imitieren. Was bedeutet, dass ich zumindest tun müssen, die folgenden:

  • Laden Sie das Usercontrol / Fenster aus einer gegebenen Baugruppe (kein Problem)
  • Instantiate es die Usercontrol / Fenster (kein Problem)
  • Löschen Sie alle abonnierten Eventhandler für alle seine Kontrollen
  • Weisen my own "ShowEditorPopup" Eventhandler zu jeder Kontrolle (sollte kein Problem sein)

Zunächst einmal, wenn jemand Vorschläge für eine einfachere oder bessere Route zu nehmen, hat lass es mich wissen. (Offenbar gibt es keine DesignHost Art der Komponente für WPF (wie ich .NET 2 hat gelesen habe), das ist also aus.)

Ich bin auf dem fett gedruckten Artikel stecken - gezeichnete Eventhandler zu löschen. Nach etwa einige graben und in Reflector bekommen, ich habe mit diesem kühlen Stück gefährlichen Code kommt (hier, ich versuche nur alle Eventhandler für einen einzigen Knopf in der XAML genannt someButton definiert zu erhalten):

<Button Name="someButton" Click="someButton_Click"/>

Hier ist der Code (Sie es von dem 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 der Invoke auf, die zurückgibt: Objekt nicht Zieltyp übereinstimmt (dh, meine params oder Zielobjekt durcheinander). 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 mag einfach nicht, was ich bin es vorbei, als ich die Invoke nennen.

Ich fühle mich wie im letzten Schritt von mir, wie eine Liste des RoutedEvent Handlers (wie guten alten GetInvocationList (), die nicht für WPF RoutedEvents funktioniert, scheinbar) zu erhalten. Von dort wird es einfach genug sein, diese Handlers von jeder Kontrolle zu entfernen und eine eventless Form hat, die ich dann zu meinen eigenen Veranstaltungen hinzufügen kann.

Irgendwelche Hinweise? Noch einmal, wenn es eine bessere / einfachere Weise insgesamt die Aufgabe zu tun, lassen Sie mich wissen:)

War es hilfreich?

Lösung

Was ist, wenn Sie einen anderen Ansatz. Sie könnten nennen EventManager.RegisterClassHandler () für alle Veranstaltungen, und dann in Ihrem Handler (ist das Ereignis unter der Annahme, für eine Kontrolle auf der Entwurfsoberfläche, und nicht Teil Ihrer UI) das Ereignis markiert als behandelt. Dies sollte es verhindern, dass zu den Kontrollen auf Ihrem Design Oberfläche weitergeleitet, da Klasse-Handler vor Standardereignishandler aufgerufen werden.

Sie würden immer noch Reflexion verwenden müssen, um die Liste der Ereignisse, die von einer Steuerung zur Verfügung gestellt zu bekommen, aber zumindest diese Art und Weise würden Sie nicht Reflexion verwenden, die Ereignisse zu entfernen. Auch wenn die Baugruppe auch eine Klasse Handler (wahrscheinlich, bevor Sie Ihren Code der Fall ist) registriert laden, würde ihre erste genannt werden, aber ich würde vermuten, dass dies ein seltenes Ereignis sein.

Andere Tipps

Wenn Sie GetEventHandlers.Invoke(EventHandlersStore , Params) verwenden es scheint gut zu funktionieren und nicht abstürzt.

Verwenden Sie den Code von oben Ich tat dies:

// Get the control's Type
Type controlViewType = ((UIElement)control).GetType();

// Dig out the undocumented (yes, I know, it's risky) EventHandlerStore
// from the control's Type
PropertyInfo EventHandlersStoreType =
controlViewType.GetProperty("EventHandlersStore",
BindingFlags.Instance | BindingFlags.NonPublic);

// Get the actual "value" of the store, not just the reflected PropertyInfo
Object EventHandlersStore = EventHandlersStoreType.GetValue(tree, null);
var miGetRoutedEventHandlers 
EventHandlersStore.GetType().GetMethod("GetRoutedEventHandlers", 
BindingFlags.Public | BindingFlags.Instance);
RoutedEventHandlerInfo[] res =   
(RoutedEventHandlerInfo[])miGetRoutedEventHandlers.Invoke(EventHandlersStore, 
new object[] { CheckedTreeViewItem.CheckedEvent });

Sobald Sie, dass dann das einzige Problem ist, dass Sie jetzt die Methode info, so dass Sie eine Instanz auf das Objekt erhalten müssen, das diese Methode implementiert. Normalerweise Event-Handler auf dem Fenster oder Page-Objekt definiert. So bekommen sie:     var parent = VisualTreeHelper.GetParent (Kontrolle);     while (! (Kontrolle Fenster) &&! (Kontrolle Seite))     {            parent = VisualTreeHelper.GetParent (parent);     }

Und mit diesem Fall können Sie dann das Ereignis Wtih aufrufen:

res.[0].Handler.Method.Invoke(parent, new object[] { control, new RoutedEventArgs() }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top