Hallo,
ich, als kleiner blutiger Programmier Anfänger, versuche seid geraumer Zeit ein kleines Programm [c#] auf Basis von einem mit MEF basierenden Plugin System zu schreiben.
Das eigentliche Plugin System wollte ich gerne in c# WPF realisieren. Ich habe bereits eine Grundstruktur eingebaut die auch funktioniert. Jedoch hänge ich jetzt an einem Problem wo ich trotz langem suchens nicht weiterkomme.
Ich beschreibe am besten erst einmal mein Vorhaben um es etwas zu konkretisieren und Missverständnisse vorzubeugen.
Also Mein Programm ist soll ein recht Simples Plugin System sein.
Es gibt das Main "Host" Project, 1-Project mit dem Interface/Metadata, 1-Project pro Plugin.
1Project
Host Project
Project
|-Interface
|-Metadata
Project
1.Plugin
Project
2.Plugin
.
.
.
Jedes Plugin soll in erster Linie in das Main Project eingebunden werden. (Gradlinig gesehen funktioniert das auch) Jedoch soll eine Unterscheidung der Plugins stattfinden da nicht unbedingt jedes Plugin im Main Fenster angezeigt werden soll, für diese Unterscheidung habe ich mir gedacht mache ich mir die Metadaten zu nutze. Sprich: Dem Plugin sollen Metdaten mitgegeben werden wie z.B. MyName, ProgrammTeil (Main, Optionen, Sonstiges), Kategorie usw.
Im Host teil sollen diese Plugins ausgelesen werden und zugeordnet werden.
Soweit meine erste Idee.
Nun zum eigentlichen Problem:
Plugins auslesen -> Funktioniert
Plugins -> Metdaten abfrage (in der reinen Natur funktioniert)
Plugin -> In Tabs anzeigen (in der reinen Natur funktioniert)
Also alle Plugins sollen ausgelesen werden (Funktioniert) von diesen Plugins sollen Metadaten abgefragt werden werden was an und für sich auch funktioniert. Das heißt es wird zum Bleistift abgefragt welche Sprache das Plugin hat (testhalber hat 1Plug German / 1Plug English). Diese Plugins sollen dann einen Tab aufbauen (Dieser Tab soll von den Plugins erstellt werden (also die TabPages). Jedoch habe ich das Problem das ich es nicht hinbekomme das passend zu kombinieren.
Entweder. Wird die Metadaten Abfrage zwar durchgeführt aber ignoriert so das dennoch beide Plugins in die tabs geladen wird.
Oder. Die Tabs werden aufgebaut jedoch ohne die Metadaten mitzuliefern so das ich nur die TabPage (Überschrift sehe) aber nicht meine Form. Sprich das Object wird nicht angesprochen.
Ausserdem habe ich ein Problem mit dem WPF was aber zusammenhängt mit der Bindung an dem TabPage. auf den Bildern die ich noch mitsende sollte mehr oder weniger herauszusehen sein was das Problem nun genau ist.
So für den Anfang gebe ich natürlich noch ein bissl Code mit.
Interface
InterfaceMetadata - Beispiel: Anhand des Namens
CodeBehind eines Plugins:
Main der eigentliche Import
Ich habe mal ein bisschen getestet mit den verschiedenen Katalog aufbauten... will an dieser Stell einfach mal nur 2 Beispiele nennen
1-Beispiel
2-Beispiel
Jetzt ein Beispiel wie ich mir das entsprechende Item in zB. panel anzeigen lassen kann
foreach (var ext in this.Extensions)
{
if (ext.Metadata.DisplayName == "App1")
{
var ctl = ext.Value.GetView();
this.viewContainer.Children.Add(ctl);
}
Hier wird auch gleich eine Abfrage gemacht wie ich das entsprechende Item zuordnen kann mit zB if Abfrage.
Jetzt das ganze nocheinmal jedoch mit einem Databinding
Hier wird die Abfrage auch ausgeführt jedoch werden dennoch beide bzw. Alle Plugins eingeladen und im TabControl angezeigt (wenn auch fehlerhaft)
Im Anhang findet ihr zum einen 2 Bilder so wie ich mir das vorstelle mit dem TabAufbau (jedoch in einer WinForm)
Dazu habe ich eine Demo dazugepackt wo der Rohkunstrukt vorhanden ist eigentlichen Programm sprich. Metadaten Ex/Import. Abfrage der Metadaten und ausgabe via Button in einem Panel (container) und als WPF.
Bei fragen etc.. fragt einfach
ich, als kleiner blutiger Programmier Anfänger, versuche seid geraumer Zeit ein kleines Programm [c#] auf Basis von einem mit MEF basierenden Plugin System zu schreiben.
Das eigentliche Plugin System wollte ich gerne in c# WPF realisieren. Ich habe bereits eine Grundstruktur eingebaut die auch funktioniert. Jedoch hänge ich jetzt an einem Problem wo ich trotz langem suchens nicht weiterkomme.
Ich beschreibe am besten erst einmal mein Vorhaben um es etwas zu konkretisieren und Missverständnisse vorzubeugen.
Also Mein Programm ist soll ein recht Simples Plugin System sein.
Es gibt das Main "Host" Project, 1-Project mit dem Interface/Metadata, 1-Project pro Plugin.
1Project
Host Project
Project
|-Interface
|-Metadata
Project
1.Plugin
Project
2.Plugin
.
.
.
Jedes Plugin soll in erster Linie in das Main Project eingebunden werden. (Gradlinig gesehen funktioniert das auch) Jedoch soll eine Unterscheidung der Plugins stattfinden da nicht unbedingt jedes Plugin im Main Fenster angezeigt werden soll, für diese Unterscheidung habe ich mir gedacht mache ich mir die Metadaten zu nutze. Sprich: Dem Plugin sollen Metdaten mitgegeben werden wie z.B. MyName, ProgrammTeil (Main, Optionen, Sonstiges), Kategorie usw.
Im Host teil sollen diese Plugins ausgelesen werden und zugeordnet werden.
Soweit meine erste Idee.
Nun zum eigentlichen Problem:
Plugins auslesen -> Funktioniert
Plugins -> Metdaten abfrage (in der reinen Natur funktioniert)
Plugin -> In Tabs anzeigen (in der reinen Natur funktioniert)
Also alle Plugins sollen ausgelesen werden (Funktioniert) von diesen Plugins sollen Metadaten abgefragt werden werden was an und für sich auch funktioniert. Das heißt es wird zum Bleistift abgefragt welche Sprache das Plugin hat (testhalber hat 1Plug German / 1Plug English). Diese Plugins sollen dann einen Tab aufbauen (Dieser Tab soll von den Plugins erstellt werden (also die TabPages). Jedoch habe ich das Problem das ich es nicht hinbekomme das passend zu kombinieren.
Entweder. Wird die Metadaten Abfrage zwar durchgeführt aber ignoriert so das dennoch beide Plugins in die tabs geladen wird.
Oder. Die Tabs werden aufgebaut jedoch ohne die Metadaten mitzuliefern so das ich nur die TabPage (Überschrift sehe) aber nicht meine Form. Sprich das Object wird nicht angesprochen.
Ausserdem habe ich ein Problem mit dem WPF was aber zusammenhängt mit der Bindung an dem TabPage. auf den Bildern die ich noch mitsende sollte mehr oder weniger herauszusehen sein was das Problem nun genau ist.
So für den Anfang gebe ich natürlich noch ein bissl Code mit.
Interface
Code:
using System.Windows.Controls;
namespace Contracts
{
public interface IExtension
{
UserControl GetView();
}
}
InterfaceMetadata - Beispiel: Anhand des Namens
Code:
using System;
using System.ComponentModel;
using System.ComponentModel.Composition;
namespace Contracts
{
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class)]
public class ExtensionExportAttribute : ExportAttribute, IModuleMetadata
{
public string DisplayName { get; private set; }
public ExtensionExportAttribute(Type contractType, string displayName)
: base(contractType)
{
this.DisplayName = displayName;
}
}
public interface IModuleMetadata
{
[DefaultValue("Extension")]
string DisplayName { get; }
}
}
CodeBehind eines Plugins:
Code:
using System.Windows.Controls;
using System.ComponentModel.Composition;
using Contracts;
namespace Extension1
{
//[Export(typeof(IExtension))]
[ExtensionExport(typeof(IExtension), "App2")]
public class Extension1 : IExtension
{
private UserControl1 _view;
public UserControl GetView()
{
if (_view == null)
_view = new UserControl1();
return _view;
}
}
}
Code:
[ImportMany(AllowRecomposition = true)]
public IEnumerable<Lazy<IExtension, IModuleMetadata>> Extensions { get; set; }
1-Beispiel
Code:
var Catalog = new AggregateCatalog(new ComposablePartCatalog[]
{
new AssemblyCatalog(Assembly.GetExecutingAssembly()),
new DirectoryCatalog(".")
});
var _container = new CompositionContainer(Catalog);
var batch = new CompositionBatch();
batch.AddPart(this);
_container.Compose(batch);
Code:
string strPath = System.Windows.Forms.Application.StartupPath;
using (var Catalog = new AggregateCatalog())
{
DirectoryCatalog directorywatcher = new DirectoryCatalog(strPath, ".");
Catalog.Catalogs.Add(directorywatcher);
CompositionBatch batch = new CompositionBatch();
batch.AddPart(this);
CompositionContainer container = new CompositionContainer(Catalog);
//get all the exports and load them into the appropriate list tagged with the importmany
container.Compose(batch);
}
foreach (var ext in this.Extensions)
{
if (ext.Metadata.DisplayName == "App1")
{
var ctl = ext.Value.GetView();
this.viewContainer.Children.Add(ctl);
}
Hier wird auch gleich eine Abfrage gemacht wie ich das entsprechende Item zuordnen kann mit zB if Abfrage.
Jetzt das ganze nocheinmal jedoch mit einem Databinding
Code:
foreach (var ext in this.Extensions)
{
if (ext.Metadata.DisplayName == "App1")
{
var ctl = ext.Value.GetView();
DataContext = from p in Extensions
select new { Title = p.Metadata.DisplayName, Page = ctl };
}
Im Anhang findet ihr zum einen 2 Bilder so wie ich mir das vorstelle mit dem TabAufbau (jedoch in einer WinForm)
Dazu habe ich eine Demo dazugepackt wo der Rohkunstrukt vorhanden ist eigentlichen Programm sprich. Metadaten Ex/Import. Abfrage der Metadaten und ausgabe via Button in einem Panel (container) und als WPF.
Bei fragen etc.. fragt einfach