C#Threading,1st Task DoSomething,2nd Task更新WinFormLabel(实时)?

时间:2012-10-28 20:09:42

标签: c# winforms multithreading parallel-processing

让我说我有任务1:

private void Task1()
{
    //Here is some Code, could be any "longer" Task - 
    //For Example: Grab all words from a .txt File and fill in a List<String>
}

然后我还有另一个任务2:

private void Task2(string word)
{
   //So lets say theres a Label on my WinForm..
   //Now While Task1 is grabbing the words, Task2 should fill a Label 
   //with the added 'word' (parameter) - (Task2 will be called from Task1
}

实际上我不知道如何使这成为可能,或者最好的方式。在UI上,我应该能够看到Label.Text更改(每个单词)..所以我需要制作第二个线程?我怎么能这样做?也许有人可以帮助我,欢呼

更新

我现在尝试使用Backgroundworker,但似乎有些错误......它实际上不起作用,表单上没有任何反应

代码:

public void CreateAndSaveAMatch(DateTime date) //That method is being called several times
{   
    //HERE IS CODE, WHICH CREATES AND SAVES A MATCH

    // Start the asynchronous operation.
    backgroundWorker1.RunWorkerAsync(date);

}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{      
    backgroundWorker1.ReportProgress(0, Convert.ToDateTime(e.Argument).ToShortDateString());          
}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    label1.Text = (string)e.UserState; //here on the Label I would like to show the Date
}

4 个答案:

答案 0 :(得分:2)

使用BackgroundWorker报告第一项任务的进度。将此组件从工具箱拖到您的表单,并订阅DoWorkProgressChanged个事件。同时将属性WorkerReportsProgress设置为true。然后异步启动第一个任务:

// this will execute code in `DoWork` event handler
backgroundWorker1.RunWorkerAsync();

下一步 - 使用userState对象传递处理过的单词:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{      
    // grab words in a loop and report progress
    backgroundWorker1.ReportProgress(0, word);
}

最后一步 - 更新ProgressChanged事件处理程序

中的标签
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    label1.Text += (string)e.UserState; // this is your grabbed word
}

答案 1 :(得分:2)

好的,试试吧。这是一个简单的示例,它将向您展示如何使用BackgroundWorker解决您的问题。另请注意,还有许多其他解决方案。要使用此示例,请在仅包含按钮和标签的新项目中创建表单。另请注意,这是对其他答案的补充,这是正确的。

public partial class Form1 : Form
    {
        BackgroundWorker createAndSaveAMatchBGW;
        public Form1()
        {
            InitializeComponent();
            createAndSaveAMatchBGW = new BackgroundWorker();
            createAndSaveAMatchBGW.DoWork += new DoWorkEventHandler(createAndSaveAMatchBGW_DoWork);
            createAndSaveAMatchBGW.ProgressChanged += new ProgressChangedEventHandler(createAndSaveAMatchBGW_ProgressChanged);
            createAndSaveAMatchBGW.RunWorkerCompleted += new RunWorkerCompletedEventHandler(createAndSaveAMatchBGW_RunWorkerCompleted);
            createAndSaveAMatchBGW.WorkerReportsProgress = true;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            createAndSaveAMatchBGW.RunWorkerAsync(DateTime.Now);
        }

        void createAndSaveAMatchBGW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            MessageBox.Show("BackgroundWorker finished");
        }

        void createAndSaveAMatchBGW_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            label1.Text = ((DateTime)e.UserState).ToString("ss");
        }

        void createAndSaveAMatchBGW_DoWork(object sender, DoWorkEventArgs e)
        {
            //BackgroundWorker does something for a 10 seconds, each second it Reports
            BackgroundWorker bgw = (BackgroundWorker)sender;
            DateTime dt = (DateTime) e.Argument;
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(1000);
                dt = dt.AddSeconds(1);
                bgw.ReportProgress(0, dt);
            }
        }
    }

如果您在执行时仅从CreateAndSave ...方法报告一次,那么您可以使用此代码:

BackgroundWorker createAndSaveAMatchBGW;
        public Form1()
        {
            InitializeComponent();
            createAndSaveAMatchBGW = new BackgroundWorker();
            createAndSaveAMatchBGW.DoWork += new DoWorkEventHandler(createAndSaveAMatchBGW_DoWork);
            createAndSaveAMatchBGW.RunWorkerCompleted += new RunWorkerCompletedEventHandler(createAndSaveAMatchBGW_RunWorkerCompleted);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            createAndSaveAMatchBGW.RunWorkerAsync(DateTime.Now);
        }

        void createAndSaveAMatchBGW_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            label1.Text = ((DateTime)e.Result).ToString();
        }

        void createAndSaveAMatchBGW_DoWork(object sender, DoWorkEventArgs e)
        {
            DateTime dt = (DateTime) e.Argument;
            //you do something with your DateTime
            dt = dt.AddDays(10);
            e.Result = dt;
        }

答案 2 :(得分:1)

实现此类事情的最简单方法是使用BackgroundWorker。

http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

BackgroundWorker自动处理线程编组并提供允许您更新UI的事件。事件处理程序在UI线程上运行。

您在Task1中执行的操作可以移动到BackgroundWorker中,您建议在Task2中执行的UI更新实际上可以响应来自BackgroundWorker的进度事件。

ProgressChangedEventArgs提供可以保存当前单词的用户定义数据。

然而,如果你打算显示你加载的每个单词,Winforms(实际上几乎任何UI)都无法跟上一个单独的CPU线程只是加载文件中的单词。

答案 3 :(得分:0)

Task1可以在一个单独的线程上启动。

除非执行一些复杂的逻辑来更新TextBox,否则实际上不需要Task2。您真正需要做的是使用TextBox.Invoke()Task1调用UI线程上的更新。