gpt4 book ai didi

c# - 多线程更新主窗体

转载 作者:太空宇宙 更新时间:2023-11-03 14:19:24 25 4
gpt4 key购买 nike

我有一个应用程序 (frmMain),它调用一个启动 2 个线程(Thread1、Thread2)的类 (ThreadBL)。当线程 1 执行操作时,我希望能够将更新发送回 frmMain,类似地,线程 2 也会执行相同的操作。

这里是一些切碎的代码,基本上就是它的工作原理。我还没有机会测试这个特定代码是否有效,但是当我运行我拥有的原始代码时,我得到一个“跨线程操作对线程无效”的错误。

是否有更好的方法从线程更新 frmMain?这段代码是否过于详尽且没有必要?非常感谢任何反馈。

public class ThreadExample() {
private void ThreadExample() {};

public delegate void CurrentFileProcessing(string filename);
public event CurrentFileProcessing CurrentFileProcessingEvent;

public bool startCopying() {
CurrentFileProcessingEvent += new CurrentFileProcessing(handlerCurrentFileProcessing);
copyFiles();
return true;
}
public void copyFiles() {
CurrentFileProcessingEvent("Copying: file.xml");
}
private void handlerCurrentFileProcessing(string filename) {
Console.WriteLine("Processing: " + filename);
}
}

public class ThreadBL() {
private void ThreadBL() {};

public delegate void Thread1CurrentProcessing(string filename);
public delegate void Thread2CurrentProcessing(string filename);

public event Thread1CurrentProcessing Thread1CurrentProcessingEvent;
public event Thread2CurrentProcessing Thread2CurrentProcessingEvent;

private bool processingThread1 = false;
private bool processingThread2 = false;

public void processThreads() {
BackgroundWorker thread1BW = new BackgroundWorker();
thread1BW.DoWork += new DoWorkEventHandler(thread1Process);
thread1BW.RunWorkerCompleted += new RunWorkerCompletedEventHandler(completeThread1);
thread1BW.RunWorkerAsync();
while (!processingThread1) {
Console.WriteLine("Waiting for thread1 to finish. TID: " + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(100);
}

BackgroundWorker thread2BW = new BackgroundWorker();
thread2BW.DoWork += new DoWorkEventHandler(thread2Process);
thread2BW.RunWorkerCompleted += new RunWorkerCompletedEventHandler(completeThread2);
thread2BW.RunWorkerAsync();
while (!thread2Done) {
Console.WriteLine("Waiting for thread2 to finish. TID: " + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(100);
}
}

private void thread1Process() {
ThreadExample thread1Example = new ThreadExample();
thread1Example.CurrentFileProcessingEvent += new ThreadExample.CurrentFileProcessing(handlerThread1CurrentProcessingEvent);
processingThread1 = thread1Example.startCopying();
}
private void completeThread1(object sender, RunWorkerCompletedEventArgs e) {
Console.WriteLine("Completed Thread1. TID: " + Thread.CurrentThread.ManagedThreadId);
processingThread1 = true;
}

private void thread2Process() {
ThreadExample thread2Example = new ThreadExample();
thread2Example.CurrentFileProcessingEvent += new ThreadExample.CurrentFileProcessing(handlerThread2CurrentProcessingEvent);
processingThread2 = thread2Example.startCopying();
}
private void completeThread2(object sender, RunWorkerCompletedEventArgs e) {
Console.WriteLine("Completed Thread1. TID: " + Thread.CurrentThread.ManagedThreadId);
processingThread2 = true;
}

private void handlerThread2CurrentProcessingEvent(string filename) {
Console.WriteLine("Thread2 Processing: " + filename);
Thread2CurrentProcessingEvent(filename);
}
}

public class frmMain {

private ThreadBL threadBL = new ThreadBL();

public void frmMain() {

threadBL.Thread1CurrentProcessingEvent += new ThreadExample.CurrentFileProcessing(handlerThread1ProgressEvent);
threadBL.Thread2CurrentProcessingEvent += new ThreadExample.CurrentFileProcessing(handlerThread2ProgressEvent);

threadBL.processThreads();
}

private void handlerThread1ProgressEvent(string progress) {
lblCopyingProgress.Invoke(new MethodInvoker(delegate { lblCopyingProgress.Text = progress; }));
this.Refresh();
}
private void handlerThread2ProgressEvent(string progress) {
lblCopyingProgress.Invoke(new MethodInvoker(delegate { lblCopyingProgress.Text = progress; }));
this.Refresh();
}
}

最佳答案

在主线程上调用的最佳方式是调用 Control.Invoke(...) 或 Control.BeginInvoke(...)。前者会阻塞,直到主线程处理完调用。后者只会在主线程空闲时发布要处理的调用。

如果您不希望您的线程知道 Control 类型,您可以简单地将 Invoke 和 BeginInvoke 调用包装到您自己的接口(interface)中,例如 IInvoker,并声明您的主窗体来实现它。将接口(interface)作为线程的参数传递,就可以了。

为了进行线程工作,我建议使用 ThreadPool。我会做这样的事情(假设所有方法都在您的主窗体代码中)。

private void MyThread(object param)
{
MyForm form = (MyForm) param; // pass your form as your param
DoWork(); // Whatever it is you are doing on your thread
form.Invoke(new MethodInvoker(form.NotifyComplete)); // Invokes on main thread
}

public void Button_OnClick(object sender, EventArgs args)
{
ThreadPool.QueueUserWorkItem(new Action<object>(MyThread), this);
}


private void NotifyComplete()
{
// update your controls here
...
}

关于c# - 多线程更新主窗体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5846418/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com