Winforms 从后台线程更新UI,该线程在线程完成时在主UI的循环中调用

Winforms 从后台线程更新UI,该线程在线程完成时在主UI的循环中调用,winforms,multithreading,Winforms,Multithreading,我有一个WinForms应用程序,它正在调用一个业务类方法,该方法执行一些繁重的操作,每次调用大约需要5秒钟。主窗体在循环中调用此方法。这个循环可以运行10到10000次 WinForms应用程序向业务类发送一个参数,并有一个区域显示每个方法调用所花费的时间以及方法返回的值。如何通知我的主窗口,并用方法为每个调用返回的内容更新主winform中的文本区域 当前,在所有线程完成后,数据会同时出现。每次调用完成后,是否有方法更新循环所有迭代的UI?我不介意是否也按顺序进行 形式 HeavyD

我有一个WinForms应用程序,它正在调用一个业务类方法,该方法执行一些繁重的操作,每次调用大约需要5秒钟。主窗体在循环中调用此方法。这个循环可以运行10到10000次

WinForms应用程序向业务类发送一个参数,并有一个区域显示每个方法调用所花费的时间以及方法返回的值。如何通知我的主窗口,并用方法为每个调用返回的内容更新主winform中的文本区域

当前,在所有线程完成后,数据会同时出现。每次调用完成后,是否有方法更新循环所有迭代的UI?我不介意是否也按顺序进行

形式

    HeavyDutyClass hd;
    public Form1()
    {
        InitializeComponent();
        hd = new HeavyDutyClass();
    }


    //BUTTON CLICK
    private void Start_Click(object sender, EventArgs e)
    {

        int filecount = 5000;  //BAD - opening 5000 threads! Any other approach?
        hd.FileProcessed += new EventHandler(hd_FileProcessed);


        var threads = new Thread[filecount];

        for (int i = 0; i < filecount; i++)
        {
            threads[i] = new Thread(() => { hd.LongRunningMethod(); });
            threads[i].Start();   
        }

    }

    //BUSINESS CLASS EVENT THAT FIRES WHEN BUSINESS METHOD COMPELTES
    void hd_FileProcessed(object sender, EventArgs e)
    {

        if (dgv.InvokeRequired)
        {
            dgv.Invoke((MethodInvoker)delegate { UpdateGrid(); });

        }
    }

    private void UpdateGrid()
    {
        dgv.Rows.Add(1);
        int i = dgv.Rows.Count;
        dgv.Rows [ i-1].Selected = true;
        dgv.FirstDisplayedScrollingRowIndex = i - 1;

    }
HeavyDutyClass hd;
公共表格1()
{
初始化组件();
hd=新的重型卡车();
}
//按钮点击
私有无效开始\单击(对象发送者,事件参数e)
{
int filecount=5000;//错误-打开5000个线程!还有其他方法吗?
hd.FileProcessed+=新事件处理程序(hd_FileProcessed);
var threads=新线程[filecount];
for(int i=0;i{hd.LongRunningMethod();});
线程[i].Start();
}
}
//当业务方法完成时激发的业务类事件
void hd_FileProcessed(对象发送方,事件参数e)
{
如果(dgv.InvokeRequired)
{
Invoke((MethodInvoker)委托{UpdateGrid();});
}
}
私有void UpdateGrid()
{
dgv.Rows.Add(1);
int i=dgv.Rows.Count;
dgv.Rows[i-1]。所选值=true;
dgv.FirstDisplayedScrollingRowIndex=i-1;
}
商务舱

    public event EventHandler FileProcessed;

    public HeavyDutyClass()
    {
    }

    protected virtual void OnMyEvent(EventArgs e)
    {
        if (FileProcessed != null)
        {
            FileProcessed(this, e);
        }
    }

    public bool LongRunningMethod()
    {
        for (double i = 0; i < 199990000; i++)
        {
            //time consuming loop
        }
        OnMyEvent(EventArgs.Empty);
        return true;
    }
public EventHandler FileProcessed;
公共重型卡车()
{
}
受保护的虚拟void OnMyEvent(事件参数e)
{
if(FileProcessed!=null)
{
文件处理(本,e);
}
}
公共bool LongRunningMethod()
{
对于(双i=0;i<199990000;i++)
{
//耗时循环
}
OnMyEvent(EventArgs.Empty);
返回true;
}

添加Winforms项目,在表单上放置标签控件,复制粘贴此代码并点击F5

