跨线程访问函数

时间:2013-12-30 03:31:07

标签: c# .net multithreading textbox backgroundworker

我正在开发一个程序,该程序使用backgroundWorker将文本附加到Textbox控件。我的问题是,backgroundWorker不会在Textbox控件中插入文字,它只是空白。

我的代码:

private void button1_Click(object sender, EventArgs e) {
    backgroundWorker1.RunWorkerAsync(); //Start the worker
}

public void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
    this.writeText("Hello World!");
}

public void writeText(string text) {
    textbox1.Text = textbox1.Text + text + "\r\n";
    textbox1.SelectionStart = textbox1.Text.Length;
    textbox1.ScrollToCaret();        //Scroll to the end of the textbox
}


看看代码,看起来很好(对我来说)并且编译也很好,所以我可能会非常明显地丢失它。

如果有人愿意让我知道我做错了什么,我将不胜感激;)

4 个答案:

答案 0 :(得分:2)

在订阅DoWork事件的方法中,执行长时间运行的操作。然后,在worker方法中,您可以调用ReportProgress来发送更新。这会导致您的UI线程触发OnProgressChanged事件,此时您可以对UI进行更改。

或者,如果您使用的是.NET 4.5,则可以使用async / await模式在执行长时间运行的I / O绑定操作时保持UI响应。对于CPU绑定操作,BackgroundWorker仍然合适。

与往常一样,MSDN是一个很棒的资源。来自BackgroundWorker page

  

要设置后台操作,请为其添加事件处理程序   DoWork活动。在此活动中呼叫您耗时的操作   处理程序。要启动该操作,请调用RunWorkerAsync。受到   进度更新通知,处理ProgressChanged事件。   要在操作完成时收到通知,请处理   RunWorkerCompleted事件。

     

您必须小心不要操纵任何用户界面对象   你的DoWork事件处理程序。而是与用户界面进行通信   通过ProgressChanged和RunWorkerCompleted事件。

答案 1 :(得分:1)

您可以在表单级别为您的表单声明委托。

public delegate void WriteLogEntryDelegate(string log_entry);

然后你可以用另一种方法包装大部分逻辑:

void WriteLogEntryCB(string log_entry)
    {
        if (textbox1.InvokeRequired == true)
                {
                    var d = new WriteLogEntryDelegate(WriteLogEntryCB);
                    this.Invoke(d, log_entry);
                }
                else
                {
                    textbox1.Text(log_entry + "\r\n");
                    this.textbox1.SelectionStart = this.textbox1.Text.Length;
                    this.textbox1.ScrollToCaret();
                }
    }

然后,您可以从DoWork方法中调用该函数:

public void DoWork(object sender, DoWorkEventArgs e) 
{
    WriteLogEntryCB("Hello World!");
}

编辑以包括Daniel Mann的建议: 另一种方法是将DoWork方法中的发送方作为BackgroundWorker进行转换,然后调用ReportProgress方法(或使用RunWorkerCompleted事件处理程序)。

void bw1_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;
        worker.ReportProgress((1));
    }

然后,您需要一个ProgressChanged事件的事件处理程序:

void bw1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        //update textbox here
    }

最后,您还可以使用RunWorkerCompleted事件处理程序:

void bw1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
       //update textbox here
    }

答案 2 :(得分:0)

在writeText方法中,UI应该调用与UI相关的代码

创建UI控件的线程。

答案 3 :(得分:0)

您所做的就是尝试从其他线程而不是创建元素的线程访问UI元素。

阅读更多信息here