无法使DataGridView与ComboBox下拉列表一起使用

时间:2016-06-17 19:49:12

标签: c# winforms datagridview combobox datatable

我需要一些帮助才能使我的代码正常工作。事实证明DataGridView比我预想的要复杂得多。我需要有人向我展示如何修复我的代码,以便DataGridView控件可以更新,DataGridViewComboBoxColumn下拉列表和DataGridViewCheckBoxColumn控制所有工作。如果你提供的解决方案有点优雅和完整,我对任何策略都没关系。我已经花了太多时间试图解决这个问题。任何想法或建议将不胜感激。

这是我的后端的简化:

MySqlDataAdapter dataAdapter = new MySqlDataAdapter(sqlRequestString, this.dbConnection);
MySqlCommandBuilder commandBuilder = new MySqlCommandBuilder(dataAdapter);
DataTable table = new DataTable();
table.Locale = System.Globalization.CultureInfo.InvariantCulture;
dataAdapter.Fill(table);
bindingSource.DataSource = table;

如果我摆脱BindingSource,如何将DataTable直接连接到DataGridView,以便正确填充ComboBoxCheckbox列?< / p>

更新

这应该是我尝试初始化DataGridView的完整概述:

private void InitializeComponent()
{

/* ... */

this.dataGridView1.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
    this.DataGridViewColumn_Section,
    this.DataGridViewColumn_Indent,
    this.DataGridViewColumn_Content,
    this.DataGridViewColumn_Summary,
    this.DataGridViewColumn_Role,
    this.DataGridViewColumn_Author,
    this.DataGridViewColumn_Updated});
    this.dataGridView1.Name = "dataGridView1";
    this.dataGridView1.DataSourceChanged += new System.EventHandler(this.dataGridView1_DataSourceChanged);
    this.dataGridView1.CellEnter += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_CellEnter);
    this.dataGridView1.CellLeave += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_CellLeave);
    this.dataGridView1.ColumnAdded += new System.Windows.Forms.DataGridViewColumnEventHandler(this.dataGridView1_ColumnAdded);
    this.dataGridView1.SelectionChanged += new System.EventHandler(this.dataGridView1_SelectionChanged);
    this.dataGridView1.Leave += new System.EventHandler(this.dataGridView1_Leave);
    // 
    // DataGridViewColumn_Section
    // 
    this.DataGridViewColumn_Section.HeaderText = "Section";
    this.DataGridViewColumn_Section.Name = "DataGridViewColumn_Section";
    // 
    // DataGridViewColumn_Indent
    // 
    this.DataGridViewColumn_Indent.HeaderText = "Indent";
    this.DataGridViewColumn_Indent.Name = "DataGridViewColumn_Indent";
    // 
    // DataGridViewColumn_Content
    // 
    this.DataGridViewColumn_Content.HeaderText = "Content";
    this.DataGridViewColumn_Content.MinimumWidth = 100;
    this.DataGridViewColumn_Content.Name = "DataGridViewColumn_Content";
    // 
    // DataGridViewColumn_Summary
    // 
    this.DataGridViewColumn_Summary.HeaderText = "Summary";
    this.DataGridViewColumn_Summary.Name = "DataGridViewColumn_Summary";
    // 
    // DataGridViewColumn_Role
    // 
    this.DataGridViewColumn_Role.HeaderText = "Minimum Signoff";
    this.DataGridViewColumn_Role.Name = "DataGridViewColumn_Role";
    // 
    // DataGridViewColumn_Author
    // 
    this.DataGridViewColumn_Author.HeaderText = "Author";
    this.DataGridViewColumn_Author.Name = "DataGridViewColumn_Author";
    this.DataGridViewColumn_Author.ReadOnly = true;
    // 
    // DataGridViewColumn_Updated
    // 
    this.DataGridViewColumn_Updated.HeaderText = "Updated";
    this.DataGridViewColumn_Updated.Name = "DataGridViewColumn_Updated";
    this.DataGridViewColumn_Updated.ReadOnly = true;

/* ... */

}

public MyWinform()
{
    InitializeComponent();

    // Initialize DataGridView DataTable
    this.dgvDataTable = new DataTable();

    // Initialize DataGridView column indexes
    this.idxSection = dataGridView1.Columns["DataGridViewColumn_Section"].Index;
    this.idxIndent = dataGridView1.Columns["DataGridViewColumn_Indent"].Index;
    this.idxContent = dataGridView1.Columns["DataGridViewColumn_Content"].Index;
    this.idxSummary = dataGridView1.Columns["DataGridViewColumn_Summary"].Index;
    this.idxRole = dataGridView1.Columns["DataGridViewColumn_Role"].Index;
    this.idxAuthor = dataGridView1.Columns["DataGridViewColumn_Author"].Index;
    this.idxLastUpdate = dataGridView1.Columns["DataGridViewColumn_Updated"].Index;
}

