views:

116

answers:

5

Hi. 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.

+4  A: 

You should rather have a look at using BackgroundWorker Class

Have a look at

C# BackgroundWorker Tutorial.

astander
This won't fix the problem. Background workers still run on a different thread to the UI thread.
Marcelo Cantos
@Marcelo Cantos, Have you read the documentation? *You must be careful not to manipulate any user-interface objects in your DoWork event handler. Instead, communicate to the user interface through the ProgressChanged and RunWorkerCompleted events.*
astander
@astander: you're right; I'm wrong; my apologies. I confused this with a normal thread pool.
Marcelo Cantos
+6  A: 

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(); }));
Marcelo Cantos
I get this error:Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type
Adam
Sorry, you have to do a cast. I've fixed it.
Marcelo Cantos
+1  A: 

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.

Enigmativity
A: 

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.

mcxiand
A: 

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");

MadBoy