从新线程调用/修改UI

时间:2011-11-23 23:41:57

标签: c#

我想逐步创建一个新的线程,以编程方式创建浏览器选项卡并在该浏览器选项卡中执行事件。问题是我收到一条消息,说我无法对父线程中的UI对象执行UI影响。

所以我需要找到一种方法来告诉新线程使用主线程的UI对象。这应该很容易做对吗?

以下是我正在使用的代码片段:

//....to this point we have told the code to run selected items in a datagrid. Each will have it's own thread.


            if (row.Cells[1].Value.ToString() == "True")
            {
                count_active++;
                //begin multithreading
                Thread this_thread = new Thread(() => f_play_campaign(row.Cells[0].Value.ToString(), row.Cells[2].Value.ToString()));
                this_thread.Name = "thread_" + row.Cells[0].Value.ToString();
                this_thread.IsBackGround = true;
                this_thread.Start();

            }

        }

        if (count_active == 0)
        {
            MessageBox.Show("No campaigns are selected!");
        }
    }


    private void f_play_campaign(string project_id, string tab_name)
    {
        //MessageBox.Show(tab_name);
        //add new tab
        string browsername = f_create_new_tab(tab_name); //this is where the code breaks!
        Control browser = f_get_control_by_name(browsername);

        //MessageBox.Show(browser.ToString());

        //... do more code

是否有一种简单的方法可以告诉线程使用主线程的UI对象?当我试图从我的方法f_create_new_tab()获取返回值时,我无法弄清楚如何使用Invoke(),而我在这方面是如此新,以至于我没有想出如何使用后台工作者和线程一样的方式。

我将继续阅读有关此问题的其他主题,但希望有人知道一个非常简单的优雅解决方案,可以满足像我这样的php程序员。

2 个答案:

答案 0 :(得分:2)

几天前我不得不处理这个问题。这很容易解决:

Thread this_thread = new Thread(() =>
    this.Invoke((MethodInvoker)delegate
    {
        f_play_campaign(row.Cells[0].Value.ToString(), row.Cells[2].Value.ToString();
    }));

基本上,您需要传递Invoke MethodInvoker委托,该委托定义为public delegate void MethodInvoker()

如果您想使用BackgroundWorker,那就非常相似:

 BackgroundWorker worker = new BackgroundWorker();
 worker.DoWork += (s, e) =>
 {
     this.Invoke((MethodInvoker) delegate { MyJobHere(); });
 };

 // Do the work
 worker.RunWorkerAsync();

如果你想返回一些值,你可以这样做:

BackgroundWorker worker = new BackgroundWorker();
int value;
worker.DoWork += (s, e) =>
{
    this.Invoke((MethodInvoker) delegate { value = DoSomething(); });
};

worker.RunWorkerAsync();


// do other processing
while (worker.IsBusy)
{
    // Some other task
}

// Use the value
foo(value);

答案 1 :(得分:1)

添加新方法:

    private void f_play_campaign_Async(string project_id, string tab_name)
    {
        Action<string, string> action = f_play_campaign; 
        this.Invoke(action, project_id, tab_name);
    }

修改therad的构造以改为调用此方法:

Thread this_thread = new Thread(() => f_play_campaign_Async(row.Cells[0].Value.ToString(), row.Cells[2].Value.ToString()));