Laden...

Variable von Thread A nach Thread B geben

Erstellt von Dumpfbacke vor 5 Jahren Letzter Beitrag vor 5 Jahren 1.842 Views
D
Dumpfbacke Themenstarter:in
11 Beiträge seit 2016
vor 5 Jahren
Variable von Thread A nach Thread B geben

Hallo,

ich möchte in einer Form Werte aus einer anderen Klasse die in in enem anderen Thread laüft anzeigen.
Zum Überegben der Variable aus der Klasse in die Form verwende ich ein Property.
Nun möchte ich mit Invoke den Aufruf für die Übergabe des Wertes in das Label der GUI machen.

In der Form sieht das bei mir so aus:

// Delegate deklarieren
        private delegate void delegate1();
        string string2;

        //public propertey für den Variablenaustausch zwischen den Klassen
        public string SetTextImTextBoxAufFom1
        {
            set
            {
                string2 = value;
                this.Invoke(new delegate1(wertInsGUI));  // Aufruf "threadsicher"
            }
        }

        // Wert in da label übetragen
        private void wertInsGUI()
        {
            label1.Text = string2;
        }

und hier der Aufruf der Property in der Klasse die den Wert zur Verfügung stellt:

// Variable an "Mainframe" übergeben
        private void timer1ElapsedEvent(Object source, ElapsedEventArgs e)
        {
            zaehler++;
            Program.MainFrame.SetTextImTextBoxAufFom1 = zaehler.ToString();
        }

Nun möchte ich aber den Wert der Methode als Parameter übergeben:
das sieht bei mir so aus:

// Delegate deklarieren
        private delegate void delegate2(string value);
      
        //public propertey für den Variablenaustausch zwischen den Klassen
        public string SetTextImTextBoxAufFom1_2
        {
            set
            {
                this.Invoke(new delegate2(wertInsGUI2(value)));  // Aufruf "threadsicher"
            }
        }

        // Wert in das label übetragen
        private void wertInsGUI2(string value)
        {
            label2.Text = value;
        }

nun weiss ich aber nicht wie ich den Aufruf inklusive Parameterübergabe machen kann...
dieser Aufruf produziert immer den Fehler > Fehlermeldung:

Fehler: Methodenname erwartet

this.Invoke(new delegate2(wertInsGUI2(value)));

ich bin für jede Anregunf dankbar....

danke, Dumpfbacke

16.842 Beiträge seit 2008
vor 5 Jahren

Erklär doch mal, was Du vor hast - nicht wie.
Vermutlich stimmt schon der Anfang nicht, wenn ich das richtig verstehe.

Eine Klasse selbst kann nicht in einem anderen Thread "liegen", sondern nur Operationen können in anderen Threads ausgeführt werden.

Suchst Du evtl. [FAQ] Kommunikation von 2 Forms
[FAQ] Controls von Thread aktualisieren lassen (Control.Invoke/Dispatcher.Invoke)

D
Dumpfbacke Themenstarter:in
11 Beiträge seit 2016
vor 5 Jahren

Hallo,

ich habe eine Klasse gebaut die Werte aus einer SPS Steuerung liest.
Diese Klasse soll im Sekundentakt (später möchte ich das über einen backgroundworker machen und die Werte zur Form übertragen wenn dieser alle Werte aus der Stuerung gelesen hat) zur Form übertragen.

Nun habe ich das Senden der Werte zur Form über eine Property gemacht (Codeauszug erstes Post), soweit richtig?

Wenn ich nun Versuche in der Form das label direkt über die Property mit dem neuen Wert zu versorgen sagt mir der Debugger "Cross-thread operation not valid: Control 'label1' accessed from a thread other than the thread it was created on."

darum habe ich nun den das Update des laberwertes über Invoke versucht.
Hat auch soweit funktioniertm, nur möchte ich nun noch die Übergabe des Wertes an die invokemethode über Paramter machen.

und das funktioniert so nicht bei mir:

this.Invoke(new delegate2(wertInsGUI2(value)));

hier der ganze invokeaufruf:

// Delegate deklarieren
        private delegate void delegate2(string value);

        //public propertey für den Variablenaustausch zwischen den Klassen
        public string SetTextImTextBoxAufFom1_2
        {
            set
            {
                this.Invoke(new delegate2(wertInsGUI2(value)));  // Aufruf "threadsicher"
            }
        }

        // Wert in das label übetragen
        private void wertInsGUI2(string value)
        {
            label2.Text = value;
        }

...oder ist hier mein Ansatz grundlegend falsch?

Danke, Dumpfbacke

4.942 Beiträge seit 2008
vor 5 Jahren

