2

我有这个代码:

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

并且txtErrors在“主”线程(UI)中。当我发现错误时,异步线程无法写入 UI 控件,我得到一个invalid cross-thread exception.

我可以在线程内与 UI 对话吗?

4

5 回答 5

4

如果您使用的是 WinForms,则需要在 UI 线程上调用您的方法,例如

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

如果您使用的是 WPF,则需要

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 });
    }
}
于 2013-04-18T07:10:42.877 回答
3

如果您的目标是 WinForm 应用程序,那么:

try
    {
        ... some operation ....
    }
catch (Exception err)
    {
       if (txtErrors.InvokeRequired)
        {
            txtErrors.BeginInvoke(new MethodInvoker(
                delegate { txtErrors.AppendText(err.Message); })
                );
        }
    }
于 2013-04-18T07:10:21.010 回答
2

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;
    }
}
于 2013-04-18T07:12:52.250 回答
1

在调用的 form_load 事件处理程序中将 CheckForIllegalCrossThreadCalls 设置为 false

于 2013-04-18T07:14:23.950 回答
1

把它从一个旧项目中拉出来,我不得不处理从另一个线程更新 UI。也应该为你工作。

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();
    }
}
于 2013-04-18T07:22:33.897 回答