Announcement

Collapse
No announcement yet.

Globale Fremdkomponenten-Variablen

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Globale Fremdkomponenten-Variablen

    Hallo Herr Kosch,
    eine Frage bezüglich dem Handling von globalen Variablen. Ich habe mir für einfache Datentypen zwei Klassen angelegt global.cs und classGlobal.cs um diese formularübergreifend zu nutzen. Das funktioniert auch. Kann ich Fremdkomponenten (eigene Klasse) ähnlich handeln? Hier mal Codeausschnitte:
    public class Global
    {
    public Global()
    {
    }
    public Global(short Zonen, int Baudrate, short Port, short Streuer, double ZoomFaktor)
    {
    _Zonen = Zonen;
    _Baudrate = Baudrate;
    _Port = Port;
    _Streuer = Streuer;
    _ZoomFaktor = ZoomFaktor;
    }

    private short _Zonen;
    private int _Baudrate;
    private short _Port;
    private short _Streuer;
    private short _Zone1;
    private short _Zone2;
    private short _Zone3;
    private short _Zone4;
    private short _Zone5;
    private double _ZoomFaktor;
    // Fremdkomponente
    private GpsToolsNET.NmeaParser _objParserGlobal;

    public GpsToolsNET.NmeaParser objParserGlobal
    {
    get {return(_objParserGlobal);}
    set {_objParserGlobal = value;}
    }

    public short Zonen
    {
    get {return(_Zonen);}
    set {_Zonen = value;}
    }
    ....
    Dann die classGlobal.cs
    public class ClassGlobal
    {
    public ClassGlobal()
    {
    }
    public static AgroSenseSmartApplikation.Global clsGlobal = null;
    public static void InitMain()
    {
    if (clsGlobal == null)
    clsGlobal = new AgroSenseSmartApplikation.Global();
    }
    public static GpsToolsNET.NmeaParser ReadParser()
    {
    return clsGlobal.objParserGlobal;
    }
    public static short ReadZonen()
    {
    return clsGlobal.Zonen;
    }
    ....
    Und nun der Aufruf in einer Form...

    //Setzten von Eigenschaften
    AgroSenseSmartApplikation.ClassGlobal.clsGlobal.Zo nen = 3;
    //Lesen von Werten
    AgroSenseSmartApplikation.FormSetup aGlobal = new AgroSenseSmartApplikation.FormSetup();
    int i = AgroSenseSmartApplikation.ClassGlobal.ReadZonen();
    *Das funktioniert so weit
    Bei den Fremdkomponentenklassen bin ich mir nicht so sicher

    AgroSenseSmartApplikation.ClassGlobal.clsGlobal.ob jParserGlobal = new GpsToolsNET.NmeaParser();
    AgroSenseSmartApplikation.ClassGlobal.clsGlobal.ob jParserGlobal.PortEnabled = true;
    .....

    Könnten Sie mit mal die Klassen ansehen ob man so damit verfahren kann...

    Wagner

  • #2
    Hallo,

    prinzipiell führt diese Vorgehensweise zum Ziel, ich würde nur wenige Punkte ändern. Damit meine Antwort besser nachvollziehbar ist, habe ich ein eigenes Beispiel vorbereitet. In der Solution (Projektgruppe) habe ich dazu das Unterverzeichnis <i>SharedData</i> angelegt, in dem die beiden Klassen <i>ClassData.cs</i> und <i>ClassGlobal.cs</i> abgelegt werden. VS.NET verwendet den Verzeichnisnamen dabei automatisch im Namespace der angelegten Klasse.
    <br>
    a) Die Klasse mit den gemeinsam zu nutzenden Daten stellt u.a. eine Eigenschaft für eine Form-Instanz zur Verfügung, diese Form-Instanz entspricht somit einer Fremdkomponentenklasse (das ist zwar nicht ein ideales Beispiel, geht aber am schnellsten):
    <code>
    <b>using</b> System;
    <b>using</b> System.Windows.Forms;

    <b>namespace</b> SharedData.SharedData
    {
    <b>public</b> <b>class</b> ClassData
    {
    <b>public</b> ClassData()
    {
    }
    <br>
    <b>private</b> <b>string</b> sGlobalerWert;
    <b>private</b> Form aDynForm;
    <br>
    <b>public</b> <b>string</b> GlobalerWert
    {
    get { <b>return</b> sGlobalerWert; }
    set { sGlobalerWert = value; }
    }
    <br>
    <b>public</b> Form DynForm
    {
    get { <b>return</b> aDynForm; }
    set { aDynForm = value; }
    }
    }
    }
    </code>
    b) Die Singleton-Klasse liefert immer die gleiche ClassData-Instanz zurück (über <b>lock</b> wird das Threadsicherer). Der Default Constructor wird dabei über <b>private</b> "versteckt", so dass es keine Missverständnisse über das Verhalten der Klasse geben kann. Jeder "Client", der die gemeinsam genutzten Daten haben möchte, muss über die öffentliche statische Methode <b>GetSingletonInstance</b> einen Verweis abholen:
    <code>
    <b>using</b> System;
    <br>
    <b>namespace</b> SharedData.SharedData
    {
    <b>public</b> <b>class</b> ClassGlobal
    {
    <font color="#003399"><i>// Default-Constructor als private verstecken</i></font>
    <b>private</b> ClassGlobal()
    {
    }
    <br>
    <font color="#003399"><i>// Sperrobjekt für Multithread-Zugriffe</i></font>
    <b>private</b> <b>static</b> <b>object</b> aLockObj = <b>new</b> <b>object</b>();
    <font color="#003399"><i>// Ablageplatz für die Singleton-Instanz</i></font>
    <b>private</b> <b>static</b> ClassData aInstance = <b>null</b>;
    <br>
    <b>public</b> <b>static</b> ClassData GetSingletonInstance()
    {
    <b>lock</b>(aLockObj)
    {
    <b>if</b> (aInstance == <b>null</b>)
    aInstance = <b>new</b> ClassData();
    <b>return</b> aInstance;
    }
    }
    }
    }
    </code>
    c) Die Anwendung besteht aus 3 Formularen, die gemeinsam auf die Daten zugreifen.
    <br>
    d) Das Hauptformular erzeugt DynForm, aber zeigt es nicht an. Erst dann, wenn im zusätzlich erzeugten/angezeigten Form1 der Button angeklickt wird, ist DynForm sichtbar (d.h. Form1 greift auf die "Fremdkomponenteninstanz" zu, die FormMain erzeugt hat):
    <code>
    <b>private</b> <b>void</b> button1_Click(<b>object</b> sender, System.EventArgs e)
    {
    SharedData.ClassData aCG = SharedData.ClassGlobal.GetSingletonInstance();
    aCG.GlobalerWert = <font color="#9933CC">&quot;Test&quot;</font>;
    aCG.DynForm = <b>new</b> Form();
    aCG.DynForm.Text = <font color="#9933CC">&quot;DynForm in FrmMain erzeugt&quot;</font>;
    Form1 aFrm = <b>new</b> Form1();
    aFrm.ShowDialog();
    }
    </code>
    e) Form1 zeigt das von FormMain erzeugte DynForm an: Über die <b>statische</b> Methode <i>GetSingletonInstance</i> kann direkt der Verweis auf die Singleton-Klasse mit den gemeinsam genutzten Daten abgefordert werden:
    <code>
    <b>private</b> <b>void</b> button1_Click(<b>object</b> sender, System.EventArgs e)
    {
    SharedData.ClassData aCG = SharedData.ClassGlobal.GetSingletonInstance();
    aCG.DynForm.Show();
    MessageBox.Show(aCG.GlobalerWert);
    }
    </code>
    e) Form2 prüft, ob in den gemeinsam genutzten Daten eine gültige Form-Instanz abrufbar ist, um ebenfalls auf die von FormMain definierten Daten zuzugreifen:
    <code>
    <b>private</b> <b>void</b> buttonForm2_Click(<b>object</b> sender, System.EventArgs e)
    {
    SharedData.ClassData aCG = SharedData.ClassGlobal.GetSingletonInstance();
    <b>if</b> (aCG.DynForm != <b>null</b>)
    {
    aCG.DynForm.Show();
    MessageBox.Show(aCG.GlobalerWert);
    }
    }
    </code&gt

    Comment


    • #3
      Danke Herr Kosch,

      funktioniert soweit prima. Ich habe aber scheinbar noch ein paar Probleme, ich denke mit dem Aufräumen von Resourcen. Wenn ich zum Beispiel ein neues PocketPC Formular erzeuge und anzeige:

      MapForm frm = new MapForm();
      frm.ShowDialog();

      damit schient die Globale Fremdkomponente nicht zu laufen.
      mit "frm.Show();" läuft Sie, aber beim Schließen des Fensters über rechts oben "OK" wird das Fenster nur in den Hintergrund gelegt und nicht geschlossen und somit auch nicht aufgeräumt (Dispose). Bei "frm.ShowDialog()" kann ich "this.Close()" und alle Events wie Onclosing ausführen.
      Wie kann ich denn bei einem normalen Fenster auf das Drücken des OK-Buttons als Beenden-Button reagieren?

      Irgendwie schienen auch Resourcen der Fremdkomponente nicht richtig über den Fensterwechsel zu kommen.

      private void MapForm_Load(object sender, System.EventArgs e)
      {
      if (aCG.objParserGlobal != null)
      {
      // Hinzufügen von Eventhandlers
      aCG.objParserGlobal.OnComStatus += new GpsTools.OnComStatus(objParser_OnComStatus);
      aCG.objParserGlobal.Generic += new GpsToolsNET.Generic(objParser_Generic);
      aCG.objParserGlobal.OnSatellites += new GpsToolsNET.OnSatellites(objParser_OnSatellites);
      }
      }

      private void objParser_Generic(GpsToolsNET.NmeaSentence sentence)
      {
      m_cnt++;
      lCnt.Text = m_cnt.ToString();
      //System.Diagnostics.Debug.Write(sentence.Command);
      sentence.Dispose();
      }

      Aufruf von Events in einem Formular im OnLoad-Ereignis führen beim Schließen über this.Close() zu folgenden Fehlermeldungen:
      "Eine verwaltete ObjectDisposedException ist ..aufgetreten.
      MISC:: HandleAr...
      Control::get_Text ...
      Control::Set_Text ...
      MapForm:bjParser_Generic...
      NmeaParser:oEvent...
      NmeaParser::m_dispatch..."

      Ein Startformular erzeugt das globale Objekt aCG und startet dieses, auf den anderen Seiten sollten über Ereignisse dieses benutzt werden. Gestoppt würde das FremdObjekt wieder auf der Startseite (GPS Start | GPS-Stop). Das hat aber so wie es aussieht einige Tücken. Vielleicht fällt Ihnen hierzu auch etwas ein.

      Besten Dank im Voraus

      Wagne

      Comment

      Working...
      X