使用 DataTable 将数据加载到 DataGridView 的进度条

Posted

技术标签:

【中文标题】使用 DataTable 将数据加载到 DataGridView 的进度条【英文标题】:Progressbar for loading data to DataGridView using DataTable 【发布时间】:2013-08-25 00:41:20 【问题描述】:

我有一个DataGridView,我在其中从 SQL 服务器数据库加载数据。当我加载数据时,它需要很长时间。

我想向用户提供数据正在加载的信息。请问当数据加载到DataGridView 时,连接Progressbar 的最佳方式是什么?

我不希望任何人为我编写完整的工作代码。我只是想知道怎么做。

我看到有人悬赏我的问题。我想说的是,目前我正在使用这段代码,如果它合适的话,我会很高兴。

DTGdataTable = new DataTable();
SqlDataAdapter SDA = new SqlDataAdapter
SDA.Fill(DTGdataTable);
dataGridView1.DataSource = DTGdataTable ;

感谢大家的宝贵时间。

【问题讨论】:

Want to show animation while datagridview is filling with data 的可能重复项 如果您只需要用户知道它正在加载,请使用 this.Cursor = Cursors.Wait; this.Cursor = Cursors.Default; 包装您的代码 【参考方案1】:

如果问题是从数据库中获取数据需要很长时间,我有一个可能的解决方案:

    private void buttonLoad_Click(object sender, EventArgs e)
    
        progressBar.Visible = true;
        progressBar.Style = ProgressBarStyle.Marquee;
        System.Threading.Thread thread = 
          new System.Threading.Thread(new System.Threading.ThreadStart(loadTable));
        thread.Start();
    

    private void loadTable()
    
        // Load your Table...
        DataTable table = new DataTable();
        SqlDataAdapter SDA = new SqlDataAdapter();
        SDA.Fill(table);
        setDataSource(table);
    

    internal delegate void SetDataSourceDelegate(DataTable table);
    private void setDataSource(DataTable table)
    
        // Invoke method if required:
        if (this.InvokeRequired)
        
            this.Invoke(new SetDataSourceDelegate(setDataSource), table);
        
        else
        
            dataGridView.DataSource = table;
            progressBar.Visible = false;
        
    

将加载数据的方法放到另一个线程中,完成后设置数据源。应该需要调用。如果您想在进度条中显示百分比值,请不要使用“Marquee”样式并添加另一个函数和委托,您可以调用它来设置进度条的值。

如果将数据绑定到网格是问题,那么您不能将绑定放入另一个线程,您可能会显示在另一个线程中运行的进度弹出窗口。

我希望这会有所帮助。

【讨论】:

【参考方案2】:

试试这个...这应该是最快的路线...

1) Add a button control.
2) Add a datagridview control.
3) Add a single column into the datagridview control.
4) Add a progressbar control.
5) Leave them all with default names.

在 button1_Click 事件下,添加这段代码...

int maxnumber = 1000;
progressBar1.Value = 0;
progressBar1.Maximum = maxnumber;
for (int x = 0; x <= maxnumber - 1; x++)

    Application.DoEvents();
    dataGridView1.Rows.Add(new string[] Convert.ToString(x));
    progressBar1.Value += 1;
    label1.Text = progressBar1.Value.ToString();

就是这样。编辑以满足您的需求。这不是您想要的完整的确切代码,但它应该可以帮助您入门。我冒昧地声明 maxnumber 来保持进度条的限制。在您的情况下,这应该是您的数据库的行数,并减去 1,因为索引总是从零开始:)

上面的方法是单线程的,这意味着你仍然不能在你的循环还没有完成的时候进行多任务处理。在某些情况下,根据代码的算法,使用单线程方法可能比使用多线程方法更快。无论如何,第二种方法是使用后台工作人员。这通常是人们最喜欢的,因为用户仍然可以在列表加载时做一些事情。有点像安装程序,即使正在执行某些操作,您也可以取消安装。下面的网站应该可以帮助您入门。代码在 VB.NET 中,但可以轻松转换为 C# :)

http://social.msdn.microsoft.com/Forums/vstudio/en-US/efd7510c-43ed-47c4-86a3-1fa350eb0d30/fill-datagridview-using-backgroundworker-progressbar?forum=vbgeneral

【讨论】:

Application.DoEvents? BackgroundWorker 不是更好的建议吗? @LarsTech 是的,你是对的。后台工作者是更好的选择,因为 Application.DoEvents 仍然是单线程的。这就是为什么我说最快的路线,不管哪个更好。吃完早餐后,我也可能会做一个后台工作方法:)谢谢您指出,先生:) @chris_techno25 感谢您发布此答案。据我所知,我可以将它连接到 string[],当时我可能已经使用了它,但现在我正在使用 SqlDataAdapter 并像`SDA.Fill(DataTable);`一样加载到 datagridview 中,您的解决方案是否也适用于数据表 - dataGridView1.DataSource = DataTable; @Marek 我不这么认为......但我可能是错的。我遇到了同样的问题,我最终按照我的建议做了。 datagridview 控件不报告任何内容。你能做的最好的就是显示一个“选框”类型的进度条,告诉用户某些东西仍在工作。我还没有找到关于你想要什么的文档,但它仍然是可能的,你只需要覆盖很多默认代码:)【参考方案3】:

问题是所有数据一起加载并从数据库返回。 您需要获取数据加载进度。这可以从数据库中完成。

    从数据库中获取数据行的计数。 (此查询将返回一个数字,因此会更快)。

    分批获取数据(分治策略),可以使用OFFSET和FETCH数据库查询。 (这是在每次调用时返回部分数据) OFFSET 和 FETCH 在不同的数据库上可用。在 MSSQL 中,它是在 2012 版本中引入的。

当我们从服务器获取部分数据时,我们可以计算进度。

【讨论】:

对于较旧的数据库版本,您可以使用 ROW_NUMBER() 获取部分结果。【参考方案4】:

在您的代码中,这一行将占用大部分处理时间:

SDA.Fill(DTGdataTable);

所以我认为最重要的是在执行过程中跟踪进度。为此,您首先需要知道您期望的行数。 SQLDataAdapter 无法提供此信息,因此您需要先运行额外的 COUNT(*) 查询才能获取此数字。然后,您可以将其用作 ProgressBar 上的最大值。

我的实际加载代码基于 Michael Hofmeiers 解决方案,但不是在选取框模式下使用 ProgressBar,而是使用来自 Timer Control 的真实进度数据提供给它。因此,在您的表单上,您添加了一个 Timer 控件(在我的示例中名为 progressTimer),将其 Interval 设置为 100 毫秒,并将 Enabled 设置为 false。那么代码就变成了:

private DataTable table = null;

private void buttonLoad_Click(object sender, EventArgs e)

    // TODO: Select the row count here and assign it to progressBar.Maximum

    progressBar.Visible = true;             
    System.Threading.Thread thread = 
      new System.Threading.Thread(new System.Threading.ThreadStart(loadTable));
    thread.Start();
    progressTimer.Enabled = true;


private void loadTable()

    // Load your Table...
    this.table = new DataTable();
    SqlDataAdapter SDA = new SqlDataAdapter();
    SDA.Fill(table);
    setDataSource(table);


internal delegate void SetDataSourceDelegate(DataTable table);
private void setDataSource(DataTable table)

    // Invoke method if required:
    if (this.InvokeRequired)
    
        this.Invoke(new SetDataSourceDelegate(setDataSource), table);
    
    else
    
        progressTimer.Enabled = false;
        dataGridView.DataSource = table;
        progressBar.Visible = false;
    


private void progressTimer_Tick(object sender, EventArgs e)

    if (this.table != null)
        progressBar.Value = this.table.Rows.Count;

当您运行此程序时,您的应用程序将在加载期间保持响应,并且您会看到 ProgressBar 发生变化以反映加载的行数。只有在最后(当您在 DataGridView 上设置 DataSource 时)应用程序才会“挂起”,但我认为没有办法避免这种情况。您只能从主线程执行此操作,因此 UI 变得无响应是不可避免的。但在我的测试中,DataGridView 可以在大约一秒钟内轻松处理 300K+ 行,所以这应该不是什么大问题。

【讨论】:

【参考方案5】:

1.从google下载一个ajax loader.gif。

2.用此代码替换该图像..

3.相应地设置时间..

<div id="spinner" style="display: none;">
<span id="ss" style="float: left; margin-left: 50% !Important; margin-top: 22% !Important;">
<img src="ajax-pink-loader.gif"  />
</span>
</div>

    $("#ssubmit").click(function () 
        $("#spinner").show();
        setInterval(function () 
            $("#spinner").hide();
        , 20000);
    );

【讨论】:

问题标记为 WinForms。恕我直言,better DELETE the question没有用的答案。

以上是关于使用 DataTable 将数据加载到 DataGridView 的进度条的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中将数据加载到 DataTable 会出现“未知 SQL 类型 - 0”错误

怎么把数据库中的数据通过jquery easyui datagrid进行绑定绑定

XDocument 到 DataTable 异步

DataTable.Load(FbDataReader) 不会将所有内容加载到 DataTable

jquery.datatable插件如何不自动加载数据?

使用 TABS 时 DataTable.js 无法正确加载