Erweitern Sie Ihre .NET-Anwendungen mit Add-Ons
German (Deutsch) translation by Nikol Angelowa (you can also view the original English article)
Ihrer Anwendung fehlt eine coole Whizbang-Funktion? Lassen Sie andere interessierte Entwickler Ihre Anwendung durch Add-Ons erweitern. Indem Sie Ihre App später für zusätzliche Funktionen öffnen, können Sie eine florierende Community rund um Ihre Anwendung aufbauen, möglicherweise sogar einen Marktplatz!
Im heutigen Tutorial werden wir genau das lernen!
Schritt 0 - Unser Spielplan
Abhängig von der verwendeten Version von Visual Studio und der Version des Frameworks, auf das Sie abzielen, sehen einige Screenshots möglicherweise etwas anders aus.
Wir werden eine Proof-of-Concept-Anwendung erstellen, die beim Start Add-Ons lädt, die in einem ihrer Unterverzeichnisse gefunden werden. Diese Add-Ons sind .NET-Assemblys, die mindestens eine Klasse enthalten, die eine bestimmte von uns definierte Schnittstelle implementiert. Die Konzepte in diesem Lernprogramm sollten ohne großen Aufwand problemlos in Ihre vorhandenen Anwendungen übertragen werden können. Dann sehen wir uns ein vollständigeres Beispiel an, bei dem UI-Komponenten verwendet werden, die von einem Add-On geladen wurden.
Dieses Tutorial wurde mit Microsoft Visual Studio 2010 in VB.NET für .NET Framework 4.0 erstellt. Die wichtigsten Konzepte dieses Tutorials sollten in anderen CLR-Sprachen ab .NET Framework 1.1 funktionieren. Es gibt einige kleinere Funktionen, die in anderen CLR-Sprachen nicht funktionieren - aber sehr einfach zu portieren sein sollten - und einige Konzepte wie Generika, die in .NET 1.1 usw. offensichtlich nicht funktionieren.
Hinweis: Das ist ein Tutorial auf Expertenebene für Benutzer, die mit der Konvertierung von Code zwischen verschiedenen CLR-Sprachen und Versionen des .NET-Frameworks zufrieden sind. Es ist mehr "Ersetzen Ihres Automotors" als "Fahren".
Schritt 1 - Erste Implementierung im kleinen Maßstab
Hinweis: Ihre Referenzen können je nach der Version von .NET Framework, auf die Sie abzielen, unterschiedlich sein.
Beginnen wir mit der Implementierung einer kleinen Version unserer Anwendung. Wir werden drei Projekte in unserer Lösung benötigen:
-
ConsoleAppA: Eine Konsolenanwendung -
ClassLibA: Eine Klassenbibliothek -
AddonA: Eine Klassenbibliothek, die als unser Add-On fungiert
Fügen Sie ClassLibA eine Referenz von ConsoleAppA und AddonA hinzu. Der Lösungs-Explorer sollte so aussehen:
Erstellung von der Add-On-Schnittstelle
Damit eine kompilierte Klasse als kompatibel angesehen werden kann, muss jedes Add-On für unsere Anwendung eine bestimmte Schnittstelle implementieren. Diese Schnittstelle definiert die erforderlichen Eigenschaften und Operationen, über die die Klasse verfügen muss, damit unsere Anwendung problemlos mit dem Add-On interagieren kann. Wir könnten auch eine abstract/MustInherit-Klasse als Basis für Add-Ons verwenden, aber in diesem Beispiel verwenden wir eine Schnittstelle.
Hier ist der Code für unsere Schnittstelle, der in einer Datei namens IApplicationModule in der ClassLibA-Klassenbibliothek abgelegt werden sollte.
1 |
Public Interface IApplicationModule |
2 |
|
3 |
ReadOnly Property Id As Guid |
4 |
ReadOnly Property Name As String |
5 |
|
6 |
Sub Initialise() |
7 |
|
8 |
End Interface |
Die Eigenschaften und Methoden, die Sie in der Schnittstelle definieren, sind beliebig. In diesem Fall habe ich zwei Eigenschaften und eine Methode definiert, aber in der Praxis können und sollten Sie sie nach Bedarf ändern.
In unserem ersten Beispiel werden die Eigenschaften Id oder Name nicht verwendet, aber sie sind nützliche Eigenschaften, die implementiert werden müssen. Wenn Sie Add-Ons in der Produktion verwenden, möchten Sie sie vorhanden haben.
Add-On erstellen
Jetzt erstellen wir das eigentliche Add-On. Damit eine Klasse als Add-On für unsere Anwendung betrachtet werden kann, muss sie unsere Schnittstelle - IApplicationModule - implementieren.
Hier ist der Code für unser Basis-Add-On, der in einer Datei namens MyAddonClass in der AddonA-Klassenbibliothek abgelegt werden sollte.
1 |
Imports ClassLibA |
2 |
|
3 |
Public Class MyAddonClass |
4 |
Implements IApplicationModule |
5 |
|
6 |
Public ReadOnly Property Id As System.Guid Implements ClassLibA.IApplicationModule.Id |
7 |
Get
|
8 |
Return New Guid("adb86b53-2207-488e-b0f3-ecd13eae4042") |
9 |
End Get |
10 |
End Property |
11 |
|
12 |
Public Sub Initialise() Implements ClassLibA.IApplicationModule.Initialise |
13 |
Console.WriteLine("MyAddonClass is starting up ...") |
14 |
'Perform start-up initialisation here ...
|
15 |
End Sub |
16 |
|
17 |
Public ReadOnly Property Name As String Implements ClassLibA.IApplicationModule.Name |
18 |
Get
|
19 |
Return "My first test add-on" |
20 |
End Get |
21 |
End Property |
22 |
End Class |
Schritt 2 - Suchen von Add-Ons zur Laufzeit
Dann benötigen wir eine Möglichkeit, Add-Ons für unsere Anwendung zu finden. In diesem Beispiel wird davon ausgegangen, dass im Verzeichnis der ausführbaren Datei ein Addons-Ordner erstellt wurde. Wenn Sie dies in Visual Studio testen, berücksichtigen Sie das Standard-Projektausgabeverzeichnis für Projekte, nämlich ./bin/debug/, sodass Sie ein ./bin/debug/Addons/-Verzeichnis benötigen.
Zeit zum Nachdenken
Platzieren Sie die TryLoadAssemblyReference-Methode unten in Module1 von ConsoleAppA. Wir untersuchen die beladene Baugruppe mithilfe von Reflection. Eine Pseudo-Code-exemplarische Vorgehensweise für die Funktionalität lautet wie folgt:
- Versuchen Sie, den angegebenen dllFilePath als .NET-Assembly zu laden
- Wenn wir die Assembly erfolgreich geladen haben, fahren Sie fort
- Für jedes Modul in der geladenen Baugruppe
- Für jeden Typ in diesem Modul
- Für jede von diesem Typ implementierte Schnittstelle
- Wenn diese Schnittstelle unsere Add-On-Schnittstelle (
IApplicationModule) ist, dann - Führen Sie Aufzeichnungen über diesen Typ. Beenden Sie die Suche.
- Geben Sie zum Schluss alle gefundenen gültigen Typen zurück
1 |
Private Function TryLoadAssemblyReference(ByVal dllFilePath As String) As List(Of System.Type) |
2 |
Dim loadedAssembly As Assembly |
3 |
Dim listOfModules As New List(Of System.Type) |
4 |
Try
|
5 |
loadedAssembly = Assembly.LoadFile(dllFilePath) |
6 |
Catch ex As Exception |
7 |
End Try |
8 |
If loadedAssembly IsNot Nothing Then |
9 |
For Each assemblyModule In loadedAssembly.GetModules |
10 |
For Each moduleType In assemblyModule.GetTypes() |
11 |
For Each interfaceImplemented In moduleType.GetInterfaces() |
12 |
If interfaceImplemented.FullName = "ClassLibA.IApplicationModule" Then |
13 |
listOfModules.Add(moduleType) |
14 |
End If |
15 |
Next
|
16 |
Next
|
17 |
Next
|
18 |
End If |
19 |
Return listOfModules |
20 |
End Function |
Starten Sie unsere Add-Ons
Schließlich können wir jetzt eine kompilierte Klasse laden, die unsere Schnittstelle in den Speicher implementiert. Wir haben jedoch keinen Code, um diese Klassen zu finden, zu instanziieren oder Methodenaufrufe durchzuführen. Als nächstes werden wir einen Code zusammenstellen, der genau das tut.
Der erste Teil besteht darin, alle Dateien zu finden, bei denen es sich möglicherweise um Add-Ons handelt (siehe unten). Der Code führt eine relativ einfache Dateisuche durch und versucht für jede gefundene DLL-Datei, alle gültigen Typen aus dieser Assembly zu laden. DLLs, die im Ordner "Addons" gefunden wurden, sind nicht unbedingt Add-Ons. Sie können lediglich zusätzliche Funktionen enthalten, die für ein Add-On erforderlich sind, sind jedoch an sich kein Add-On.
1 |
Dim currentApplicationDirectory As String = My.Application.Info.DirectoryPath |
2 |
Dim addonsRootDirectory As String = currentApplicationDirectory & "\Addons\" |
3 |
Dim addonsLoaded As New List(Of System.Type) |
4 |
|
5 |
If My.Computer.FileSystem.DirectoryExists(addonsRootDirectory) Then |
6 |
Dim dllFilesFound = My.Computer.FileSystem.GetFiles(addonsRootDirectory, Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, "*.dll") |
7 |
For Each dllFile In dllFilesFound |
8 |
Dim modulesFound = TryLoadAssemblyReference(dllFile) |
9 |
addonsLoaded.AddRange(modulesFound) |
10 |
Next
|
11 |
End If |
Dann müssen wir für jeden gültigen Typ, den wir gefunden haben, etwas tun. Der folgende Code erstellt eine neue Instanz des Typs, gibt den Typ ein, ruft die Initialise()-Methode auf (dies ist nur eine beliebige Methode, die wir in unserer Schnittstelle definiert haben) und behält dann einen Verweis auf diesen instanziierten Typ in einer Liste auf Modulebene bei .
1 |
If addonsLoaded.Count > 0 Then |
2 |
For Each addonToInstantiate In addonsLoaded |
3 |
Dim thisInstance = Activator.CreateInstance(addonToInstantiate) |
4 |
Dim thisTypedInstance = CType(thisInstance, ClassLibA.IApplicationModule) |
5 |
thisTypedInstance.Initialise() |
6 |
m_addonInstances.Add(thisInstance) |
7 |
Next
|
8 |
End If |
Alles in allem sollte unsere Konsolenanwendung ungefähr so aussehen:
1 |
Imports System.Reflection |
2 |
|
3 |
Module Module1 |
4 |
|
5 |
Private m_addonInstances As New List(Of ClassLibA.IApplicationModule) |
6 |
|
7 |
Sub Main() |
8 |
LoadAdditionalModules() |
9 |
|
10 |
Console.WriteLine('Finished loading modules ...') |
11 |
Console.ReadLine() |
12 |
End Sub |
13 |
|
14 |
Private Sub LoadAdditionalModules() |
15 |
Dim currentApplicationDirectory As String = My.Application.Info.DirectoryPath |
16 |
Dim addonsRootDirectory As String = currentApplicationDirectory & '\Addons\' |
17 |
Dim addonsLoaded As New List(Of System.Type) |
18 |
|
19 |
If My.Computer.FileSystem.DirectoryExists(addonsRootDirectory) Then |
20 |
Dim dllFilesFound = My.Computer.FileSystem.GetFiles(addonsRootDirectory, Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, "*.dll") |
21 |
For Each dllFile In dllFilesFound |
22 |
Dim modulesFound = TryLoadAssemblyReference(dllFile) |
23 |
addonsLoaded.AddRange(modulesFound) |
24 |
Next
|
25 |
End If |
26 |
|
27 |
If addonsLoaded.Count > 0 Then |
28 |
For Each addonToInstantiate In addonsLoaded |
29 |
Dim thisInstance = Activator.CreateInstance(addonToInstantiate) |
30 |
Dim thisTypedInstance = CType(thisInstance, ClassLibA.IApplicationModule) |
31 |
thisTypedInstance.Initialise() |
32 |
m_addonInstances.Add(thisInstance) |
33 |
Next
|
34 |
End If |
35 |
End Sub |
36 |
|
37 |
Private Function TryLoadAssemblyReference(ByVal dllFilePath As String) As List(Of System.Type) |
38 |
Dim loadedAssembly As Assembly |
39 |
Dim listOfModules As New List(Of System.Type) |
40 |
Try
|
41 |
loadedAssembly = Assembly.LoadFile(dllFilePath) |
42 |
Catch ex As Exception |
43 |
End Try |
44 |
If loadedAssembly IsNot Nothing Then |
45 |
For Each assemblyModule In loadedAssembly.GetModules |
46 |
For Each moduleType In assemblyModule.GetTypes() |
47 |
For Each interfaceImplemented In moduleType.GetInterfaces() |
48 |
If interfaceImplemented.FullName = 'ClassLibA.IApplicationModule' Then |
49 |
listOfModules.Add(moduleType) |
50 |
End If |
51 |
Next
|
52 |
Next
|
53 |
Next
|
54 |
End If |
55 |
Return listOfModules |
56 |
End Function |
57 |
End Module |
Probelauf
Zu diesem Zeitpunkt sollten wir in der Lage sein, einen vollständigen Build unserer Lösung durchzuführen. Wenn Ihre Dateien erstellt wurden, kopieren Sie die kompilierte Assembly-Ausgabe des AddonA-Projekts in den Addons-Ordner von ConsoleAppA. Der Addons-Ordner sollte unter dem Ordner /bin/debug/ erstellt werden. Auf meinem Computer mit Visual Studio 2010, Standardprojektspeicherorten und einer Lösung namens "DotNetAddons" befindet sich der Ordner hier:
C:\Users\jplenderleith\Documents\Visual Studio 2010\Projects\DotNetAddons\ConsoleAppA\bin\Debug\Addons
Wir sollten die folgende Ausgabe sehen, wenn wir den Code ausführen:
1 |
MyAddonClass is starting up ... |
2 |
Finished loading modules ... |
So wie es aussieht, ist es nicht auffällig oder beeindruckend, aber es zeigt eine wichtige Funktionalität, nämlich, dass wir zur Laufzeit eine Assembly abrufen und Code innerhalb dieser Assembly ausführen können, ohne über vorhandene Kenntnisse über diese Assembly zu verfügen. Dies ist die Grundlage für die Erstellung komplexerer Add-Ons.
Schritt 3 - Integration in eine Benutzeroberfläche
Als Nächstes werden einige Add-Ons erstellt, um zusätzliche Funktionen in einer Windows Forms-Anwendung bereitzustellen.
Erstellen Sie ähnlich wie bei der vorhandenen Lösung eine neue Lösung mit den folgenden Projekten:
-
WinFormsAppA: Eine Windows Forms-Anwendung -
ClassLibA: Eine Klassenbibliothek -
UIAddonA: Eine Klassenbibliothek, die einige Add-Ons mit UI-Komponenten enthält
Ähnlich wie bei unserer vorherigen Lösung sollten sowohl die WinFormsAppA- als auch die UIAddonA-Projekte Verweise auf die ClassLibA enthalten. Das UIAddonA-Projekt benötigt außerdem einen Verweis auf System.Windows.Forms, um auf Funktionen zugreifen zu können.
Die Windows Forms-Anwendung
Wir erstellen eine schnelle und einfache Benutzeroberfläche für unsere Anwendung, die aus einem MenuStrip und einem DataGridView besteht. Das MenuStrip-Steuerelement sollte drei MenuItems haben
- Datei
- Add-Ons
- Hilfe
Docken Sie die DataGridView an ihren übergeordneten Container an - das Formular selbst. Wir werden einen Code zusammenstellen, um einige Scheindaten in unserem Raster anzuzeigen. Das Add-Ons-Menüelement wird mit allen Add-Ons gefüllt, die beim Start der Anwendung geladen wurden.
Hier ist ein Screenshot der Anwendung zu diesem Zeitpunkt:
Schreiben wir einen Code, um der Hauptform von WinFormsAppA einige Funktionen zu geben. Wenn das Formular geladen wird, wird die derzeit leere LoadAddons()-Methode aufgerufen - wir werden dies später ausfüllen. Anschließend generieren wir einige Beispieldaten von Mitarbeitern, an die wir unser DataGridView binden.
1 |
Public Class Form1 |
2 |
|
3 |
Private m_testDataSource As DataSet |
4 |
Private m_graphicalAddons As List(Of System.Type) |
5 |
|
6 |
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load |
7 |
LoadAddons() |
8 |
m_testDataSource = GenerateTestDataSet() |
9 |
With DataGridView1 |
10 |
.AutoGenerateColumns = True |
11 |
.AutoResizeColumns() |
12 |
.DataSource = m_testDataSource.Tables(0) |
13 |
End With |
14 |
End Sub |
15 |
|
16 |
Private Sub LoadAddons() |
17 |
|
18 |
End Sub |
19 |
|
20 |
Private Function GenerateTestDataSet() As DataSet |
21 |
Dim newDataSet As New DataSet |
22 |
Dim newDataTable As New DataTable |
23 |
Dim firstNames = {"Mary", "John", "Paul", "Justyna", "Michelle", "Andrew", "Michael"} |
24 |
Dim lastNames = {"O'Reilly", "Murphy", "Simons", "Kelly", "Gates", "Power"} |
25 |
Dim deptNames = {"Marketing", "Sales", "Technical", "Secretarial", "Security"} |
26 |
|
27 |
With newDataTable |
28 |
.Columns.Add("EmployeeId", GetType(Integer)) |
29 |
.Columns.Add("Name", GetType(String)) |
30 |
.Columns.Add("IsManager", GetType(Boolean)) |
31 |
.Columns.Add("Department", GetType(String)) |
32 |
End With |
33 |
|
34 |
For i = 1 To 100 |
35 |
Dim newDataRow As DataRow = newDataTable.NewRow() |
36 |
With newDataRow |
37 |
.Item("EmployeeId") = i |
38 |
.Item("Name") = firstNames(i Mod firstNames.Count) & " " & lastNames(i Mod lastNames.Count) |
39 |
.Item("IsManager") = ((i Mod 20) = 0) |
40 |
.Item("Department") = deptNames(i Mod deptNames.Count) |
41 |
End With |
42 |
newDataTable.Rows.Add(newDataRow) |
43 |
Next
|
44 |
|
45 |
newDataSet.Tables.Add(newDataTable) |
46 |
Return newDataSet |
47 |
End Function |
48 |
|
49 |
End Class |
Wenn wir die Anwendung ausführen, sollte sie folgendermaßen aussehen:


