markzzz
markzzz

Reputation: 48015

Thread that talk with UI?

I have this code:

private void buttonStart_Click(object sender, EventArgs e)
{
    Task.Factory.StartNew(() => GeneraListaCartelle())
        .ContinueWith(t => GeneraListaCartelleCompletata()
        , CancellationToken.None
        , TaskContinuationOptions.None
        , TaskScheduler.FromCurrentSynchronizationContext());
}

private void GeneraListaCartelle()
{
    try
    {
        ... some operation ....
    }
    catch (Exception err)
    {
        txtErrors.AppendText(err.Message);
    }
}

GeneraListaCartelleCompletata()
{
    ... process finished...
}

and txtErrors is in the "main" thread (the UI). When I catch an error, the asynch thread cannot write to the UI control, and I get an invalid cross-thread exception.

Can I dialogate with the UI inside a Thread?

Upvotes: 2

Views: 118

Answers (5)

bash.d
bash.d

Reputation: 13217

If you are using WinForms, you will need to Invoke your method on the UI-thread like

catch (Exception err)
{
    if(this.InvokeRequired){
        Action<Exception> act = ((ex) => {
            txtErrors.AppendText(ex.Message);
        }); 
        this.Invoke(act, new object[] { err });
    }
    else{
        txtErrors.AppendText(err.Message);
    }
}

If you are using WPF you will need to

catch (Exception err)
{
    if(this.Dispatcher.CheckAccess()){
       txtErrors.AppendText(err.Message);
    }
    else {
           Action<Exception> act = ((ex) => {
            txtErrors.AppendText(ex.Message);
           }); 
        this.Dispatcher.Invoke(act, new object[] { err });
    }
}

Upvotes: 4

Hjalmar Z
Hjalmar Z

Reputation: 1601

Pulled this out of an old project where I had to deal with updating the UI from another thread. Should work for you as well.

delegate void addtoValProg();
addtoValProg myDelegate;

myDelegate = new addtoValProg(invokeControl);

private void GeneraListaCartelle()
{
    try
    {
        //... some operation ....
    }
    catch (Exception err)
    {
        invokeControl();
    }
}

private void invokeControl()
{
    if (this.InvokeRequired)
    {
        this.Invoke(this.myDelegate);
    }
    else
    {
        txtErrors.AppendText(err.Message);
        txtErrors.Update();
    }
}

Upvotes: 1

mehdi.loa
mehdi.loa

Reputation: 575

set CheckForIllegalCrossThreadCalls to false in the called form_load event handler

Upvotes: 1

Denys Denysenko
Denys Denysenko

Reputation: 7904

There's an example from msdn:

// This delegate enables asynchronous calls for setting
// the text property on a TextBox control.
delegate void SetTextCallback(string text);

// This method demonstrates a pattern for making thread-safe
// calls on a Windows Forms control. 
//
// If the calling thread is different from the thread that
// created the TextBox control, this method creates a
// SetTextCallback and calls itself asynchronously using the
// Invoke method.
//
// If the calling thread is the same as the thread that created
// the TextBox control, the Text property is set directly.
private void SetText(string text)
{
    // InvokeRequired required compares the thread ID of the
    // calling thread to the thread ID of the creating thread.
    // If these threads are different, it returns true.
    if (this.textBox1.InvokeRequired)
    {
        SetTextCallback d = new SetTextCallback(SetText);
        this.Invoke(d, new object[] { text });
    }
    else
    {
        this.textBox1.Text = text;
    }
}

Upvotes: 2

Habib
Habib

Reputation: 223392

if You are targetting WinForm Application then:

try
    {
        ... some operation ....
    }
catch (Exception err)
    {
       if (txtErrors.InvokeRequired)
        {
            txtErrors.BeginInvoke(new MethodInvoker(
                delegate { txtErrors.AppendText(err.Message); })
                );
        }
    }

Upvotes: 3

Related Questions