![](/img/trans.png)
[英]ComboBox added programmatically to DataGridView cell not expanding on cell click
[英]ComboBox added programmatically to DataGridView doesn't open until after the cell loses focus and then is clicked on again
在 C# WinForms 項目中,我從DataTable
填充 DGV。 當用戶單擊其中一列的單元格時,我需要填充ComboBox
並單擊打開它。
但是,只有當相關單元格失去焦點(單擊表單上的其他位置)然后重新獲得焦點(再次單擊該單元格)時,CBO 才會打開 - 並且僅在單擊 CBO 的向下箭頭時才會打開,而不是在 CBO 的文本是點擊。 單擊 CBO 的文本時,我還需要打開 CBO。
private void dgvCategories_Click(Object sender, DataGridViewCellEventArgs e)
{
try
{
// Prevent code from executing if user clicks on a cell that already has a CBO
if (e.ColumnIndex == 5 && !(dgvCategories.Rows[e.RowIndex].Cells[e.ColumnIndex].GetType().Name == "DataGridViewComboBoxCell"))
{
// Get fields to build New Value query
List<string> lsNewValuesResult = new List<string>();
string strCategory = dtCategories.Rows[e.RowIndex][1].ToString();
string strCompanyName = cboSelectCompany.Text;
string strQueryGetNewValuesValidationInfo = "SELECT validationdb, validationtable, validationfield, validationfield2, validationvalue2" +
" FROM masterfiles.categories" +
" WHERE category = @category";
// Pass validation info query to db and return list of New Values
db getListOfNewValues = new db();
lsNewValuesResult = getListOfNewValues.GetNewValuesList(strQueryGetNewValuesValidationInfo, strCategory, strCompanyName);
// Create CBO object
DataGridViewComboBoxCell cboNewValueList = new DataGridViewComboBoxCell();
//Populate the combobox with the list of New Values
foreach (string strListItem in lsNewValuesResult) cboNewValueList.Items.Add(strListItem);
// Bind the CBO to the DGV
dgvCategories[e.ColumnIndex, e.RowIndex] = cboNewValueList;
var editingControl = dgvCategories.EditingControl as DataGridViewComboBoxEditingControl;
if (editingControl != null) editingControl.DroppedDown = true;
}
}
catch (Exception ex)
{
Console.WriteLine("dgvCategories_Click Exception: " + ex.Message);
}
}
DataGridViewEditMode
設置為EditOnEnter
並且DataGrieViewSelectionMode
設置為CellSelect
。
最后的兩行來自 SO 問題,“ DataGridViewComboBoxColumn - 必須單擊單元格兩次才能顯示組合框”
我不確定還能嘗試什么...
如果您考慮使用CellBeginEdit
事件來解決您的問題,那么您可以使用下一種方法:
private void dgvCategories_CellBeginEdit(Object sender, DataGridViewCellCancelEventArgs e)
{
if (e.ColumnIndex == 5)
{
if (dgvCategories.Rows[e.RowIndex].Cells[e.ColumnIndex].GetType().Name != "DataGridViewComboBoxCell")
{
// Bind combobox to dgv and than bind new values datasource to combobox
DataGridViewComboBoxCell cboNewValueList = new DataGridViewComboBoxCell();
// Get fields to build New Value query
List<string> lsNewValuesResult = getCboValues();
//Populate the combobox with the list of New Values
foreach (string strListItem in lsNewValuesResult)
{
cboNewValueList.Items.Add(strListItem);
}
// Store current cell value into ComboBox cell. It is for convenience.
cboNewValueList.Value = dgvCategories[e.ColumnIndex, e.RowIndex].Value;
// Cancel current BeginEdit event because it occurs on the cell of type TextBox.
// Later we'll launch another BeginEdit event on cell of type ComboBox.
e.Cancel = true;
// BeginInvoke is needed because:
// 1. there is a known problem with DataGridView:
// - https://stackoverflow.com/questions/5114668/why-is-my-bound-datagridview-throwing-an-operation-not-valid-because-it-results
// - https://stackoverflow.com/questions/26522927/how-to-evade-reentrant-call-to-setcurrentcelladdresscore/26527759#26527759
// 2. current cell has type TextBox, but we want to change its type to
// ComboBox and then begin editing ComboBox.
BeginInvoke(new Action(
() =>
{
// Change type of current cell to ComboBox.
dgvCategories[e.ColumnIndex, e.RowIndex] = cboNewValueList;
// Begin editing of the ComboBox cell.
dgvCategories.BeginEdit(true);
// Here (after BeginEdit) the type of the cell is ComboBox.
// Automatically drop down ComboBox cell.
if (dgvCategories.EditingControl != null)
((DataGridViewComboBoxEditingControl)dgvCategories.EditingControl).DroppedDown = true;
}));
}
else
{
// If current cell is already of type ComboBox then we simply drop down it.
BeginInvoke(new Action(
() =>
{
if (dgvCategories.EditingControl != null)
((DataGridViewComboBoxEditingControl)dgvCategories.EditingControl).DroppedDown = true;
}));
}
}
}
以下是對這種方法的解釋:
CellBeginEdit
事件發生在TextBox
類型的單元格上,我們取消此事件,然后:
ComboBox
;ComboBox
單元啟動CellBeginEdit
事件;ComboBox
電池;CellBeginEdit
事件發生在ComboBox
類型的單元格上,我們只需將其下拉;BeginInvoke
更改當前單元格的類型,然后開始編輯,因為:
使用CellBeginEdit
的方法還有下一個好處:它可以更改單元格類型,或者用戶使用鼠標或鍵盤導航到單元格。
另一種方法是使用CellStateChanged
事件:
private void dgvCategories_CellStateChanged(object sender, DataGridViewCellStateChangedEventArgs e)
{
if (e.StateChanged == DataGridViewElementStates.Selected)
{
int col = e.Cell.ColumnIndex;
int row = e.Cell.RowIndex;
if (col == 5)
{
if (dgvCategories.Rows[row].Cells[col].GetType().Name != "DataGridViewComboBoxCell")
{
// Bind combobox to dgv and than bind new values datasource to combobox
DataGridViewComboBoxCell cboNewValueList = new DataGridViewComboBoxCell();
// Get fields to build New Value query
List<string> lsNewValuesResult = getCboValues();
//Populate the combobox with the list of New Values
foreach (string strListItem in lsNewValuesResult)
{
cboNewValueList.Items.Add(strListItem);
}
//
cboNewValueList.Value = dgvCategories[col, row].Value;
dgvCategories[col, row] = cboNewValueList;
// To drop down current cell we must call BeginInvoke,
// because in the CellStateChanged event handler
// dgvCategories.EditingControl is null.
BeginInvoke(new Action(
() =>
{
if (dgvCategories.EditingControl != null)
((DataGridViewComboBoxEditingControl) dgvCategories.EditingControl).DroppedDown = true;
}));
}
else
{
// If current cell is already ComboBox we simply drop it down.
BeginInvoke(new Action(
() =>
{
if (dgvCategories.EditingControl != null)
((DataGridViewComboBoxEditingControl)dgvCategories.EditingControl).DroppedDown = true;
}));
}
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.