Nachdem wir die Add-On-Schnittstellen definiert haben, kehren wir zu unseren leeren LoadAddons() zurück.
Add-On-Schnittstelle
Definieren wir unsere Add-On-Oberfläche. UI-Komponenten werden unter Add-ons MenuStrip aufgelistet und öffnen ein Windows-Formular, das Zugriff auf die Daten hat, an die unser DataGrid gebunden ist. Fügen Sie dem ClassLibA-Projekt eine neue Schnittstellendatei mit dem Namen IGraphicalAddon hinzu und fügen Sie den folgenden Code in die Datei ein:
1 |
Public Interface IGraphicalAddon |
2 |
|
3 |
ReadOnly Property Name As String |
4 |
WriteOnly Property DataSource As DataSet |
5 |
Sub OnClick(ByVal sender As Object, ByVal e As System.EventArgs) |
6 |
|
7 |
End Interface |
- Wir haben eine
Name-Eigenschaft, die ziemlich selbsterklärend ist. - Die
DataSourcewird ordnungsgemäß verwendet, um Daten an dieses Add-On weiterzuleiten. - Die
OnClick-Methode, die als Handler verwendet wird, wenn Benutzer auf den Eintrag unseres Add-Ons im Menü Addons klicken.
Laden der Add-Ons
Fügen Sie dem ClassLibA-Assemblyprojekt eine Klassenbibliothek mit dem Namen AddonLoader mit dem folgenden Code hinzu:
1 |
Imports System.Reflection |
2 |
|
3 |
Public Class AddonLoader |
4 |
Public Enum AddonType |
5 |
IGraphicalAddon = 10 |
6 |
ISomeOtherAddonType2 = 20 |
7 |
ISomeOtherAddonType3 = 30 |
8 |
End Enum |
9 |
|
10 |
Public Function GetAddonsByType(ByVal addonType As AddonType) As List(Of System.Type) |
11 |
Dim currentApplicationDirectory As String = My.Application.Info.DirectoryPath |
12 |
Dim addonsRootDirectory As String = currentApplicationDirectory & "\Addons\" |
13 |
Dim loadedAssembly As Assembly |
14 |
Dim listOfModules As New List(Of System.Type) |
15 |
|
16 |
If My.Computer.FileSystem.DirectoryExists(addonsRootDirectory) Then |
17 |
Dim dllFilesFound = My.Computer.FileSystem.GetFiles(addonsRootDirectory, Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, "*.dll") |
18 |
For Each dllFile In dllFilesFound |
19 |
|
20 |
Try
|
21 |
loadedAssembly = Assembly.LoadFile(dllFile) |
22 |
Catch ex As Exception |
23 |
End Try |
24 |
If loadedAssembly IsNot Nothing Then |
25 |
For Each assemblyModule In loadedAssembly.GetModules |
26 |
For Each moduleType In assemblyModule.GetTypes() |
27 |
For Each interfaceImplemented In moduleType.GetInterfaces() |
28 |
If interfaceImplemented.Name = addonType.ToString Then |
29 |
listOfModules.Add(moduleType) |
30 |
End If |
31 |
Next
|
32 |
Next
|
33 |
Next
|
34 |
End If |
35 |
|
36 |
Next
|
37 |
End If |
38 |
|
39 |
Return listOfModules |
40 |
End Function |
41 |
End Class |
Sie können ähnlichen Code verwenden, um Add-On-Entwickler darauf zu beschränken, nur bestimmte Arten von Add-Ons zu erstellen
In dieser Klasse haben wir eine Möglichkeit bereitgestellt, verschiedene Arten von Add-Ons zu laden. Sie können ähnlichen Code verwenden, um Add-On-Entwickler darauf zu beschränken, nur bestimmte Arten von Add-Ons zu erstellen oder sie zumindest zu kategorisieren. In unserem Beispiel verwenden wir nur den ersten deklarierten Add-On-Typ, nämlich IGraphicalAddon.
Wenn wir andere Add-On-Typen in unserem Projekt hatten, um beispielsweise die Berichtsfunktionalität zu verbessern oder einige nützliche Tastaturkürzel bereitzustellen, möchten wir nicht, dass diese in unserem Add-On-Menü aufgeführt werden, da es keinen Sinn macht, dass jemand darauf klicken kann auf diesem Add-On.
Allerdings kann es wünschenswert sein, in einer Menüleiste einen Verweis auf alle Add-Ons hinzuzufügen. Klicken Sie auf, um das Optionsformular des Add-Ons anzuzeigen. Dies würde jedoch den Rahmen dieses Tutorials sprengen.
Das grafische Add-On
Lassen Sie uns das eigentliche UI-Add-On erstellen. Fügen Sie dem UIAddonA-Assemblyprojekt die folgenden zwei Dateien hinzu. eine Klasse namens UIReportAddon1 und ein Windows-Formular namens UIReportAddon1Form. Die UIReportAddon1-Klasse enthält den folgenden Code:
1 |
Imports ClassLibA |
2 |
|
3 |
Public Class UIReportAddon1 |
4 |
Implements ClassLibA.IGraphicalAddon |
5 |
|
6 |
Private _dataSource As DataSet |
7 |
Public WriteOnly Property DataSource As System.Data.DataSet Implements IGraphicalAddon.DataSource |
8 |
Set(ByVal value As System.Data.DataSet) |
9 |
_dataSource = value |
10 |
End Set |
11 |
End Property |
12 |
|
13 |
Public ReadOnly Property Name As String Implements IGraphicalAddon.Name |
14 |
Get
|
15 |
Return "Managers Report" |
16 |
End Get |
17 |
End Property |
18 |
|
19 |
Public Sub OnClick(ByVal sender As Object, ByVal e As System.EventArgs) Implements IGraphicalAddon.OnClick |
20 |
Dim newUiReportingAddonForm As New UIReportAddon1Form |
21 |
newUiReportingAddonForm.SetData(_dataSource) |
22 |
newUiReportingAddonForm.ShowDialog() |
23 |
End Sub |
24 |
End Class |
Fügen Sie UIReportAddon1Form eine DataGridView hinzu, die in ihrem übergeordneten Container angedockt ist. Fügen Sie dann den folgenden Code hinzu:
1 |
Public Class UIReportAddon1Form |
2 |
|
3 |
Private m_providedDataSource As DataSet |
4 |
|
5 |
Public Sub SetData(ByVal DataSource As System.Data.DataSet) |
6 |
m_providedDataSource = DataSource |
7 |
FilterAndShowData() |
8 |
End Sub |
9 |
|
10 |
Private Sub FilterAndShowData() |
11 |
Dim managers = m_providedDataSource.Tables(0).Select("IsManager = True") |
12 |
Dim newDataTable = m_providedDataSource.Tables(0).Clone |
13 |
For Each dr In managers |
14 |
newDataTable.ImportRow(dr) |
15 |
Next
|
16 |
DataGridView1.DataSource = newDataTable |
17 |
End Sub |
18 |
|
19 |
Private Sub UIReportAddon1Form_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load |
20 |
Text = "List of managers" |
21 |
End Sub |
22 |
End Class |
Wir bieten lediglich die Möglichkeit, Daten an das Formular zu senden und es dann entscheiden zu lassen, was mit diesen Daten geschehen soll. In diesem Fall führen wir Select() für eine DataTable aus und rufen eine Liste aller Mitarbeiter ab, die Manager sind.
Zurück zu unserer Hauptbenutzeroberfläche
Jetzt ist es Zeit, unsere unvollendete LoadAddons()-Methode in unserem WinFormsAppA-Projekt abzuschließen. Dieser Code weist die GetAddonsByType-Methode von ClassLibA.AddonLoader an, einen bestimmten Add-On-Typ zu finden - in diesem Fall IGraphicalAddon-Add-Ons.
Für jedes gefundene Add-On werden die folgenden Aktionen ausgeführt
- Erstellen Sie eine neue Instanz des Add-Ons
- Geben Sie die Add-On-Instanz zu IGraphicalAddon ein
- Füllen Sie die DataSource-Eigenschaft aus
- Fügen Sie das Add-On zum Menüpunkt Add-Ons hinzu
- Fügen Sie einen Handler für das Click-Ereignis dieses Menüelements hinzu
1 |
Private Sub LoadAddons() |
2 |
Dim loader As New ClassLibA.AddonLoader |
3 |
Dim addonsLoaded = loader.GetAddonsByType(ClassLibA.AddonLoader.AddonType.IGraphicalAddon) |
4 |
|
5 |
For Each graphicalAddon In addonsLoaded |
6 |
Dim thisInstance = Activator.CreateInstance(graphicalAddon) |
7 |
Dim typedAddon = CType(thisInstance, ClassLibA.IGraphicalAddon) |
8 |
typedAddon.DataSource = m_testDataSource |
9 |
Dim newlyAddedToolstripItem = AddonsToolStripMenuItem.DropDownItems.Add(typedAddon.Name) |
10 |
AddHandler newlyAddedToolstripItem.Click, AddressOf typedAddon.OnClick |
11 |
Next
|
12 |
End Sub |
Testen unserer Benutzeroberfläche
Stellen Sie sicher, dass Sie eine vollständige erfolgreiche Kompilierung der Lösung durchführen können. Kopieren Sie die Datei UIAddonA.dll aus dem Ausgabe-Debug-Ordner des UIAddonA-Projekts in den Ordner /bin/debug/Addons/ des WinFormsAppA-Projekts. Wenn Sie das Projekt ausführen, sollten Sie, wie zuvor, ein Datenraster sehen. Wenn Sie jedoch in das Menü Add-Ons klicken, sollte jetzt ein Verweis auf das neu erstellte Add-On angezeigt werden.


Wenn wir auf den Menüpunkt Managerbericht klicken, wird ein Methodenaufruf für die in unserem Add-On implementierte OnClick-Methode ausgeführt, wodurch UIReportAddon1Form so angezeigt wird.


Abschluss
Wir haben zwei Beispiele für die Erstellung einer Anwendung gesehen, mit der Add-Ons nach Bedarf abgerufen und ausgeführt werden können. Wie bereits erwähnt, sollte es einfach genug sein, diese Art von Funktionalität in vorhandene Anwendungen zu integrieren. Die Frage, wie viel Kontrolle Sie benötigen (oder wollen), um Entwicklern von Drittanbietern zu geben, ist eine ganz andere Frage.
Ich hoffe Sie haben Spaß mit diesem Tutorial! Vielen Dank fürs Lesen!



