更新GUI多线程应用程序

时间:2014-08-22 11:55:02

标签: c# multithreading

我有主程序

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Worker w1 = new Worker(1);
        Worker w2 = new Worker(2);
        Thread w1Thread = new Thread(new ThreadStart(w1.StartWorking));
        Thread w2Thread = new Thread(new ThreadStart(w2.StartWorking));
        w1Thread.Start();
        w2Thread.Start();
        Application.Run(new MainWindow());
        if (w1Thread.IsAlive)
        {
            w1Thread.Abort();
        }
        if (w2Thread.IsAlive)
        {
            w2Thread.Abort();
        }
    }
}

和工人阶级:

class Worker
{
    public int m_workerId;
    public bool m_workerLifeBit;
    public bool m_workerWork;

    public Worker(int id)
    {
        m_workerId = id;
        m_workerLifeBit = false;
    }
    public void StartWorking()
    {
        while (!m_workerWork)
        {
            m_workerLifeBit = false;
            System.Threading.Thread.Sleep(5000);
            m_workerLifeBit = true;
            System.Threading.Thread.Sleep(5000);
        }
    }
}

checkBox表格MainWindow。 如何监控Worker变量m_workerLifeBit的状态并在MainWindow checkBox中显示其变化?

我发现这个q& a How to update the GUI from another thread in C#? hovewer答案没有显示完整的示例,我使用线程安全委托失败了。

我想要在Worker.StartWorking中触发一些事件机制并以MainWindow形式捕获插槽。

3 个答案:

答案 0 :(得分:2)

如评论中所述,如果这是 WinForms 应用程序,那么我建议使用BackgroundWorker

开始bg工作者并订阅活动:

BackgroundWorker worker = new BackgroundWorker();

// Subscribing to the worker method. Do all of your work here
worker.DoWork += worker_DoWork; 

// Subscribing to the progress changed event where you'll want to update the UI
worker.ReportProgress = true;
worker.ProgressChanged += worker_ProgressChanged; 

// Subscribing to the worker completed event. Fires when the work is complete
worker.RunWorkerCompleted += worker_RunWorkerCompleted;

// This line starts the worker
worker.RunWorkerAsync();

然后您可以将您的方法定义为:

void worker_DoWork(object sender, DoWorkEventArgs e)
{
    // Perform some work with the object you've passed in e.g.
    MyObj foo = (MyObj)e.Argument;

    foo.Name = "foobar";

    // Notify UI
    worker.ReportProgress(100, foo);
}

void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    // Update UI
}

void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // Worker has finished
}

答案 1 :(得分:1)

以下是使用events的简单版本:

class Worker
{
    public event Action<bool> WorkerLifeBitChanged;

    // ...

    public void StartWorking()
    {
        // ...

        m_workerLifeBit = false;
        OnWorkerLifeBitChanged();

    // ...

    private void OnWorkerLifeBitChanged()
    {
        if (WorkerLifeBitChanged != null)
            WorkerLifeBitChanged(m_workerLifeBit);
    }

然后在Main

中连接事件
//...
var mainWindow = new MainWindow();

w1.WorkerLifeBitChanged += mainWindow.UpdateWorkerLifeBit;
w2.WorkerLifeBitChanged += mainWindow.UpdateWorkerLifeBit;

w1Thread.Start();
w2Thread.Start();

Application.Run(mainWindow);
//...

UpdateWorkerLifeBit中的MainWindow实施:

public void UpdateWorkerLifeBit(bool workerLifeBit)
{
    if (this.checkBox.InvokeRequired)
    {
        this.Invoke(new Action(() => checkBox.Checked = workerLifeBit));
    }
    else
    {
        checkBox.Checked = workerLifeBit;
    }
}

答案 2 :(得分:0)

一种解决方案是将Program类的引用(或者甚至是程序类中的委托,或者worker类中的数据引用)传递给Worker线程。您可以直接从线程代码调用程序的函数。您也可以使用信号,但对于这个小例子,我之前的“解决方案”是可以接受的。