Announcement

Collapse
No announcement yet.

C# Ungültiger threadübergreifender Vorgang

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

  • C# Ungültiger threadübergreifender Vorgang

    Hallo,
    ich hoffe, hier kann mir jemand helfen. Ich weiß, es gibt viele Seiten wenn man danach sucht. Habe ich auch gemacht, aber leider verstehe ich es trotzdem nicht.
    Ich versuche über einen Timer eine Task zu starten, welcher dann Daten auf der GUI anzeigt.
    Leider habe ich bisher immer oben geschriebene Fehlermeldung erhalten.
    Nun habe ich zwar viel versucht, allerdings erreiche ich nicht mein Ziel: Einen Wert an die Textbox zu übergeben und anzeigen zu lassen.

    Hier mal mein Code
    Code:
    public delegate void StringParameterDelegate(string wert);
    
    private void Form1_Load(object sender, EventArgs e)
    {
    timer.Tick += new EventHandler(Timer_Starten);
    timer.Interval = 5000;
    timer.Enabled = true;
    }
    
    private void Timer_Starten(object sender, EventArgs e)
    {
    Task task = new Task(delegate { TaskAufgabe("8"); });
    task.Start();
    }
    
    private void TaskAufgabe(string wert)
    {
    if (InvokeRequired)
    {
    BeginInvoke(new StringParameterDelegate(TaskAufgabe), new object[] { textBox1.Text = wert});
    return;
    }
    }
    Was passt hier nicht bzw. weshalb erhalte ich immer noch diese Fehlermeldung?
    Danke füre Eure Hilfe!

  • #2
    Muster wäre eher

    Code:
    private void TaskAufgabe(string wert)
    {
        if (InvokeRequired)
            Invoke(new StringParameterDelegate(TaskAufgabe), wert);
        else
            textBox1.Text = wert;
    }
    Dort wo du nur den Parameter übergeben solltest hast du auch die Zuweisung zur textbox gemacht. Das passiert vor Invoke/BeginInvoke ist ja nur das zurechtbasteln der Parameter die wieder an TaskAufgabe übergeben werden. Das zuweisen zur Textbox passiert dann in dem Zuge auch noch.
    Man ruft sich da ja selbst wieder auf weil in dem "2.ten Call" man dann im MainThread ist heißt man muß es dann auch in diesem Aufruf tun. Heißt z.b. in einem else Zweig.

    Der ganze construct ist ein bisschen krude. Ein Windows Message basierter Timer der in seinem Event einen Task startet der "zufällig" ein anderer Thread ist und dann mit einem asynchronen Call in den Mainthread zu kommen. Wild.

    Je nachdem was du da genau tust oder tun willst
    - Nimm einfach direkt einen Threaded Timer und nutz von da aus direkt die TaskAufgabe Methode wie von mir gezeigt.
    z.b den hier https://learn.microsoft.com/de-de/do...r?view=net-8.0
    - Oder gleich auf asynchronen Code umstellen und das mit dem Task/Thread vergessen dann ist man erlöst von der Notwendigkeit des Invoke und hat auch eine Art von Nebenläufigkeit









    Comment


    • #3
      Danke, so läuft es.
      Du hast recht, das ganze ist etwas wild ...

      Ich möchte das ganze im geöffneten Programm immer wieder abprüfen bzw. dern Wert setzen(mit Daten aus der DB).
      Was spricht dagegen, wenn ich es beim Programmstart nur über den Timer starten/laufen lasse?
      Bekomme ich dann Probleme was die Performance betrifft? Bzw. was ist in diesem Fall dann die beste Lösung.

      Comment


      • #4
        Das Muster ob schön oder nicht sollte nicht der Performance relevante Teil sein.
        Performance vorhersagen ist auch eher schwer erst so programmieren das es funktioniert und von da aus schauen ob es ein Performanceproblem gibt oder nicht und nur dann optimieren.

        Das problematische was ich hier sehe wäre eher wenn es eine gewisse Wahrscheinlichkeit gibt das deine Hintergrundoperation länger als der Timerintervall dauert. So wie das jetzt aussieht hast du die dann im Zweifel mehrmals parallel laufen.
        Könnte man typischerweise so machen

        Code:
            public partial class Form1 : Form
            {
                private System.Threading.Timer timer;
                public Form1()
                {
                    InitializeComponent();
                    timer = new System.Threading.Timer(MyLovelyTimerCallback, null, 1000, Timeout.Infinite);
                }
        
                private void MyLovelyTimerCallback(Object stateInfo)
                {
                    try
                    {
                        // hier irgendeinen Hintergrundprozess einfügen
                        string dummy = $"Die Daten die ich vom Hintergrundprozess bekommen habe {DateTime.UtcNow.ToString()}";
                        // Daten auf die Form bringen
                        Invoke((MethodInvoker)delegate { textBox1.Text = dummy; });
                    }
                    finally
                    {
                        // nächsten Callback einplanen
                        timer.Change(5000, Timeout.Infinite);
                    }
                }
            }
        Alternative wäre grundsätzlich asynchroner Code. Macht aber nur Sinn wenn man das ganze auch mehr oder weniger komplett durchzieht. Also per async/await.


        Comment

        Working...
        X