Laden...

Control wird von einem anderen Thread aufgerufen?

Erstellt von reteep vor 18 Jahren Letzter Beitrag vor 18 Jahren 2.793 Views
R
reteep Themenstarter:in
70 Beiträge seit 2005
vor 18 Jahren
Control wird von einem anderen Thread aufgerufen?

Kompletter Error:
Message: Cross-thread operation not valid: Control '' accessed from a thread other than the thread it was created on.

Der Fehler tritt genau hier auf:


richTextBox1.Text += "ChangeT
ype :: " + e.ChangeType.ToString() + "\nFullPath ::" + e.FullPath.ToString() + "\n\n";

Wenn ich die Zeile einfach in eine string Variable packe gehts, ich möchte es aber direkt in die Textbox parsen. Weis jemand Rat? Danke!

Ich hab das definiert:


        private System.Windows.Forms.RichTextBox richTextBox1;

Und diesen Code:


using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace FolderWatcher_
{
    public partial class Form1 : Form
    {
        private FileSystemWatcher myWatcher;
        private Button btnAddFile, btnAddDir, btnDelDir, btnDelFile, btnExit;
        string DirPath;

        public Form1(string myPath)
        {
            DirPath = myPath;
            InitializeComponent();
        }

        private void richTextBox1_TextChanged(object sender, EventArgs e)
        {

        }

        private void Form1_Load(object sender, EventArgs e)
        {
            myWatcher = new FileSystemWatcher(DirPath);
            myWatcher.EnableRaisingEvents = true;
            myWatcher.IncludeSubdirectories = true;
            myWatcher.Created += new FileSystemEventHandler(myWatcher_Created);
            myWatcher.Changed += new FileSystemEventHandler(myWatcher_Changed);
            myWatcher.Deleted += new FileSystemEventHandler(myWatcher_Deleted);
            myWatcher.Renamed += new RenamedEventHandler(myWatcher_Renamed);
        }

        public static void Main()
        {
            myProperties myprop = new myProperties();
            myprop.ShowDialog();
            Application.Run(new Form1(myprop.myPath));
        }
        
        //Creating New File
        protected void btnAddFile_Click(object sender, EventArgs e)
        {

        }

        // Created Event
        protected void myWatcher_Created(object sender, FileSystemEventArgs e)
        {
            richTextBox1.Text += "ChangeType :: " + e.ChangeType.ToString() + "\nFullPath ::" + e.FullPath.ToString() + "\n\n";
        }

        //Changed Event
        protected void myWatcher_Changed(object sender, FileSystemEventArgs e)
        {
            richTextBox1.Text += "ChangeType :: " + e.ChangeType.ToString() + "\nFullPath ::" + e.FullPath.ToString() + "\n\n";
        }

        //Deleted Event
        protected void myWatcher_Deleted(object sender, FileSystemEventArgs e)
        {
            richTextBox1.Text += "ChangeType :: " + e.ChangeType.ToString() + "\nFullPath ::" + e.FullPath.ToString() + "\n\n";
        }

        //Renamed Event
        protected void myWatcher_Renamed(object sender, RenamedEventArgs e)
        {
            richTextBox1.Text += "ChangeType :: " + e.ChangeType.ToString() + "\nFullPath ::" + e.FullPath.ToString() + "\nOld FileName :: " + e.OldName.ToString() + "\n\n";
        }
    }
}

D
124 Beiträge seit 2005
vor 18 Jahren

Hi,

von einem anderen Thread kann man nicht auf die User Controls zugreifen, dafür musst du
Control.Invoke oder Control.BeginInvoke aufrufen.

Statt der Zuweisung:

richTextBox1.Text += "...";

solltest du nen Delegate erstellen und prüfen ob ein Invoke erforderlich ist.
z.B. so:


private delegate void AppendTextHandler(string s);

private void AppendText(string s)
{
 if( richTextBox1.InvokeRequired )
  richTextBox1.Invoke(new AppendTextHandler(AppendText), new object[]{s});
 else
  richTextBox1.Text += s;
}
R
reteep Themenstarter:in
70 Beiträge seit 2005
vor 18 Jahren

Ok danke so hats geklappt:


        protected void myWatcher_Created(object sender, FileSystemEventArgs e)
        {
            //FileStream file = new FileStream("change.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite);
            //StreamWriter sw = new StreamWriter(file);
            //sw.Write("ChangeType :: " + e.ChangeType.ToString() + "\nFullPath ::" + e.FullPath.ToString() + "\n\n");
            //sw.Close();

         string s = "ChangeType :: " + e.ChangeType.ToString() + "\nFullPath ::" + e.FullPath.ToString() + "\n\n";
            AppendText(s);
        }                       

            private delegate void AppendTextHandler(string s);

            private void AppendText(string s)
            {
            if( richTextBox1.InvokeRequired )
            richTextBox1.Invoke(new AppendTextHandler(AppendText), new object[]{s});
            else
            richTextBox1.Text += s;
            }

