首页 > 解决方案 > 如何有效地在 DataGridView 中填充生成的列?

问题描述

我的 Winforms 程序中有一个 DataGridView 设置,其中包含从数据库填充的信息。

我使用Select * FROM [Data]以下代码填充了 DataGridView:

private void GetData(string selectCommand)
{
    try
    {
        // Create a new data adapter based on the specified query.
        dataAdapter = new OleDbDataAdapter(selectCommand, strConn);

        // Create a command builder to generate SQL update, insert, and
        // delete commands based on selectCommand.
        OleDbCommandBuilder commandBuilder = new OleDbCommandBuilder(dataAdapter);

        // Populate a new data table and bind it to the BindingSource.
        DataTable table = new DataTable
        {
            Locale = CultureInfo.InvariantCulture
        };
        dataAdapter.Fill(table);
        bindingSource1.DataSource = table;

        // Resize the DataGridView columns to fit the newly loaded content.
        LogDataGridView.AutoResizeColumns(
            DataGridViewAutoSizeColumnsMode.AllCellsExceptHeader);
    }
    catch (OleDbException) { }
}

标签: c#winformsdatagridviewoledb

解决方案


选项 1

如果存储状态信息的数据库没有被其他进程不断更新,您可以简单地指定要连接的列是外部数据库中表的一部分。

如果它从其他来源接收更新,则必须使用 Timer 轮询它(或使用 FileSystemWatcher 类在数据库文件更改时接收通知)。不过,查询是相同的。

在 JOIN 子句之后添加[;database=Second database Path].[Source Table] AS alias,然后照常进行。

例如,设置指定第二个数据库路径的 DataGridView.Datasource。

LogDataGridView.DataSource = GetCrossJoinedTable([Second database path]);

连接字符串Data Source=包含第一个数据库的路径。
然后,使用公共键交叉连接两个数据库中的两个表,并返回包含第二个数据库中表的状态信息的[Order Status]列(如果我正确阅读更新的代码,该列)。

private DataTable GetCrossJoinedTable(string secondDataBasePath)
{
    var dt = new DataTable("JoinedTable");
    string sql = "SELECT [Data].*, status.[Order Status] " +
                $"FROM [Data] LEFT JOIN [;database={secondDataBasePath}].[Output] AS status " +
                 "ON [Data].[SO nr] = status.[Source No]";
    using (var conn = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=firstDatabase.accdb;Persist Security Info=false;"))
    using (var cmd = new OleDbCommand(sql, conn)) {
        conn.Open();
        using (var reader = cmd.ExecuteReader()) {
            dt.Load(reader);
            return dt;
        }
    }
}

选项 2
查询第一个数据库,添加一个状态列,从第二个数据库更新状态信息,然后使用计时器轮询新的状态信息。

您可以调用LogDataGridView.DataSource = GetMainTableData()设置数据源。它还将从第二个数据库加载状态信息。

然后计时器将仅轮询第二个数据库,以检查DataTable 中[Order Status]匹配[SO nr]列的 Column 是否已更改。
当 DataTable(这里是一个名为 的字段mainDT)更新时,您的 DataGraidView 将立即反映更改。

  • 如果可以编辑数据,如果IsCurrentCellInEditMode返回true(阅读那里关于 CheckBoxColumns 的注释),或在 Cell 处于编辑模式时暂停(CellBeginEdit事件)并在 Cell 退出编辑模式时恢复(CellEndEdit事件),计时器应跳过更新)。
  • Form.FormClosing请记住在表单关闭(事件)时停止并处理计时器。

如果您不需要计时器来轮询状态信息,只需UpdateStatusInfo()在需要更新 DGV 时调用。

System.Windows.Forms.Timer sqlTimer = null;
DataTable mainDT = new DataTable("MainTable");

private DataTable GetMainTableData()
{
    string sql = "SELECT * FROM Data";
    using (var conn = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=firstDatabase.accdb;Persist Security Info=false;"))
    using (var cmd = new OleDbCommand(sql, conn)) {
        conn.Open();
        var reader = cmd.ExecuteReader();
        mainDT.Load(reader);
        mainDT.Columns.Add(new DataColumn() {
            Caption = "Status", ColumnName = "fStatus", DataType = typeof(string), ReadOnly = true
        });
    }
    sqlTimer = new System.Windows.Forms.Timer() { Interval = 5000 };
    sqlTimer.Tick += (s, ev) => { UpdateStatusInfo(mainDT, false); };
    sqlTimer.Start();
    return UpdateStatusInfo(mainDT, true);
}

private DataTable UpdateStatusInfo(DataTable dt, bool returnTable)
{
    string sql = "SELECT Output.[Order Status], Output.[Source No] FROM Output";
    using (var conn = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=secondDatabase.accdb;Persist Security Info=false;"))
    using (var cmd = new OleDbCommand(sql, conn)) {
        conn.Open();
        var reader = cmd.ExecuteReader();
        dt.Columns["fStatus"].ReadOnly = false;
        while (reader.Read()) {
            dt.Select($"fNumber = {reader["Source No"]}").FirstOrDefault()?
              .SetField("fStatus", reader["Order Status"].ToString());
        }
        dt.Columns["fStatus"].ReadOnly = true;
        return returnTable ? dt : null;
    }
}

推荐阅读