如何正确地更新的DataGridView,所以GUI不会冻结 [英] How to update DataGridView correctly, so GUI doesn't freeze

查看:318
本文介绍了如何正确地更新的DataGridView,所以GUI不会冻结的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个BackgroundWorker,它做了一些计算和报告进度的结果作为字符串。此字符串需要插入的dataGridView。但是,当插入值,GUI冻结。

 私人无效bckgrSorter_DoWork(对象发件人,DoWorkEventArgs E)
{
    的for(int i = 0; I< 1000;我++)
    {
        //做一些计算
        bckgrSorter.ReportProgress(ⅰ,someString);
    }
}

 私人无效bckgrSorter_ProgressChanged(对象发件人,ProgressChangedEventArgs E)
 {
     字符串结果=(字符串)e.UserState;
     dataGridView1.Rows.Add(结果);
 }
 

所以,即使我在后台线程所有繁重的计算,图形用户界面仍然冻结,因为DataGridView中的。

修改为code:

 私人无效bckgrSorter_DoWork(对象发件人,DoWorkEventArgs E)
    {
        字符串[]文件夹= //一些文件夹来从文件列表

        bckgrFileScanner.RunWorkerAsync(文件夹);
    }

私人无效bckgrFileScanner_DoWork(对象发件人,DoWorkEventArgs E)
    {
        字符串[]文件夹=(字符串[])e.Argument;
        的foreach(文件夹弦F)
        {
            GetFileList(REF scannedFiles,男,bckgrFileScanner);
            bckgrFileScanner.ReportProgress(1);
        }
    }

公共无效GetFileList(参考名单,其中,FileInfo的>的flist,串fPath,BackgroundWorker的扫描仪)
        {
            DirectoryInfo的迪=新的DirectoryInfo(fPath);
            的FileInfo [] F1 = di.GetFiles();

            的foreach(FileInfo的fiTemp在FI)
            {
                // AR〜$ saakasnevajadzīgie温度faili,TOSizlaižam
                如果(fiTemp.Name.StartsWith(〜$)==假)
                {
                    fList.Add(fiTemp);
                    scanner.ReportProgress(0,fiTemp.Name);
                }
            }
            DirectoryInfo的[] dFolders = di.GetDirectories();

            // katraiapakšmapeirekursīviizsaucam所以funkciju
            的foreach(DirectoryInfo的d在dFolders)
            {
                GetFileList(REF的flist,d.FullName,扫描仪);
            }
        }

私人无效bckgrFileScanner_ProgressChanged(对象发件人,ProgressChangedEventArgs E)
    {
        如果(e.ProgressPercentage == 0)
        {
            filesDataGrid.Rows.Add(e.UserState);
        }

        别的progressBar1.PerformStep();
    }
 

解决方案

在我看来像你需要批量从你的工作线程的结果。也许你可以让ProgressChanged事件进展返回结果或东西的集合?或者,只有在事件火灾最多每隔半秒钟的最新数据。我怀疑的问题是,你只是想太快添加数据。你需要做的工作较少的单位,在每个单元(一次性添加大量的行)更多的工作。

巴贝尔是正确的。这样的事情可能会做你想要的(我还没有尝试编译它):

 公共无效GetFileList(参考名单,其中,FileInfo的>的flist,串fPath,BackgroundWorker的扫描仪)
    {
        DirectoryInfo的迪=新的DirectoryInfo(fPath);
        的FileInfo [] F1 = di.GetFiles();

        名单<字符串> progressData =新的名单,其中,串>();

        的foreach(FileInfo的fiTemp在FI)
        {
            // AR〜$ saakas nevajadzigie温度faili,TOSizlaižam
            如果(fiTemp.Name.StartsWith(〜$)==假)
            {
                fList.Add(fiTemp);
                progressData.Add(fiTemp.Name);
                如果(progressData.Count→50){
                    scanner.ReportProgress(0,progressData.ToArray());
                    progressData.Clear(); //你的数据刚刚复制到一个数组并将其发送到GUI,清除列表并开始计数再次
                }
            }
        }

        如果(progressData.Count大于0){
            scanner.ReportProgress(0,progressData.ToArray());
        }

        DirectoryInfo的[] dFolders = di.GetDirectories();

        // katraiapakšmapeirekursivi izsaucam所以funkciju
        的foreach(DirectoryInfo的d在dFolders)
        {
            GetFileList(REF的flist,d.FullName,扫描仪);
        }
    }
 