A
196 Beiträge seit 2005
vor 18 Jahren

Seit dem Umstieg auf .NET 2 kommt bei mir auch immer dieser Fehler

Cross-thread operation not valid:

Ich will aber nicht meinen ganzen Quellcode umschreiben. Gibt es keine schnellere Möglichkeit außer invoke() und delegate ?

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo alf468,

das die Exception bei 1.1 nicht kommt, ist ein Bug von 1.1. Stattdessen können bei 1.1 lustige Effekte auftreten. Es kann sein, dass diese Effekte nur unter bestimmten Bedingungen auftreten (Racing Conditions). Dein Code ist also fehlerhaft (auch wenn du keine Exception bekommst und auch wenn die Effekte nicht auftreten). Die einige Lösung ist den Code umzuschreiben. Zum Trost: Invoke ist simpel.

herbivore

N
20 Beiträge seit 2005
vor 18 Jahren

Hallo,

Nach der Umstellung auf .Net 2.0 kam bei mir genau die gleiche Fehlermeldung. Also habe ich auch die Delegates und Invokes eingebaut. Mein Problem ist jetzt, dass die Invokes erst ausgeführt werden,w enn der Thread beendet ist. Das hat zur Folge, dass alle Nachrichten die ich in einem Fenster ausgeben wollte, erst ganz am Ende angezeigt bekomme. Damit fehlen dem Nutzer genau die Rückmeldungen, um die es mir dabei ging. Hat jemand ne Idee, was ich daran ändern muss.

Natsukawa

F
234 Beiträge seit 2006
vor 18 Jahren

Kannst Du mal ein Code-Beispiel posten ?
Oder hast Du das vielleicht blockierend programmiert ?
D.h.: wartet Dein "Haupt"-Thread bis der andere Thread, aus dem die Nachrichten kommen, tot ist? Dann wärs klar, warum.

N
20 Beiträge seit 2005
vor 18 Jahren

Hallo,

Ja der Hauptthread muss auf die anderen Threads warten. Das liegt daran, dass zwischendurch einige Aufgaben parallel in den Threads laufen, und danach der Hauptthread etwas auswerten muss.

Beispiel posten ist etwas schwierig, es verteilt sich auf viele Klassen und so.

Wieos muss den der Hauptthread beendet sein, damit die Nachrichten zur Control durchgereicht werden?

Natsukawa

564 Beiträge seit 2006
vor 18 Jahren

hi!

dein Problem ist folgendes: Wenn ei Thread auf einen anderen wartet, dann ist der wartende Thread blockiert. Als Lösung würde sich anbieten, erst einen "zwischenthread" zu starten, welcher deinen eigentlichen Arbeitsthread aufruft und auf ihn wartet. Per Events müssen die Daten aus deinem eigentlichen Arbeitsthread in den GUI-Thread gelangen. Insgesamt wären das bei der Lösung also 3 Threads. (GUI + Zwischenthread + Arbeitsthread)

der Marcel

:] 😄Der größte Fehler eines modernen Computers sitzt meist davor 😁 :]

F
234 Beiträge seit 2006
vor 18 Jahren

Nee, der muss nicht beendet sein. Geht ja auch nicht. Er darf nicht blockiert werden. Also ich mein jetzt der Thread in dem die GUI läuft, der darf nicht blockiert werden, sonst passiert da garnichts. Der hängt dann an der Stelle, wo er drauf wartet, daß die anderen Thread zurückkommen. Und erst wenn DIE ihre Arbeit beendet haben, dann läuft er weiter.
Um das zu verhindern, musst Du das mit Threads also so programmieren, daß sie den GUI-Thread nciht blockieren. Das reicht ja, wenn die sowas wie ein "ich bin fertig"-Event schicken. Oder per BeginInvoke und Callback ihr Ergebnis abliefern. Und wenn alle Threads das gemacht haben, wird ausgewertet.

Haha, zwei Dumme, ein Gedanke. Warst schneller, Marcel 😁

N
20 Beiträge seit 2005
vor 18 Jahren

Hallo,

Danke, dass mit dem Bin-Fertig-Event werd ich gleich mal probieren.

Natsukawa

A
196 Beiträge seit 2005
vor 18 Jahren

Hallo ich habe eine kleines Problem.Ich will ein Item in einer Listbox einfügen.
Dabei kommt folgender Fehler:
System.InvalidOperationException: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.

Die Listbox ist static hat das Problem damit was zu tun ?
Das ist das erste Mal das ich damit Probleme habe 🙁

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo alf468,

es ist so wie die Meldung sagt.

Der Handle eines Controls wird erst bei Show oder explizit durch CreateHandle/Handle erzeugt.

herbivore