Laden...

Objekt aus VSIXCommand an Projekt weiter geben

Erstellt von c#nup vor 5 Jahren Letzter Beitrag vor 5 Jahren 1.675 Views
C
c#nup Themenstarter:in
19 Beiträge seit 2017
vor 5 Jahren
Objekt aus VSIXCommand an Projekt weiter geben

Hallo community,

ich habe eine Visual Studio Extension (VSIX) mit einem Command geschrieben. Auf Knopfdruck passiert im Command im Wesentlichen folgendes:

DatenManager datenManager = new DatenManager();
DatenManager.holDaten();

Dieses Command kann vom VS Nutzer zu einem beliebigen Zeitpunkt ausgelöst werden - direkt nach dem Start, noch bevor ein Projekt ausgewählt oder angelegt wurde, oder auch Mitten in der Arbeit an einem Projekt.

Nun möchte ich das datenManager-Objekt innerhalb eines Projekts zugänglich machen, sodass der Programmierer zu Lebzeiten der VS-Instanz die im Datenmanager enthaltenen Daten nutzen kann.

Sinngemäß also sowas:

VisualStudioInstance.GlobalObjectCache.add(datenManager) // das würde noch im Command passieren
...
...
try{
DatenManager dm = (DatenManager)VisualStudioInstance.GlobalObjectCache.GetObject("datenManager")
}
// ab hier wird dann innerhalb eines Projekts mit den Daten aus dem Datenmanager gearbeitet
...

Überall ist zu lesen, dass VS absolut erweiterbar und konfigurierbar ist, also gehe ich davon aus, dass es einen realen Gegenpart zu meinem erfundenen "VisualStudioInstance.GlobalObjectCache" geben muss.

Kann mich bitte jemand aufschlauen.

16.806 Beiträge seit 2008
vor 5 Jahren

Kannst Du mal ganz neutral erklären, was Du wirklich tun willst - ohne hier vom expliziten Code zu sprechen?

Also: was willst Du tun? Wozu die Extension?

C
c#nup Themenstarter:in
19 Beiträge seit 2017
vor 5 Jahren

Hi Abt,

die Extension implementiert ein Command, einen Button in der Werkzeugleiste von VS. Wird dieser Button gedrückt, wird eine Liste von Strukturen aus einer nicht statischen Quelle geladen, wobei jede Struktur aus einem string "Name" und einer List<string> "Werte" besteht. Der Ladevorgang für diese Strukturen, die geladenen Strukturen und einiges mehr, sind implementiert in einem Singleton-Objekt den ich in meinem Eingangspost "datenManager" genannt habe. Das ganze geschieht unabhängig davon ob und welche Art von Projekt in VS gerade bearbeitet wird. Bis hierhin Funktioniert alles wie gewünscht.

Eine Anwendung für die geladenen Strukturen soll sein:

  1. Man lege eine Control-Klasse an, die von einem beliebigen Windows.Forms Control erbt und versehe diese Klasse mit zusätzlichen Eigenschaften e1 und e2.
  2. Man erstelle ein neues Form-Projekt in VS, ziehe eines dieser "eigenen Controls" auf den Form und gehe zu den Eigenschaften e1 und e2 im Eigenschaften-Fenster.
  3. An dieser Stelle werden die geladenen Daten aus dem "datenManager" benötigt. Im einfachsten Fall erhalten e1 und e2 im Eigenschaftenfenster Dropdowns mit den "Namen" der Strukturen und den dazu gehörenden Werten aus den List<string>.
    Das programatische Anlegen von Dropdowns für Eigenschaften im Eigenschaftenfenster funktioniert soweit (- zumindestens im einem Entwurf, aber an dieser Stelle muss ich später noch mehr arbeiten).

Mein Problem ist, dass ich zum Zeitpunkt 3. nicht auf den "datenManager" zugreifen kann, den ich bei der Ausführung des Commands initialisiert habe. Aus dem Bauch heraus stelle ich mir eine Lösung vor, bei der ich das "datenManager"-Objekt nach der Initialisierung in einem "VisualStudio-globalen" Bereich ablege und von dort abrufe. Ich bin da aber sehr ahnungslos und deshalb offen für andere Vorschläge.

16.806 Beiträge seit 2008
vor 5 Jahren

Nochmal die Bitte: kannst Du mal neutral formulieren, was Du tun willst?

Keiner hier, kann was mit Datenmanager anfangen.
Es ist nicht ersichtlich, was das sein soll.

Was genau eine Extension einer Entwicklungsumgebung dann inhaltlich mit einer Anwendung zutun haben soll: es erschließt sich - zumindest mir - null.

Natürlich kann man in einem .NET Programm nicht auf "irgendwelche" Objekte einer anderen Anwendung zugreifen; jedenfalls nicht einfach so.
Selbstverständlich kann daher eine .NET Anwendung niemals ein Objekt kennen, das in einer Visual Studio Extension läuft. So funktioniert kein .NET und im Endeffekt überhaupt Windows auch nicht.

Visual Studio - auch mit einer Extension - hat null mit der .NET Applikation am Hut, die Du in dem Editor entwickelst.
Visual Studio ist eben NUR ein Editor. Das solltest Du verstehen.