[编辑]:使用用户的
业务类
注释进行更新

NB:我的表单类名为
Form3
。您可能需要更改
Program.cs,反之亦然。

using System.ComponentModel;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public class BusinessClass
    {
        public int MyFunction(int input)
        {
            return input+10;
        }
    }

    public partial class Form3 : Form
    {
        private BackgroundWorker _worker;
        BusinessClass _biz = new BusinessClass();
        public Form3()
        {
            InitializeComponent();
            InitWorker();
        }

        private void InitWorker()
        {
            if (_worker != null)
            {
                _worker.Dispose();
            }

            _worker = new BackgroundWorker
            {
                WorkerReportsProgress = true,
                WorkerSupportsCancellation = true
            };
            _worker.DoWork += DoWork;
            _worker.RunWorkerCompleted += RunWorkerCompleted;
            _worker.ProgressChanged += ProgressChanged;
            _worker.RunWorkerAsync();
        }


        void DoWork(object sender, DoWorkEventArgs e)
        {
            int highestPercentageReached = 0;
            if (_worker.CancellationPending)
            {
                e.Cancel = true;
            }
            else
            {
                double i = 0.0d;
                int junk = 0;
                for (i = 0; i <= 199990000; i++)
                {
                    int result = _biz.MyFunction(junk);
                    junk++;

                    // Report progress as a percentage of the total task.
                    var percentComplete = (int)(i / 199990000 * 100);
                    if (percentComplete > highestPercentageReached)
                    {
                        highestPercentageReached = percentComplete;
                        // note I can pass the business class result also and display the same in the LABEL  
                        _worker.ReportProgress(percentComplete, result);
                        _worker.CancelAsync();
                    }
                }

            }
        }

        void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                // Display some message to the user that task has been
                // cancelled
            }
            else if (e.Error != null)
            {
                // Do something with the error
            }
        }

        void ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            label1.Text =  string.Format("Result {0}: Percent {1}",e.UserState, e.ProgressPercentage);
        }
    }
}
使用System.ComponentModel;
使用System.Windows.Forms;
命名空间Windows窗体应用程序1
{
公务舱
{
公共整数MyFunction(整数输入)
{
返回输入+10;
}
}
公共部分类表单3:表单
{
私人背景工人;
BusinessClass _biz=新的BusinessClass();
公共表格3()
{
初始化组件();
InitWorker();
}
私有void InitWorker()
{
如果(_worker!=null)
{
_worker.Dispose();
}
_worker=新的后台工作人员
{
WorkerReportsProgress=true,
WorkerSupportsScanCellation=真
};
_worker.DoWork+=DoWork;
_worker.RunWorkerCompleted+=RunWorkerCompleted;
_worker.ProgressChanged+=ProgressChanged;
_worker.RunWorkerAsync();
}
无效DoWork(对象发送方,DoWorkEventArgs e)
{
int highestPercentageReached=0;
如果(_worker.CancellationPending)
{
e、 取消=真;
}
其他的
{
双i=0.0d;
int=0;
对于(i=0;i最高百分比)
{
highestPercentageReached=完成百分比;
//注意,我也可以传递业务类结果,并在标签中显示相同的结果
_工人报告进度(完成百分比、结果);
_worker.CancelAsync();
}
}
}
}
void RunWorkerCompleted(对象发送方,RunWorkerCompletedEventArgs e)
{
如果(如已取消)
{
//向用户显示任务已完成的消息
//取消
}
否则如果(例如错误!=null)
{
//对这个错误做点什么
}
}
void ProgressChanged(对象发送方,progresschangedventargs e)
{
label1.Text=string.Format(“结果{0}:百分比{1}”,e.UserState,e.ProgressPercentage);
}
}
}
有了它,您还可以非常轻松地实现取消功能。
请注意,在初始化过程中,我设置了
WorkerSupportsCancellation=true
&然后我检查了DoWork中的
\u worker.CancellationPending
。因此,如果您想通过单击
取消按钮来取消流程,那么您将在按钮处理程序-
\u worker.CancelAsync()中编写此代码

为什么不使用Backgroundroker并使用ProgressChanged处理程序(
ReportProgress方法
)来实现您想要做的事情?后台工作人员是指这种单一的长期运行的后台工作。你可以在这上面搜索并找到很多样本。我可以循环调用它大约5000次吗?是的,你可以。更新了答案。谢谢。这是否能够支持向我的业务类方法发送参数并从中获取返回值?我想我得叫我的车了