Threading-Problem



  • Morgen zusammen,

    ich arbeite gerade an einem Programm in dem in einem eigenen Thread ein Form geöffnet werden soll und in diesem Form ein Progressbalken von 0 auf 100 zählen soll.

    Bei mir sieht das derzeit so aus:

    class Class1
    	{
    
    		private static Thread th1;
    		public static Form1 fm1;		
    
    		public Class1()
    		{
                th1 = new Thread(new ThreadStart(FormRun));
    			th1.Start();
                CreateCustomerAdapter();
    			th1.Abort();
    
    		}
    
    		public static void FormRun()
    		{
    			fm1 = new Form1();
    			Application.Run(fm1);
                fm1.Activate();
    		}
    
    		public static void CreateCustomerAdapter()
    		{
                //Form1 fm1 = new Form1();
                fm1.Activate();
    			fm1.label1.Visible=false;
    			fm1.Text="Datensätze werden übertragen";
    			fm1.label2.Text="Tabelle: TEST";
    			fm1.label2.Visible=true;
    			fm1.progressBar1.Visible=true;
    			fm1.progressBar1.Maximum=1000;
    
                fm1.Show();
    
                for (int i=0;i<1000;i++){
    			    fm1.progressBar1.Step=1;
                    System.Threading.Thread.Sleep(1);
    			    fm1.progressBar1.PerformStep();
                    System.Windows.Forms.Application.DoEvents();
    
                }
                fm1.Close();
    		}
    	}
    }
    

    Derzeit öffnen sich merkwürdigerweise immer 2 Fenster und zählen den Counter hoch....



  • Ich habe jetzt meine Anforderungen zurückgeschraubt und will nur mehr dass 2 Threads abwechselnd das Label eines Forms verändern:

    class Class1
    {
    private static Thread th1 = new Thread(new ThreadStart(FormRun));
    public static Form1 fm1=new Form1();

    public Class1()
    {
    th1.Start();
    CreateCustomerAdapter();
    th1.Abort();
    }

    static void FormRun()
    {
    fm1.label1.Text = " HUHUHUHUHUHU ";
    fm1.Activate();
    fm1.Show();
    Application.Run();
    for (int i = 1; i < 1000000; i++)
    {
    fm1.label1.Text = "TEST 1 ";
    fm1.Refresh();
    }
    }

    void CreateCustomerAdapter()
    {
    for (int k = 1; k < 1000000; k++)
    {
    fm1.label1.Text = " TEST2";
    }
    }
    }

    Die Fehlermeldung besagt aber, dass ich aus einem Thread auf ein Objekt zugreife das nicht in diesem Thread erzeugt wurde. Wie kann ich das umgehen ? 🙂



  • Servus,

    schau dir mal Invoke des Controls ein wenig genauer an. Da liegt der Hase begraben 🙂

    mfg
    Hellsgore

    EDIT: Vielleicht war mein Tipp etwas zu dürfitg *g*. Dein Label hier ist dein Problem.

    Beispiel Problemlösung:

    Erstelle dir ein Delegate. (Ist nur ein Beispiel)

    public delegate void LabelTextEventHandler(string text);
    

    Erstelle eine Instanz.

    private LabelTextEventHandler OnLabelTextAdded;
    

    Lege eine Methode an.

    private void AddLabelText(string text)
    {
       this.label.Text = text;
    }
    

    Erstelle ein neues Objekt.

    OnLabelTextAdded = new LabelTextEventHandler (AddLabelText);
    

    Invoke den mist.

    this.label.Invoke(this.OnLabelTextAdded);
    


  • Danke Hellsgore für den Tip !

    Ich habe jetzt etwas herumprobiert, komme aber auf keinen grünen Zweig 🙂

    Ich habe eine Klasse Class1.cs in der die Logik laufen sollte und ein Form1.cs in dem ich einen Startbutton und das erwähnte Label habe.

    In der Class1 lege ich mir ein neues Form1 an und starte es

    static void Main() 
    {
    	Form1 fm1 = new Form1();
             fm1.label1.Text="TEST";
             Application.Run(fm1);
             fm1.Activate();
    
             OnLabelTextAdded = new LabelTextEventHandler(AddLabelText); 
    }
    

    Daneben habe ich mir die von dir vorgeschlagenen Komponenten angelegt:

    private static Thread th1 = new Thread(new ThreadStart(FormRun));
    		private static Form1 fm1;
            public delegate void LabelTextEventHandler(string text);
            private LabelTextEventHandler OnLabelTextAdded;
    
            private void AddLabelText(string text)
            {
                fm1.label1.Text = text;
            }
            private void CreateCustomerAdapter()
            {
                fm1.label1.Invoke(this.OnLabelTextAdded);
            }
    

    Mir fehlt nur leider eine Idee wie ich das in weiterer Folge angehe 😞
    Vielleicht hast du noch einen kurzen Tip für mich 😉

    liebe Grüße
    Marion



  • Danke Hellsgore für den Tip !

    Ich habe jetzt etwas herumprobiert, komme aber auf keinen grünen Zweig 🙂

    Ich habe eine Klasse Class1.cs in der die Logik laufen sollte und ein Form1.cs in dem ich einen Startbutton und das erwähnte Label habe.

    In der Class1 lege ich mir ein neues Form1 an und starte es

    static void Main() 
    {
    	Form1 fm1 = new Form1();
             fm1.label1.Text="TEST";
             Application.Run(fm1);
             fm1.Activate();
    
             OnLabelTextAdded = new LabelTextEventHandler(AddLabelText); 
    }
    

    Daneben habe ich mir die von dir vorgeschlagenen Komponenten angelegt:

    private static Thread th1 = new Thread(new ThreadStart(FormRun));
    		private static Form1 fm1;
            public delegate void LabelTextEventHandler(string text);
            private LabelTextEventHandler OnLabelTextAdded;
    
            private void AddLabelText(string text)
            {
                fm1.label1.Text = text;
            }
            private void CreateCustomerAdapter()
            {
                fm1.label1.Invoke(this.OnLabelTextAdded);
            }
    

    Mir fehlt nur leider eine Idee wie ich das in weiterer Folge angehe 😞
    Vielleicht hast du noch einen kurzen Tip für mich 😉

    liebe Grüße
    Marion



  • Oje, tut mir leid, ich habe hier eine völlig falsche Version gepostet:

    Derzeit sieht es so aus:

    In meiner Form-Klasse gibt es diese Methode und das Delegate:

    private void UpdateText(string text)
            {
                label1.Text = text;
            }
    
    public delegate void UpdateTextCallback(string text);
    

    Die aufrufende Klasse sieht so aus, obwohl da noch irgendwo der Wurm drinnen ist :):)

    class Class1
    	{
    		private static Thread th1 = new Thread(new ThreadStart(FormRun));
    
            static void Main()
            {
                th1.Start();
                int i = 0;
                while (i < 100)
                {
                    i++;
                    System.Threading.Thread.Sleep(100);
                    label1.Invoke(new UpdateTextCallback(this.UpdateText), new object[] { "Text generated on non-UI thread." });
                }
            }
    
            static void FormRun()
            {
                Form1 fm1 = new Form1();
                fm1.label1.Text = "TEST";
                Application.Run(fm1);
                fm1.Activate();
            }
    }
    

    Vielleicht findest du den Fehler, wäre echt super 😃

    liebe Grüße Marion



  • Wenn du das Visual Studio hast, helfen dir vielleicht diese Snippets:
    http://www.fheinemann.de/archives/10-Threading-snippets.html

    Insbesondere das erste wäre dahingehend verwendbar. Bräuchtest nur noch das
    Progress-Reporting nach Vorlage des Complete-Reportings einbauen. Ist
    universell einsetzbar und achtet auch darauf, dass die GUI nur von dem
    GUI-Thread geupdatet werden kann.


Anmelden zum Antworten