仅在辅助线程结束后才更新GUI

时间:2018-09-10 11:46:53

标签: c# multithreading winforms

在一个解决方案中,我有一个Windows Form应用程序和托管DLL。 DLL包含一些耗时的函数,在这些函数中,我希望更新表单内容(使用动态更新从DLL回调到Form)。我有以下代码:

表单代码,我在其中初始化DLL,并在Initialize方法中为其提供回调函数。我还启动了一个单独的线程来定期检查message_queue中是否有来自DLL的新消息。 DLL函数也可以在单独的线程中调用(UI不阻塞)。

private LibraryDLL library_dll;
private ConcurrentQueue<string> message_queue;

public MainForm()
{
    InitializeComponent();
    library_dll = new LibraryDLL();
    message_queue = new ConcurrentQueue<string>();
    library_dll.Initialize(ProcessMessage);

    new Thread(() =>
    {
        Thread.CurrentThread.IsBackground = true;
        string message;
        if (message_queue.TryDequeue(out message))
        {
            PrintMessage(message);
        }
    }).Start();
}

private void ProcessMessage(string message)
{
    message_queue.Enqueue(message);
}

private void PrintMessage(string message)
{
    this.Invoke((MethodInvoker)delegate
    {
        listBox_rows.Items.Add(message);
    });            
}

private void button_send_Click(object sender, EventArgs e)
{
    new Thread(() =>
    {
        Thread.CurrentThread.IsBackground = true; 
        library_dll.DoWork();           
    }).Start();
}

在DLL代码中,我使用回调方法报告进度:

private CallBack callback;
public delegate void CallBack(string message);

public LibraryDLL() { }

public void Initialize(CallBack callback)
{
    this.callback = callback;
}

public void DoWork()
{
    callback("working...")
    Thread.Sleep(500);
    callback("working...")
    Thread.Sleep(500);
    callback("working...")
    Thread.Sleep(500);
}

我的问题是,而不是字符串“ working”每500毫秒出现一次,而是在1500毫秒之后出现3次(仅在运行DoWork方法的线程结束之后)。我还尝试了Form的PrintMessage函数中的Invalidate()-Update()-Refresh()序列,但没有任何效果。

谢谢您的建议!

EDIT1:

我修改了代码以使用BackgroundWorker,但是问题仍然存在(1500ms内无任何问题,一次只剩下3个字符串)。

BackgroundWorker bck_worker;

public MainForm()
{
    InitializeComponent();
    library_dll = new LibraryDLL();
    library_dll.Initialize(bck_worker);

    bck_worker = new BackgroundWorker();
    bck_worker.ProgressChanged += new ProgressChangedEventHandler(bckWorker_ProgressChanged);
    bck_worker.WorkerReportsProgress = true;
    bck_worker.WorkerSupportsCancellation = true;
} 

private void bckWorker_DoWork(object sender, DoWorkEventArgs e)
{
    library_dll.DoWork();
}

private void bckWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    PrintMessage((string)e.UserState);
}

private void button_send_Click(object sender, EventArgs e)
{
    bck_worker.DoWork += new DoWorkEventHandler(bckWorker_DoWork);
    bck_worker.RunWorkerAsync();
}

private void PrintMessage(string message)
{
    listBox_rows.Items.Add(message);
}

和DLL:

private BackgroundWorker bck_worker;

public LibraryDLL() { }

public void Initialize(BackgroundWorker bck_worker)
{
    this.bck_worker = bck_worker;
}

public void DoWork()
{
    bck_worker.ReportProgress(25, "working...");        
    Thread.Sleep(500);
    bck_worker.ReportProgress(50, "working...");
    Thread.Sleep(500);
    bck_worker.ReportProgress(75, "working...");
    Thread.Sleep(500);
}

EDIT2:

好的,我现在尝试在PrintMessage函数的末尾添加Invalidate-Update-Refresh序列,它最终可以工作(使用BackgroundWorker方法)!

1 个答案:

答案 0 :(得分:2)

使用后台工作人员和工作人员的报告进度来更新您的用户界面:background worker doc