这不是一个真正的很好的解决方案,但它是一个开始......

您将需要转换e.UserState为一个字符串数组中的回调,以及...

I have a backgroundworker, which does some calculations and reports progress result as string. This string needs to be inserted into dataGridView. But while inserting values, GUI freezes.

private void bckgrSorter_DoWork(object sender, DoWorkEventArgs e)
{
    for (int i=0; i<1000; i++)
    {
        // doing some calculations
        bckgrSorter.ReportProgress(i, someString);
    }
}    

 private void bckgrSorter_ProgressChanged(object sender, ProgressChangedEventArgs e)
 {
     string results = (string)e.UserState;
     dataGridView1.Rows.Add(results);
 }

So even though I do all the heavy calculations on a background thread, GUI still freezes, because of DataGridView.

Edit for code:

private void bckgrSorter_DoWork(object sender, DoWorkEventArgs e)
    {
        string[] folders = // some folders to get File List from

        bckgrFileScanner.RunWorkerAsync(folders);            
    }

private void bckgrFileScanner_DoWork(object sender, DoWorkEventArgs e)
    {
        string[] folders = (string[])e.Argument;
        foreach (string f in folders)
        {
            GetFileList(ref scannedFiles, f, bckgrFileScanner);
            bckgrFileScanner.ReportProgress(1);
        }
    }

public void GetFileList(ref List<FileInfo> fList, string fPath, BackgroundWorker scanner)
        {
            DirectoryInfo di = new DirectoryInfo(fPath);
            FileInfo[] fi = di.GetFiles();

            foreach (FileInfo fiTemp in fi)
            {
                //ar ~$ saakas nevajadzīgie temp faili, tos izlaižam
                if (fiTemp.Name.StartsWith("~$") == false)
                {
                    fList.Add(fiTemp);
                    scanner.ReportProgress(0, fiTemp.Name);
                }
            }
            DirectoryInfo[] dFolders = di.GetDirectories();

            //katrai apakšmapei rekursīvi izsaucam šo funkciju
            foreach (DirectoryInfo d in dFolders)
            {
                GetFileList(ref fList, d.FullName, scanner);
            }
        }

private void bckgrFileScanner_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        if (e.ProgressPercentage == 0)
        {
            filesDataGrid.Rows.Add(e.UserState);
        }

        else progressBar1.PerformStep();
    }

解决方案

It looks to me like you need to batch up the results from your worker thread. Maybe you could make the ProgressChanged event return a collection of progress results or something? Or only have the event fire at most every half a second with the latest data. I suspect the problem is that you're just trying to add data too fast. You need to do less units of work with more work in each unit (add lots of rows in one go).

Babar is right. Something like this would probably do what you want (I haven't tried to compile it):

    public void GetFileList(ref List<FileInfo> fList, string fPath, BackgroundWorker scanner)
    {
        DirectoryInfo di = new DirectoryInfo(fPath);
        FileInfo[] fi = di.GetFiles();

        List<string> progressData = new List<string>();

        foreach (FileInfo fiTemp in fi)
        {
            //ar ~$ saakas nevajadzigie temp faili, tos izlaižam
            if (fiTemp.Name.StartsWith("~$") == false)
            {
                fList.Add(fiTemp);
                progressData.Add(fiTemp.Name);
                if (progressData.Count > 50){
                    scanner.ReportProgress(0, progressData.ToArray());
                    progressData.Clear();//You've just copied the data to an array and sent it to the GUI, clear the list and start counting up again
                }
            }
        }

        if (progressData.Count > 0){
            scanner.ReportProgress(0, progressData.ToArray());
        }

        DirectoryInfo[] dFolders = di.GetDirectories();

        //katrai apakšmapei rekursivi izsaucam šo funkciju
        foreach (DirectoryInfo d in dFolders)
        {
            GetFileList(ref fList, d.FullName, scanner);
        }
    }

It's not really a very good solution but it's a start...

You will need to cast e.UserState to a string array in your callback as well...

这篇关于如何正确地更新的DataGridView,所以GUI不会冻结的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