View Single Post
  #1 (permalink)  
Old December 13th, 2006, 09:17 AM
Richw71 Richw71 is offline
Registered User
 
Join Date: Dec 2006
Location: Paris, , France.
Posts: 1
Thanks: 0
Thanked 0 Times in 0 Posts
Send a message via MSN to Richw71
Default Cross-thread operation not valid

Hi,

I have a form that, on clicking a button, kicks off a thread. That thread raises occasional events that I want the original form to trap and show information about.

Everything seems perfectly logical to me, but at run-time I get an error: Cross-thread operation not valid.

The solutions that I have seen work for the case where the code to update the form is contained within the thread itself. In my case, though, I want the thread class to be reusable without modification and so do not want to code references to a particular form inside the thread.

Here is the code, in the form, that uses the thread:


Code:
// This is my UI class: the standard VS2005 created "Form1"
// The form contains a button: button1, and a label: label1

/*  Info:
 *  When the button1 is clicked a thread is created that 
 *  performs a long calculation.   From time-to-time during 
 *  the calculation an event - ChangedResult - is raised and 
 *  this event passes back the current result to the calling 
 *  form for display in label1
*/ 

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

namespace TestCrossThreadApp1
{
    public partial class Form1 : Form
    {

        // Default constructor... no surprises
        public Form1()
        {
            InitializeComponent();
        }//Form1

        // The button click event that creates an instance of a "calc" thread
        // an event handling method, onChangedResult, is setup to received
        // the ChangedResult event from the Calc1 thread.
        private void button1_Click(object sender, EventArgs e)
        {
            MyCalcThread Calc1 = new MyCalcThread();
            Calc1.ChangedResult += onChangedResult;
            Calc1.StartCalculation();
        }// button1_click

        // The onChangedResult method is called by delegation
        private void onChangedResult(object sender, CalcEventArgs CEA)
        {
            string s = Convert.ToString(CEA.Result);
            label1.Text = s;  //<-------- This is where the ERROR occurs!
        }// onChangedResult

    }// class Form1

}// Namespace

The following is the code for the thread object and it's eventargs object:

Code:
using System;
using System.Threading;

namespace TestCrossThreadApp1
{
    // Define the delegate for the ChangedResult event
    public delegate void ChangedResultHandler(object sender, CalcEventArgs CEA);

    // Event Arguments
    public class CalcEventArgs : EventArgs
    {
        private int result;

        // Constructor
        public CalcEventArgs(int Result)
        {
            this.result = Result;
        } // Constructor

        // Get Parameter
        public int Result
        {
            get
            {
                return result;
            } // Get
        } // Get Parameter
    }//class CalcEventArgs


    // Declare a class that encapsulates the threaded calculations
    public class MyCalcThread
    {
        // Define an event that will be fired when the calculation result is changed significantly
        public event ChangedResultHandler ChangedResult;

        // This method creates an instance of the event args and raises the ChangedResult event
        public void RaiseResultChangedEvent(int Result)
        {
            CalcEventArgs CEA = new CalcEventArgs(Result);
            ChangedResult(this, CEA);
        }// RaiseResultChangedEvent


        // Public class that starts the calculation in it's own thread
        public void StartCalculation()
        {
            Thread CalculationThread = new Thread(new ThreadStart(CalcThread));
            CalculationThread.Start();
        }// StartCalculation

        // This is a mundane "calculation"
        public void CalcThread()
        {
            int i = 0;

            while (++i < 10000000)
            {
                // Raise the ChangedEvent method via the RaiseResultChangedEvent wrapper
                switch (i)
                {
                    case 1:
                    case 100000:
                    case 500000:
                    case 1000000:
                        RaiseResultChangedEvent(i);
                        break;
                } // switch
            }// While
        }// CalcThread

    }// Class MyCalcThread

}// Namespace

This is very frustrating, so any help that you could offer would be appreciated!

- Rich

Reply With Quote