![](/img/trans.png)
[英]Clearing a previous selection and selecting a row in datagridview in winforms
[英]Winforms Datagridview row selection isssue
我正在做一個功能,就像我的UserControl
中有一個DataGridView
一樣,它托管在 Base Form 中。 這個Grid
有 3 列,例如 ID、Name、Age,這個 Age 列是一個ComboBox
控件。 當應用程序啟動時, Grid
會填充來自數據庫表 Student 的數據。 選擇模式是單行。 起初,它會顯示 ID 和名稱,但 Age 列是空的,用戶可以單擊該列 - 這是一個ComboBox
控件。
假設用戶填充的數據來自數據庫,並且只有 10 行。 用戶單擊第 4 行並嘗試從ComboBox
指定一個值。 好吧,沒關系。 現在看到當前行是第 4 行並且該行被選中。 然后用戶嘗試點擊第 6 行。 但它突然選擇了第一行 [0 索引]。 我點擊了第 6 行,但它沒有選擇第 6 行。 相反,會自動選擇第一行。
dgv_RowEnter
是我們單擊行時觸發的第一個事件。 但是在我不知道的dgv_RowEnter
事件之前調用了另一個事件。
那是什么活動?
首先,我選擇一行並從ComboBox
[Age Column] 中選擇一個數字,然后,當我單擊任何其他行時 - 當時它正在選擇 [highlighting] 第一行 [0th rowindex]。
如何防止這種情況?
在你的帖子中,你問:
dgv_RowEnter 是我們單擊行時觸發的第一個事件。 但是在我不知道的 dgv_RowEnter 事件之前調用了另一個事件。 那是什么活動?
您提出的問題表明DataGridView
的默認行為沒有按照您想要的順序提供您想要的事件。 將數據綁定與DataSource
屬性結合使用是使 DGV 開箱即用地表現得體的最快方法,這將是我的第一個建議。 但聽起來您好像直接與 DGV 進行交互,這意味着您是一位高級用戶,希望在 DGV 發送的事件中“處於領先地位”。 在SelectedRow
、 SelectedColumn
和SelectedCell
作為事件發出之前攔截它們的方法是制作一個CustomDataGridView : DataGridView
並分別覆蓋SetSelectedRowCore
、 SetSelectedColumnCore
和SetSelectedCellCore
方法。
您將需要更改 Form.Designer.cs 文件中的兩行:
// private System.Windows.Forms.DataGridView dataGridView1;
private CustomDataGridView dataGridView1;
和:
private void InitializeComponent()
{
// this.dataGridView1 = new System.Windows.Forms.DataGridView();
this.dataGridView1 = new CustomDataGridView();
.
.
.
}
下面顯示的控制台輸出表明,當這些狀態發生時,所示的自定義類現在是“第一響應者”。
class CustomDataGridView : DataGridView
{
protected override void SetSelectedRowCore(
int rowIndex,
bool selected)
{
Debug.WriteLine($"{MethodBase.GetCurrentMethod().Name} Row {rowIndex}");
base.SetSelectedRowCore(rowIndex, selected);
}
protected override void SetSelectedCellCore(
int columnIndex,
int rowIndex,
bool selected)
{
Debug.WriteLine($"{MethodBase.GetCurrentMethod().Name} Column {columnIndex} Row {rowIndex}");
base.SetSelectedCellCore(columnIndex, rowIndex, selected);
}
protected override void SetSelectedColumnCore(
int columnIndex,
bool selected)
{
Debug.WriteLine($"{MethodBase.GetCurrentMethod().Name} Column {columnIndex}");
base.SetSelectedColumnCore(columnIndex, selected);
}
protected override bool SetCurrentCellAddressCore(
int columnIndex,
int rowIndex,
bool setAnchorCellAddress,
bool validateCurrentCell,
bool throughMouseClick)
{
Debug.WriteLine($"{MethodBase.GetCurrentMethod().Name} Column {columnIndex} Row {rowIndex}");
return base.SetCurrentCellAddressCore(
columnIndex,
rowIndex,
setAnchorCellAddress,
validateCurrentCell,
throughMouseClick);
}
}
您的帖子描述了行選擇問題並以問題結尾:“如何防止這種情況? ”這是一種方法。 如果將 DataGridView 的DataSource
屬性分配給將通知記錄集更改的源,則DataGridView
效果最好並且更易於管理。 如圖所示,此特定示例將使用BindingList
創建DataGridView
。 請自行嘗試代碼,看看您的選擇問題現在是否已修復:
假設這是您的Student
課程:
class Student
{
static int _id = 1;
public int ID { get; } = _id++;
public string Name { get; set; }
public string Age { get; set; } = "Select";
}
然后,您可以(例如)將DataSource
設置為BindingList<Student>
。 現在DataGridView
將完成選擇事物的工作,而無需大驚小怪。 只需像這樣初始化dataGridView1
:
private void initDataGridView()
{
dataGridView1.DataSource = Students;
// Add one or more Student records to autogenerate columns
foreach (var student in MockDatabaseQuery())
{
Students.Add(student);
}
// Swap autogenerated column for DataGridViewComboboxColumn.
int index = dataGridView1.Columns[nameof(Student.Age)].Index;
dataGridView1.Columns.RemoveAt(index);
var comboBoxColumn =
new DataGridViewComboBoxColumn
{
Name = nameof(Student.Age),
DataPropertyName = nameof(Student.Age),
DataSource = new string[]{
"Select","15 and Under","16","17","18","19","20","21","22","23","24","25 and Older"
}
};
dataGridView1.Columns.Insert(index, comboBoxColumn);
// Format columns
dataGridView1.Columns[nameof(Student.ID)].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
dataGridView1.Columns[nameof(Student.Name)].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
dataGridView1.Columns[nameof(Student.Age)].Width = 160;
// Prevents leaving the row in Edit state When the combo box changes
dataGridView1.CurrentCellDirtyStateChanged += onCurrentCellDirtyStateChanged;
}
BindingList<Student> Students { get; } = new BindingList<Student>();
試驗台
此代碼使用模擬查詢返回Student
記錄列表。 這樣我們就可以專注於您所詢問的選擇問題,而無需在線實際數據庫。
private IEnumerable<Student> MockDatabaseQuery()
{
return new List<Student>
{
new Student { Name = "Katherine Johnson" },
new Student { Name = "Dorothy Vaughan" },
new Student { Name = "Mary Jackson" },
new Student { Name = "Ken Thompson" },
new Student { Name = "Alan Turing" },
new Student { Name = "Ada Lovelace" },
new Student { Name = "Linus Torvalds" },
new Student { Name = "Mark Zuckerberg" },
new Student { Name = "Bill Gates" },
new Student { Name = "Larry Page" },
};
}
當 ComboBox 更改值時,此處理程序結束行編輯。
private void onCurrentCellDirtyStateChanged(object sender, EventArgs e)
{
switch (dataGridView1.Columns[dataGridView1.CurrentCell.ColumnIndex].Name)
{
case nameof(Student.Age):
dataGridView1.EndEdit();
break;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.