private void MyWinform_Load(object sender, EventArgs e)
{
    DataGridView dgv = this.dataGridView1;
    DataGridViewComboBoxColumn comboCol;

    // Load System Menu
    SystemMenu.Load(this.Handle);

    // Insert selection prompt
    ProcTemplateRecord selectProcPrompt = new ProcTemplateRecord();
    selectProcPrompt.PrimaryKey = 0;
    selectProcPrompt.ProcName = "Select from the list...";
    this.procList.Insert(0, selectProcPrompt);

    // Add new procedure prompt
    ProcTemplateRecord newProcPrompt = new ProcTemplateRecord();
    newProcPrompt.PrimaryKey = -1;
    newProcPrompt.ProcName = "Start a new Safe Job Procedure";
    this.procList.Add(newProcPrompt);

    // Finish initializing the ComboBox dropdown list
    this.comboBox1.DataSource = this.procList;
    this.comboBox1.DisplayMember = "ProcName";
    this.comboBox1.ValueMember = "PrimaryKey";

    // Finish initializing DataGridView and bind to BindingSource
    this.dataGridView1.AutoGenerateColumns = false;

/*
    // Finish initializing the DataGridView ComboBox columns...
    comboCol = (DataGridViewComboBoxColumn)dgv.Columns[this.idxSection];
    comboCol.DataSource = Enum.GetValues(typeof(SectionType));
    comboCol.ValueType = typeof(SectionType);
    comboCol.DropDownWidth = ComboBoxMaxLabelWidth(comboCol);

    comboCol = (DataGridViewComboBoxColumn)dgv.Columns[this.idxRole];
    comboCol.DataSource = Enum.GetValues(typeof(RoleType));
    comboCol.ValueType = typeof(RoleType);
    comboCol.DropDownWidth = ComboBoxMaxLabelWidth(comboCol);

    this.dataGridView1.DataSource = this.dgvDataTable;
*/
    this.RefreshDataGridViewColumnWidths();

    // Setup post-initialization DataGridViewEvent handlers
    this.dataGridView1.CellValueChanged += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_CellValueChanged);
    this.dataGridView1.CurrentCellDirtyStateChanged += new System.EventHandler(this.dataGridView1_CurrentCellDirtyStateChanged);
}

private void dataGridView1_DataSourceChanged(object sender, EventArgs e)
{
    this.RefreshDataGridViewColumnWidths();
}

private void dataGridView1_CellEnter(object sender, DataGridViewCellEventArgs e)
{
    DataGridView dgv = (DataGridView)sender;

    this.RefreshButtons();

    if (e.ColumnIndex == this.idxSection)
    {
        this.label_dgvToolTip.Visible = false;
    }
    else if (e.ColumnIndex == this.idxIndent)
    {
        this.label_dgvToolTip.Visible = false;
    }
    else if (e.ColumnIndex == this.idxContent)
    {
        this.label_dgvToolTip.Visible = false;
    }
    else if (e.ColumnIndex == this.idxSummary)
    {
        this.label_dgvToolTip.Visible = false;
    }
    else if (e.ColumnIndex == this.idxRole)
    {
        this.label_dgvToolTip.Visible = false;
    }
    else if (e.ColumnIndex == this.idxAuthor)
    {
        this.label_dgvToolTip.Visible = false;
        this.label_dgvToolTip.Text = "Author column values are read only.";
        this.label_dgvToolTip.Visible = true;
    }
    else if (e.ColumnIndex == this.idxLastUpdate)
    {
        this.label_dgvToolTip.Visible = false;
        this.label_dgvToolTip.Text = "Updated column values are read only.";
        this.label_dgvToolTip.Visible = true;
    }
    else
    {
        this.label_dgvToolTip.Visible = false;
    }

    this.idxActiveColumn = e.ColumnIndex;
    this.idxActiveRow = e.RowIndex;
}

private void dataGridView1_CellLeave(object sender, DataGridViewCellEventArgs e)
{
    this.label_dgvToolTip.Visible = false;
    this.RefreshButtons();
}

