Adam
Adam

Reputation: 101

Multithreading Errors in C#

I am trying to update a text box. I thought my threading code would fix the problem, but it does not. Can anyone help with this?

new Thread((ThreadStart)delegate { txtCapacitance.Text = Math.Round(capacitance, 3).ToString(); }).Start();

Gives the following error:

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

Note that all this is being started by a dataReceived function which is called whenever USB data is received.

Upvotes: 6

Views: 209

Answers (5)

Marcelo Cantos
Marcelo Cantos

Reputation: 186058

UI objects can only be called from the UI thread. This can be accomplished via the Control's Invoke method:

txtCapacitance.Invoke((Action)(() => { txtCapacitance.Text = Math.Round(capacitance, 3).ToString(); }));

Upvotes: 6

MadBoy
MadBoy

Reputation: 11104

You need to make sure that you update textBox from same thread as you have created it.

For this purpose create yourself class helper like this and use this extensions instead of using normal way (here are couple of extensions i made for myself, but the one interesting you is changeText):

public static class ControlExtensions {
    public static void changeStatus(this Control varControl, bool varState) {
        if (varControl.InvokeRequired) {
            varControl.BeginInvoke(new MethodInvoker(() => changeStatus(varControl, varState)));
        } else {
            varControl.Enabled = varState;
        }
    }
    public static void changeText(this Control varControl, string varText) {
        if (varControl.InvokeRequired) {
            varControl.BeginInvoke(new MethodInvoker(() => changeText(varControl, varText)));
        } else {
            varControl.Text = varText;
        }
    }
    public static DateTime readDateValue(this DateTimePicker varControl) {
        if (varControl.InvokeRequired) {
            return (DateTime) varControl.Invoke(new Func<DateTime>(() => readDateValue(varControl)));
        } else {
            return varControl.Value;
        }
    }
    public static bool ReadStatus(this CheckBox varControl) {
        if (varControl.InvokeRequired) {
            return (bool) varControl.Invoke(new Func<bool>(() => ReadStatus(varControl)));
        }
        return varControl.Checked;
    }
    public static bool ReadStatus(this RadioButton varControl) {
        if (varControl.InvokeRequired) {
            return (bool) varControl.Invoke(new Func<bool>(() => ReadStatus(varControl)));
        }
        return varControl.Checked;
    }
    public static string readText(this Control varControl) {
        if (varControl.InvokeRequired) {
            return (string) varControl.Invoke(new Func<string>(() => readText(varControl)));
        } else {
            return varControl.Text;
        }
    }
    public static bool readEnabled(this Control varControl) {
        if (varControl.InvokeRequired) {
            return (bool) varControl.Invoke(new Func<bool>(() => readEnabled(varControl)));
        } else {
            return varControl.Enabled;
        }
    }

}

Then you use it like this: txtCapacitance.changeText("new text");

Upvotes: 0

Adriaan Stander
Adriaan Stander

Reputation: 166506

You should rather have a look at using BackgroundWorker Class

Have a look at

C# BackgroundWorker Tutorial.

Upvotes: 4

mark vanzuela
mark vanzuela

Reputation: 1391

try this one

//delegate
delegate void updateTextboxDelegate(string value);

private void updateDisplay(string value)
{
   txtCapacitance.Text = value;
}

//the thread
string msg = string.empty;
var th =new Thread(()=>{BeginInvoke(new updateTextboxDelegate(updateDisplay), msg); });
th.Start();

Hope that will work for you.

Upvotes: 0

Enigmativity
Enigmativity

Reputation: 117154

Updates to any UI element must be done on the UI-thread. You can certainly calculate your value on another thread, but you must use the .Invoke(...) method of the control to perform the update.

Upvotes: 1

Related Questions