我有一个DataGridView
列,其中有一个ComboBox
列,当下拉列表显示时,我必须更新每个ComboBox的可能值。我还必须使ComboBox
能够具有自定义类型的值。键入新值时,应将其添加到可能值列表中。问题是我得到了无限多的DataError
事件触发器(错误消息框),我知道如何通过仅更改DataGridViewDataErrorEventArgs
对象中的字段来处理它,但是我知道这不是正确的方法处理它:
private void DataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e)
{
e.Cancel = false;
}
如果我以错误的方式执行此操作,则从下拉列表中选择一个值或键入新值后,将触发CellValueChanged
,但关闭的ComboBox
不会显示当前值,但会显示已经存在的值(列表中的第一个)。
在下面的代码中,Form子类为Form2
,初始值存储在str
字段中,并且调用UpdatePossibleValues
方法来更新所有{{ 1}}位于数据网格视图中唯一的列ComboBox
:
DataGridViewComboBoxColumn
屏幕截图:
答案 0 :(得分:1)
要将项目动态添加到DataGridViewComboBoxColumn
:
EditingControlShowing
并获得DataGridViewComboBoxEditingControl
DropDownStyle
设置为DropDown
Validating
编辑控件事件,并确保仅将事件处理程序附加一次。Text
:
注意:
如果有多个组合框,请确保对组合框使用不同的数据源,并在验证事件中更新相应的数据源。
如果使用匿名方法处理事件,请确保对捕获的变量有正确的假设。为简单起见,您可以使用常规方法处理事件。
示例
以下示例显示了一个DataGridView
具有两个DataGridViewComboBoxColumn
,对于第二个Form
,您可以通过在运行时在组合框中键入来添加新值。
要运行该示例,请创建一个DataGridView
并将一个private List<String> comboSource1;
private List<String> comboSource2;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
comboSource1 = new List<string> { "A", "B" };
comboSource2 = new List<string> { "1", "2" };
var dt = new DataTable();
dt.Columns.Add("C1");
dt.Columns.Add("C2");
dt.Rows.Add("A", "1");
dt.Rows.Add("B", "2");
var c1 = new DataGridViewComboBoxColumn();
c1.Name = "C1";
c1.DataPropertyName = "C1";
c1.DataSource = comboSource1;
var c2 = new DataGridViewComboBoxColumn();
c2.Name = "C2";
c2.DataPropertyName = "C2";
c2.DataSource = comboSource2;
dataGridView1.Columns.AddRange(c1, c2);
this.dataGridView1.DataSource = dt;
dataGridView1.EditingControlShowing += dataGridView1_EditingControlShowing;
dataGridView1.EditMode = DataGridViewEditMode.EditOnEnter;
}
放置在新窗体上,然后将以下代码复制并粘贴到该窗体中:
private void dataGridView1_EditingControlShowing(object sender,
DataGridViewEditingControlShowingEventArgs e)
{
var dataGridView = sender as DataGridView;
if (dataGridView?.CurrentCell?.ColumnIndex != 1) return;
var comboBox = e.Control as DataGridViewComboBoxEditingControl;
if (comboBox == null) return;
comboBox.DropDownStyle = ComboBoxStyle.DropDown;
if (!true.Equals(comboBox.Tag))
{
comboBox.Tag = true;
comboBox.Validating += (obj, args) =>
{
var column = (DataGridViewComboBoxColumn)dataGridView.CurrentCell.OwningColumn;
var list = comboBox.DataSource as List<string>;
if (list == null) return;
var txt = comboBox.Text;
if (!list.Contains(txt))
{
list.Add(txt);
column.DataSource = null;
column.DataSource = list;
}
dataGridView.CurrentCell.Value = txt;
dataGridView.NotifyCurrentCellDirty(true);
};
}
}
public class Main extends Application {
private boolean fileChooserOpen = false;
@Override
public void start(Stage stage) throws Exception{
/* EventHandler to be used with multiple buttons */
EventHandler<KeyEvent> enterWithFileChooser = event -> {
if (!fileChooserOpen && event.getCode() == KeyCode.ENTER && event.getSource() instanceof Button) {
Button src = (Button) event.getSource();
src.fire();
fileChooserOpen = true;
}else {
fileChooserOpen = false;
}
event.consume();
};
EventHandler<KeyEvent> enter = event -> {
if (event.getCode() == KeyCode.ENTER && event.getSource() instanceof Button) {
Button src = (Button) event.getSource();
src.fire();
}
event.consume();
};
/* Create a new button */
Button b1 = new Button("Save");
Button b2 = new Button("Print");
/* Add event handlers */
b1.setOnKeyReleased(enterWithFileChooser);
b2.setOnKeyReleased(enter);
/* Called by .fire method of save button */
b1.setOnAction(event -> {
/* Create the save dialog box */
FileChooser saveDialog = new FileChooser();
saveDialog.setTitle("Save");
/* Get file */
File f = saveDialog.showSaveDialog(stage);
/* ... do stuff with file ... */
});
/* Called by .fire method of print button */
b2.setOnAction(event -> System.out.println("Pressed"));
Scene scene = new Scene(new HBox(b1, b2));
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) { launch(args); }
}