Bei Invoke mußt du die Parameter getrennt übergeben:


this.Invoke(new delegate2(wertInsGUI2), value);

Oder du nimmst die Variante mittels des Action-Delegates aus dem FAQ-Artikel (DoCheapGuiAccess).

Es geht auch noch die Lambda-Variante:


this.Invoke((Action)(() => wertInsGUI2(value)));

16.842 Beiträge seit 2008
vor 5 Jahren

Ich weiß nicht ganz, auf welchem Kenntnisstand Du bist - aber ein Backgroundworker ist halt schon sehr veraltet und konzeptiell gibt es bessere Wege.

Was Du hier hast ist Event Driven; und dafür gibt es Reactive Extensions, dank dem sich sowas super schnell und einfach umsetzen lässt.
Man muss sich etwas umgewöhnen; ist aber deutlich sauberer als über direkte Fummelei in der UI.

Verwende ich selbst bei den meisten Programmen - und ich bin auch im Maschinenumfeld tätig.

D
Dumpfbacke Themenstarter:in
11 Beiträge seit 2016
vor 5 Jahren

Hallo,

Danke! Paramterübergabe klappt so!

mfg

D
Dumpfbacke Themenstarter:in
11 Beiträge seit 2016
vor 5 Jahren

Hallo,
Danke für die Antwort
Tatsächlich bin ich nicht der C# Experte, bin mehr auf der SPS zuhause.

Ich finde die Implementation mit dem Backgroundworker nicht soo aufwendig.
Was ist der Vorteil mit Reactive Extensions, so wie du es machst?

Danke, mfg

Hinweis von Abt vor 5 Jahren

Bitte keine Full Quotes
[Hinweis] Wie poste ich richtig?

D
Dumpfbacke Themenstarter:in
11 Beiträge seit 2016
vor 5 Jahren

Hallo,

Danke! Paramterübergabe klappt so!

mfg

Hinweis von Abt vor 5 Jahren

Bitte keine Full Quotes
[Hinweis] Wie poste ich richtig?

16.842 Beiträge seit 2008
vor 5 Jahren

Hallo,
Was ist der Vorteil mit Reactive Extensions, so wie du es machst?

Es ist einfach ein viel moderneres Konzept.

Deine gesamte Anwendung kennt einen State - und überwacht diese.
Zum State gehören zB. die eintrudelnden Nachrichten.

Mit Hilfe von Subscriptions kann der State überwacht werden und damit Deine komplette Applikation, jede Komponente, jedes Windows aktualisiert werden - ohne in der UI direkt umwerken zu müssen.

Beispiel: ich überwache eingehende SPS Nachrichten - mein SPS State - und zeige diese in einer RichTextBox an.
Folgender Code genügt dafür:

    public partial class DemoForm : Form
    {
        public DemoForm(ISpsService spsService)
        {
            InitializeComponent();

            AddSubscription = spsService.Message
                .ObserveOn(LogBox)
                .Subscribe(x =>
                {
                    string msg = $"[{x.Timestamp:HH:mm:ss}] - {x.Message}" + Environment.NewLine;
                    LogBox.Text = LogBox.Text.Insert(0, msg);
                });
        }

        public IDisposable AddSubscription { get; set; }
    }

Die Zeile

.ObserveOn(LogBox)
 .Subscribe(x =>

macht quasi alles das, was Du mit Deinem Backgroundworker auch alles manuell machst - direkt in der UI.

Wobei der spsService nur dazu da ist die Verbindung zu eröffnen und die Nachrichten zu sammeln.

    public class SpsService : IDisposable, ISpsService
    {
        private ISpsConnection _spsConection;

        private Subject<SpsMessage> _message = new Subject<SpsMessage>();
        public IObservable<SpsMessage> Message => _message.AsObservable();

        public SpsService(ISpsConnection spsConection)
        {
            _spsConection = spsConection;

            _spsConection.NewMessage += HandleNewSpsMessage;
        }

        private void HandleNewSpsMessage(object sender, NewSpsMessageEventArgs args)
        {
            _message.OnNext(args.Message);
        }

        public void Dispose()
        {
            if (_spsConection != null)
            {
                _spsConection.NewMessage -= HandleNewSpsMessage;
                _spsConection = null;
            }
        }
    }

Durch diese Programmierweise wird sehr viel Overhead-Code vermieden, der zum Aktualisieren von Werten manuell notwendig ist; es ist eben Event-Driven.
Quasi Push vs. Pull.

Hab hier mal ein sehr vereinfachtes Samples hochgeladen.
https://github.com/BenjaminAbt/Sample-WinForms-RxNET-SPS