Du kannst genauso jedes .NET Programm mit Nodepad und Kommandozeile entwickeln.
Daher nochmal: was genau hast Du vor?

PS: und von Gedanken wie "globalen Objekten" solltest Du ganz ganz weiteren Abstand nehmen.
That's evil!

4.931 Beiträge seit 2008
vor 5 Jahren

Warum möchtest du diese Daten schon im Entwurfsmodus für die Eigenschaften festlegen?
Macht es nicht mehr Sinn, diese zur Laufzeit zu laden (z.B. aus einer XML-Datei o.ä. - Stichwort: Serialisierung)?

C
c#nup Themenstarter:in
19 Beiträge seit 2017
vor 5 Jahren

@Abt
Ich versuche mal nachher an einem Beispiel zu demonstrieren um was es mir geht. Vielleicht wird es dann klarer.

@Th69
Es ist halt so gefordert, dass die Daten an dieser Stelle verfügbar sein müssen. Der Entwickler des Forms soll zu dem Zeitpunkt wenn er ein Control plaziert auch die betreffenden Eigenschaften händisch festlegen. Dabei soll er aus einer festgelegten Menge an Werten auswählen. Die Werte werden bei bei jedem Bearbeitungsvorgang, von einem anderen System neu geladen.

C
c#nup Themenstarter:in
19 Beiträge seit 2017
vor 5 Jahren

Ok, die zip mit den Projekten ist zu groß, deshalb hänge ich hier die zwei relevanten .cs Dateien an.

  1. Ich habe mir ein VSIX Projekt namens "MeinCommand" angelegt wie zB hier beschrieben. In diesem VSIX Projekt habe ich ein Command "Mein Command" eingefügt. Die entsprechende Datei "MeinCommand.cs" ist im Anhang. Zu beachten sind die Includes:
using System.Runtime.InteropServices;
using EnvDTE;

und das was in der Methode Execute() passiert:

         private void Execute(object sender, EventArgs e)
        {
            DTE dte = (DTE)Marshal.GetActiveObject("VisualStudio.DTE.15.0"); // bei VisualStudio 2017
            //DTE dte = (DTE)Marshal.GetActiveObject("VisualStudio.DTE.14.0"); // bei VisualStudio 2015
            Globals globals = dte.Globals;

            string s = "";

            try
            {
                s = (string)globals["meinGlobalVar"];
                MessageBox.Show("Der Wert meiner globalen Variable ist: " + s);
            }
            catch(Exception ex)
            {
                globals["meinGlobalVar"] = "los gehts";
                MessageBox.Show("Meine globale Variable wird mit 'los gehts' initialisiert");
            }
        }

Diese Extension erweitert mein VisualStudio um die Option "Invoke MeinCommand" im "Extras" Menü (in der englischen Version ist es das Tools Menü). Durch einen Click auf diese Option wird die Methode "Execute" ausgeführt.

  1. Nachdem ich die VS Extension compiliert und installiert habe, habe ich eine stinknormale Konsolenanwendung angelegt - siehe Program.cs. Einziger relevanter Inhalt:
  static void Main(string[] args)
        {
            DTE dte = (DTE)Marshal.GetActiveObject("VisualStudio.DTE.15.0");
            Globals globals = dte.Globals;

            string s = globals["meinGlobalVar"];

            MessageBox.Show(s);

            globals["meinGlobalVar"] = "zweiter Schritt";
        }

Diese Konsolenanwendung starte ich direkt aus VS.

  1. Es ist nur eine VS Instanz offen und zwar die mit der Konsolenanwendung. Die Konsolenanwendung ist nicht gestartet. Durch einen Click auf "Invoke MeinCommand" lege ich in der VS Extension im Globals Interface das Name/Wert Paar namens "meinGlobalVar" und initialisiere es mit dem Wert "los gehts". Nun starte ich die Konsolenanwendung und und rufe hier das Globals Interface (nach meinem bisherigen Verständnis gehört es zur aktiven VisualStudio Instanz) ab, genauer das gerade eben angelegte Name/Wert Paar "meinGlobalVar" und OH WUNDER mein string s bekommt den Wert "los gehts". Dann weise ich dem Name/Wert Paar den string-Wert "zweiter Schritt" zu und klicke wieder auf das Command "Invoke MeinCommand" - OOOH, NOCH EIN WUNDER in der VS Extension kommt der gerade eben gesetzte Wert "zweiter Schritt" zum Vorschein.

Das ist im Grunde die Funktionalität auf die ich aus bin - nur solle statt Strings beliebige Objekte geteilt werden.


Auf das DTE.Globals Interface bin ich erst heute im Tagesverlauf gestoßen. So ganz bin ich da noch nicht durchgestiegen, aber es scheint so ziemlich das zu sein, was ich mir als Lösung für mein Problem vorstelle. Mir ist aber noch nicht gelungen beliebige Objekte über dieses Interface hin und her zu schieben (so wie die strings im obigen Beispiel).

Für eure konstruktive Beiträge bin ich weiterhin dankbar.

C
c#nup Themenstarter:in
19 Beiträge seit 2017
vor 5 Jahren

hier noch die andere .cs