private void dataGridView1_ColumnAdded(object sender, DataGridViewColumnEventArgs e)
{
    DataGridView dgv = this.dataGridView1;

    if ((e.Column.DataPropertyName == "PageSection") &&
        (e.Column.CellType != typeof(DataGridViewComboBoxCell)))
    {
        var cbo = GetComboBoxColumn(e.Column);
        cbo.DataSource = Enum.GetValues(typeof(SectionType));
        cbo.ValueType = typeof(SectionType);
        dgv.Columns.Remove(e.Column);
        dgv.Columns.Add(cbo);
    }
    else if ((e.Column.DataPropertyName == "UserRole") &&
        (e.Column.CellType != typeof(DataGridViewComboBoxCell)))
    {
        var cbo = GetComboBoxColumn(e.Column);
        cbo.DataSource = Enum.GetValues(typeof(RoleType));
        cbo.ValueType = typeof(RoleType);
        dgv.Columns.Remove(e.Column);
        dgv.Columns.Add(cbo);
    }
}

private void dataGridView1_SelectionChanged(object sender, EventArgs e)
{
    this.RefreshButtons();
}

private void dataGridView1_Leave(object sender, EventArgs e)
{
    DataGridView dgv = this.dataGridView1;

    if (dgv.SelectedCells.Count == 0)
    {
        this.idxActiveColumn = -1;
        this.idxActiveRow = -1;
    }
}

private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
    DataGridView dgv = (DataGridView)sender;
    DataGridViewComboBoxCell sectionCell = (DataGridViewComboBoxCell)dgv.Rows[e.RowIndex].Cells[this.idxSection];
    DataGridViewTextBoxCell indentCell = (DataGridViewTextBoxCell)dgv.Rows[e.RowIndex].Cells[this.idxIndent];
    DataGridViewComboBoxCell roleCell = (DataGridViewComboBoxCell)dgv.Rows[e.RowIndex].Cells[this.idxRole];
    Int32 colIndex = e.ColumnIndex;

    try
    {
        if (colIndex == this.idxIndent)
        {
            int number;
            string cellValue = indentCell.Value.ToString();
            bool isNumeric = int.TryParse(cellValue, out number);

            if (!isNumeric)
            {
                cellValue = cellValue.Substring(0, cellValue.Length - 1);
                indentCell.Value = cellValue;
            }
        }

        // Column resizing code goes last
        this.RefreshDataGridViewColumnWidths();

        this.dgvIsDirty = true;
    }
    catch (Exception ex)
    {
        throw new Exception("Failed to refresh DataGridView on cell change.", ex);
    }
}

private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
    DataGridView dgv = (DataGridView)sender;

    try
    {
        if (dgv.IsCurrentCellDirty)
        {
            // This fires the cell value changed handler below
            dgv.CommitEdit(DataGridViewDataErrorContexts.Commit);
            this.RefreshDataGridViewColumnWidths();
        }
    }
    catch (Exception ex)
    {
        throw new Exception("Failed to commit edit of DataGridView cell.", ex);
    }
}

这是我用来更新DataGridView控件的代码:

// Load the data from the database into the DataGridView
this.dbif.GetProcedure(this.procList.ElementAt(selectedIndex).PrimaryKey, ref this.dgvDataTable);

DataRow[] rows = this.dgvDataTable.Select();
//Object dgvDataSource = dgv.DataSource;
//dgv.DataSource = null;

foreach (DataRow dataRow in rows)
{
    DataGridViewRow dgvRow = new DataGridViewRow();
    dgvRow.CreateCells(dgv);
    dgvRow.Cells[idxSection].Value = dataRow.Field<string>(0);
    dgvRow.Cells[idxIndent].Value = dataRow.Field<byte>(1);
    dgvRow.Cells[idxContent].Value = dataRow.Field<string>(3);
    dgvRow.Cells[idxSummary].Value = dataRow.Field<UInt32>(4) != 0;
    dgvRow.Cells[idxRole].Value = dataRow.Field<string>(5);
    dgvRow.Cells[idxAuthor].Value = dataRow.Field<string>(6) + dataRow.Field<string>(7);
    dgvRow.Cells[idxLastUpdate].Value = dataRow.Field<DateTime>(8).ToString();
    dgv.Rows.Add(dgvRow);
}

//dgv.DataSource = dgvDataSource;

这就是我的枚举的定义方式:

public enum SectionType
{
    ESJP_SECTION_HEADER = 1,        // start with 1 for database compatibility
    ESJP_SECTION_FOOTER,
    ESJP_SECTION_BODY
}

public enum RoleType
{
    ESJP_ROLE_NONE = 1,             // start with 1 for database compatibility
    ESJP_ROLE_TEST_ENG,
    ESJP_ROLE_FEATURE_LEAD,
    ESJP_ROLE_TEAM_LEAD
}

1 个答案:

答案 0 :(得分:1)

有许多问题/改进。关于修复所有内容的数据有太多未知数,但这里显示的一些技术可能有所帮助。

1。手动填充DGV

你不应该这样做。只需将DataTable设置为DataSource即可使用大多数列。

2。表达式

您有两个用于填充dgv的表达式:

dgvRow.Cells[idxSummary].Value = dataRow.Field<UInt32>(4) != 0;
dgvRow.Cells[idxAuthor].Value = dataRow.Field<string>(6) + dataRow.Field<string>(7);

这让我相信dgv是ReadOnly。否则你会遇到麻烦。例如Summary:如果用户取消选中该列,则可以将该值设置为0,但如果他们检查了该怎么办?你怎么知道要设置什么值?

缩进因为Byte似乎也很奇怪 - 几乎就像是一个布尔值。

3。连击

在上一个问题中,dgv是从List<Class>填充的。使用 作为`DataSource,Enum运行良好,因为2个属性属于该类型。使用枚举,以下工作:

cbo.ValueType = typeof(RoleType);

问题的第1版,第2版或第3版一样,使用DataTable的可能性较小,因为没有db / Datatable类型的{{1} }或SectionType。在其他情况中有翻译 - 显示用户&#34; ESJP_SECTION_HEADER&#34;但将RoleType存储在2中,最终存储在数据库中 - 小DataTable对列表将起作用。不同的数据模型意味着对DGV cbo采用不同的方法。

现在看起来像是文本列(我已经问了3次)。如果是这样,你真的只需要将选择限制在枚举名称中。在IDE中,粘贴NameValue属性的文本:

enter image description here

或者,您可以在代码中执行此操作:

Items

<强>的AutoGenerateColumns

当设置DGV的数据源时,默认情况下它会自动为每个DTC列创建一个DGV列,这在大多数情况下效果很好。有时您需要进行一些小调整,例如隐藏private string[] secList = {"ESJP_SECTION_HEADER","ESJP_SECTION_FOOTER", "ESJP_SECTION_BODY"}; ... ((DataGridViewComboBoxColumn)dgv1.Columns["PageSection"]).Items.AddRange(secList); 列,或将TextColumn更改为CBOColumn。 Id中的代码进行这些更改而不是手动布置列可以很好地工作。

但是由于存在相当多的此类更改,并且由于您已经在IDE中布置了列,因此您希望确保在代码中的某处将ColumnAddedEvent设置为false。否则它会添加更多列。

设置

您在DGV设计师中可能会或可能不会做的事情:

  • 以您希望的顺序添加列,但请确保将AutoGenerateColumns分配给SQL查询中使用的名称。将作者留空。
    • DataPropertyName这样的表达式列意味着更改查询或在DGV中进行一些格式化。为此,请将 First Last 名称列添加到DGV以及“作者”列。让前两个看不见。下面的代码显示了格式。 (确保在部件后出现复合列(作者)。)。
    • 通常情况下,我会尝试在SQL中执行此操作:Author,但如果您不想弄乱该查询,则可以在DGV事件中进行连接。
  • 请务必将SELECT (First + Last) AS AuthorPage列的名称添加到Role集合。

然后,其余的很简单:

Items

格式化事件:

private DataTable dtF;
...
string SQL = "SELECT PageSection, Indent, Content, SummaryId, "
        + "UserRole, AuthorFirstN, AuthorLastN, LastUpdated FROM FellPage";

using (var dbCon = new MySqlConnection(MySQLConnStr))
using (var cmd = new MySqlCommand(SQL, dbCon))
{
    dbCon.Open();
    dtF = new DataTable();
    dtF.Load(cmd.ExecuteReader());
}
// IMPORTANT!!!
dgv1.AutoGenerateColumns = false;
dgv1.DataSource = dtF;

结果:

enter image description here

关闭private void dgv1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) { if (dgv1.Rows[e.RowIndex].IsNewRow) return; if (e.ColumnIndex == 7) // ie "Author" { e.Value = dgv1.Rows[e.RowIndex].Cells[6].Value.ToString() + ", " + dgv1.Rows[e.RowIndex].Cells[5].Value.ToString(); e.FormattingApplied = true; } } 非常重要。默认情况下,dgv将为源中的所有内容添加列。由于您添加了它们,因此在代码中将其设置为false(没有IDE属性)。

由于AutoGenerateColumnsSummary被定义为检查列,它将非零转换为true。 我不知道你将如何编辑任何Indent 值。 这应该是一个文本列,以便他们可以输入一个值,如果允许的话(那个col也可以只读?)。

我的查询和你的查询并不复杂,当然有一些细节我/我们不知道哪些已被省略。但是肯定会有更少的旋转和代码来使它工作......不管这是什么。

绑定到SummaryId,当用户编辑任何内容时,更改会流向基础DataTable(使用各种DataTable事件检查其工作)。 Validating依次跟踪每一行的状态 - 新增,更改,删除 - 以便稍后您可以:

DataTable

这将返回自上一个var changes = dtF.GetChanges(); 以来已更改的所有行。