2009-06-30 4 views
9

Beim Erstellen einer designierbaren .NET-Komponente müssen Sie einen Standardkonstruktor bereitstellen. Von der IComponent Dokumentation:Kombinieren von gestaltbaren Komponenten mit Abhängigkeitsinjektion

eine Komponente zu sein, muss eine Klasse die IComponent-Schnittstelle implementieren und eine grundlegende Konstruktor, keine Parameter oder einen einzelnen Parameter des Typs IContainer erfordert.

Dies macht eine Abhängigkeitsinjektion über Konstruktorargumente unmöglich. (Extra-Konstrukteuren zur Verfügung gestellt werden könnte, aber der Designer würde sie ignorieren.) Einige Alternativen wir unter Berücksichtigung

  • Service Locator

    Verwenden Sie Dependency Injection nicht, sondern das Muster Service Locator verwenden Abhängigkeiten erwerben. Dies scheint IComponent.Site zu sein. GetService ist für. Ich denke, wir könnten eine wiederverwendbare ISite-Implementierung (ConfigurableServiceLocator?) Erstellen, die mit den notwendigen Abhängigkeiten konfiguriert werden kann. Aber wie funktioniert das im Designer-Kontext?

  • Dependency Injektion über Eigenschaften

    Injekt Abhängigkeiten über Eigenschaften. Stellen Sie Standardinstanzen bereit, wenn sie erforderlich sind, um die Komponente in einem Designer anzuzeigen. Dokumentieren Sie, welche Eigenschaften eingegeben werden müssen.

  • Inject Abhängigkeiten mit einer Initialize-Methode

    Dies sind ähnlich wie Injektion über Eigenschaften, aber es hält die Liste der Abhängigkeiten, die an einem Ort injiziert werden müssen. Auf diese Weise wird die Liste der erforderlichen Abhängigkeiten implizit dokumentiert, und der Compiler unterstützt Sie bei Fehlern, wenn sich die Liste ändert.

Eine Idee, was die beste Praxis ist hier? Wie machst du das?


bearbeiten: Ich habe entfernt „(zum Beispiel ein WinForms Usercontrol)“, da ich die Frage nach Komponenten im Allgemeinen sein soll. Bei den Komponenten dreht sich alles um die Inversion der Kontrolle (siehe Abschnitt 8.3.1 der UMLv2 specification). Ich denke also nicht, dass "Sie keine Dienste injizieren sollten", ist eine gute Antwort.


bearbeiten 2: Es dauerte einige Spiele mit WPF und dem MVVM Muster Antwort Mark, um endlich "get". Ich sehe jetzt, dass visuelle Kontrollen tatsächlich ein Sonderfall sind. Was die Verwendung nicht visueller Komponenten auf Designeroberflächen anbelangt, ist das .NET-Komponentenmodell meiner Ansicht nach grundsätzlich nicht mit der Abhängigkeitsinjektion kompatibel. Es scheint stattdessen um das Service-Locator-Muster herum angelegt zu sein. Möglicherweise wird sich dies mit der Infrastruktur ändern, die in .NET 4.0 im Namespace System.ComponentModel.Composition hinzugefügt wurde.

Antwort

6

Die gleiche Frage nervte mich lange, bis ich realisierte, dass ich falsch darüber nachdachte.AFAIR, der einzige Grund für das Erstellen einer IComponent-Implementierung besteht in der Bereitstellung von Entwurfszeitfunktionen - es gibt keinen Laufzeiteffekt von IComponent-Implementierungen.

von corrolary bedeutet dies, dass Sie meist Komponenten erstellen sollten Design-Zeit-Funktionen zu implementieren. Speziell für Controls bedeutet dies, dass Sie die Komponente so konfigurieren können, dass sie sich in einer bestimmten Weise verhält. Es ist sehr wichtig zu erkennen, dass dies ein völlig anderes Problem ist, als dass sich die Komponente tatsächlich verhält oder welche Daten sie anzeigt. Es sollte kein Verhalten zur Entwurfszeit haben und sollte auch keine Daten enthalten.

Als solche wird die Einschränkung für den Konstruktor ist eigentlich ein Segen, da es Ihnen anweist, Ihr Design zu überdenken. Ein Control ist eine datenquellenunabhängige Software, die Daten in einer bestimmten Weise anzeigt und mit ihnen interagiert. Solange diese Daten bestimmten Schnittstellen usw. entsprechen, freut sich die Control. Wie diese Daten ankommen, ist für die Steuerung nicht von Interesse, und es sollte auch nicht sein. Es wäre ein Fehler, wenn die Steuerung steuern würde, wie Daten geladen und geändert werden.

In WPF, ist dies explizit viel klarer als in Windows Forms: Sie geben ein bestimmtes Steuerelement ein Datacontext und binden Eigenschaften der Steuerung an die Mitglieder des Datacontext. Der DataContext (der ein beliebiges Objekt sein kann) stammt von außerhalb des Controls; Das ist die Verantwortung oder Ihre Präsentationsschicht.

In Windows Forms, können Sie immer noch das gleiche tun, indem Sie einen Datenkontext zu einer Kontrolle zuweisen. Im Wesentlichen ist dies Property Injection - seien Sie sich bewusst, dass Sie keine Services injizieren sollten. Sie sollten Daten injizieren.

Zusammenfassend würde ich weder mit Ihren Vorschläge gehen. Lassen Sie das Steuerelement stattdessen eine oder mehrere Eigenschaften, die Ihnen ermöglichen, Daten dem Steuerelement zuzuweisen, und verwenden Sie Datenbindung, um gegen diese Daten zu binden. Machen Sie sich in der Implementierung des Controls bereit, die Situation zu bewältigen, in der es keine Daten gibt: Dies wird jedes Mal passieren, wenn das Control zur Design-Zeit von VS gehostet wird. Das Null-Objekt-Muster ist sehr nützlich für die Implementierung einer solchen Widerstandsfähigkeit.

Sie dann den Datenkontext von Ihrem Controller auf. Das ist der MVC-Weg: Die Control ist die View, aber Sie sollten einen separaten Controller haben, der ein Model zur View instanziieren und zuweisen kann.

+0

Wenn ich Ihre Antwort richtig interpretiere, sagen Sie, dass Kontrollen keine Dienste verwenden sollten. Ich bin mir nicht sicher, ob ich dem zustimme. Zum Beispiel habe ich ein Steuerelement, das Text nicht direkt durch den Aufruf von System.Windows.Forms.TextRenderer rendert. Stattdessen verwendet es einen injizierbaren ITextRenderer-Dienst (mit im Wesentlichen den gleichen Methoden). Dies ermöglicht es mir, ausgefallene Abkürzungsstrategien zu implementieren, die über die Möglichkeiten des .NET-Frameworks hinausgehen, während der Code unabhängig von der Steuerung selbst gehalten wird. –

+0

Ja, ich sage, dass Controls keine Dienste verwenden sollten - Dienste sollten Controls verwenden. Ein Steuerelement sollte nur UI rendern. Es ist in Ordnung, dass Sie komplizierte Abkürzungsstrategien einfügen können, aber eine solche Logik gehört in das (Ansichts-) Modell, nicht in die Ansicht selbst. Sie können dann Ihre View an Eigenschaften im Modell binden, die die gewünschten Werte erzeugen, indem Sie die injizierten Abhängigkeiten aufrufen. Auch wenn Sie WinForms zu verwenden scheinen, finden Sie hier Informationen zur Inspiration: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx –