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
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)
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
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
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)));
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.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
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
Bitte keine Full Quotes
[Hinweis] Wie poste ich richtig?
Hallo,
Danke! Paramterübergabe klappt so!
mfg
Bitte keine Full Quotes
[Hinweis] Wie poste ich richtig?
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
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code