【问题标题】:Set visibility of DataGridView columns using CheckedListBox使用 CheckedListBox 设置 DataGridView 列的可见性
【发布时间】:2019-07-05 14:33:25
【问题描述】:

我正在开发一个操作 SQL Server 数据库的 Windows 窗体应用程序。当我单击一个填充了所有表的组合框时,我将所选表中的每一列添加到checkedlistbox 中,而不是当我检查以下列消失时。我被困在这里了。

private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
        var tableName = comboBox1.SelectedItem;

        SqlDataAdapter sqlDa = new SqlDataAdapter($"SELECT * FROM {tableName}", form1.conn = new SqlConnection($"Server = {form1.ServerBox.Text }; Database = { form1.DBBox.Text}; Trusted_Connection = True"));

        DataTable dataTable = new DataTable();
        sqlDa.Fill(dataTable);

        string comboQuery = $"SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = N'{tableName}'";

        using (form1.conn = new SqlConnection($"Server = {form1.ServerBox.Text }; Database = { form1.DBBox.Text}; Trusted_Connection = True"))
        {
            form1.conn.Open();

            using (SqlCommand cmd = new SqlCommand(comboQuery, form1.conn))
            {
                using (SqlDataReader reader = cmd.ExecuteReader())
                {
                    checkedListBox1.Items.Clear();

                    while (reader.Read())
                    {
                        checkedListBox1.Items.Add((string)reader["COLUMN_NAME"]);
                    }
                }
            }

            form1.conn.Close();
        }

        dataGridView1.DataSource = dataTable;
}

感谢您投入时间!

【问题讨论】:

    标签: c# .net winforms datagridview


    【解决方案1】:

    当您在DataGridView 中有列时,您不需要从 SQL Server 再次加载它们,并且如另一个答案中所示,您可以从 DataGridView 获取列名。

    要将列添加到CheckedListBox,我更喜欢使用DataSourceDisplayMemberValueMemberCheckedListBox 中显示列HeaderText,同时可以访问它们的名称以便能够找到它们在DataGridView

    然后我会根据相应列的可见性设置项目的初始检查状态。

    然后我处理ItemCheck事件并根据选中项找到列名,并根据新的检查状态设置列可见性:

    //Add the columns to checked list box
    var columns = dataGridView1.Columns.Cast<DataGridViewColumn>()
        .Select(x => new { x.Name, x.HeaderText }).ToList();
    checkedListBox1.DataSource = columns;
    checkedListBox1.ValueMember = "Name";
    checkedListBox1.DisplayMember = "HeaderText";
    
    //Set initial check state based on columns visibility
    for (int i = 0; i < checkedListBox1.Items.Count; i++)
    {
        dynamic item = checkedListBox1.Items[i];
        checkedListBox1.SetItemChecked(i, dataGridView1.Columns[(string)item.Name].Visible);
    }
    
    //Hanlde ItemCheck event
    checkedListBox1.ItemCheck += (obj, args) =>
    {
        dynamic item = checkedListBox1.Items[args.Index];
        var visible = args.NewValue == CheckState.Checked ? true : false;
        dataGridView1.Columns[(string)item.Name].Visible = visible;
    };
    

    以防万一您有兴趣使用ContextMenuStrip

    //Add the columns to context menu strip
    foreach (DataGridViewColumn c in dataGridView1.Columns)
    {
        var item = (ToolStripMenuItem)contextMenuStrip1.Items.Add(c.HeaderText);
        item.Tag = c.Name;
        item.Checked = c.Visible;
        item.CheckOnClick = true;
    
        //Hanlde CheckStateChanged event of context menu strip items
        item.CheckStateChanged += (obj, args) =>
        {
            var i = (ToolStripMenuItem)obj;
            dataGridView1.Columns[(string)i.Tag].Visible = i.Checked;
        };
    }
    
    //Show context menu strip on right click on data grid veiw header
    dataGridView1.CellMouseClick += (obj, args) =>
    {
        if (args.RowIndex == -1 && args.Button == MouseButtons.Right)
            contextMenuStrip1.Show(Cursor.Position);
    };
    

    【讨论】:

    • 但是当我将值更改为不同的表时,它们都会被保存,如果我在第一个表“ID”和第二个“名称”和“编号”中有示例,它们都是保存在 ToolStripMenu 中,我只需要选中的表。
    • 如果您将代码放在表单的Load 事件处理程序中并且有dataGridView1contextMenuStrip1 它将正常工作。对?这意味着对于dataGridView2,它需要contextMenuStrip2
    • 好吧,当您从表格组合框中选择一个项目时,datagridview 会随着所选表格的变化而变化,我已经这样编写了代码。但是,当我从第一个表中选择其他表时,stripmenu 会被保存,并且我在该菜单中拥有所有值。
    • 我可以想象代码中可能存在一些错误,但我不确定您的代码。让我们保持这个帖子的原样(因为这段代码是对帖子的补充,它不是您问题的主要答案)并提出一个新问题,包括minimal reproducible example 来重现问题并描述预期的行为,然后我或者也许其他社区成员会帮助您解决问题:)
    【解决方案2】:

    您可以先填写CheckedListBox,可能是这样:

    checkedListBox1.Items.Clear   
    checkedListBox1.Items.AddRange(dataGridView1.Columns.Cast<DataGridViewColumn>()
                                                        .Select(x => x.Name)
                                                        .ToArray());
    
    for (int i = 0; i < checkedListBox1.Items.Count; i++)
    {
        checkedListBox1.SetItemChecked(i, true);
    }
    checkedListBox1.CheckOnClick = true;
    

    现在您可以像这样编写checkedListBox1_SelectedIndexChanged 事件:

    for (int i = 0; i < checkedListBox1.Items.Count; i++)
    {
        dataGridView1.Columns[i].Visible =
           checkedListBox1.GetItemCheckState(i) == CheckState.Checked;
    }
    

    更新 Reza 发现了ItemCheck 事件;不知道我是怎么错过的;-)。这显然要好得多,因为它不需要遍历所有项目..

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-23
      • 2011-11-21
      • 1970-01-01
      • 2011-04-28
      相关资源
      最近更新 更多