【发布时间】:2015-09-05 14:23:08
【问题描述】:
我希望有人可以帮助我解决一个让我非常困惑的晦涩问题。
我希望设置一个 DataGridView,它允许用户从 DataGridViewComboBoxColumn 中选择一个选项,并且对于作为 DataGridView 数据源的对象,使用用户在 ComboBox 中选择的对象进行更新。
[NB 我希望 DataGridViewComboBoxColumn 在下拉列表中显示多个属性,因此我使用 DataTable 作为 DataGridViewComboBoxColumn 数据源。换句话说,我希望他们看到一个描述,它是其他属性连接在一起的组合。]
我的代码有效,但是当我在 ComboBox 单元格外部单击时,该值会自动设置(它会设置回 BindingList 中的第一项)。我无法让它坚持用户选择的值。最终错误的对象实例被分配给 DataGridView 的数据源。
我会发一张照片,但我没有足够的代表。
所以我的问题是,为什么当我在单元格外部单击时,DataGridViewComboBoxColumn 会切换到其数据源(DataTable)中的第一项。我怎样才能让它保留我选择的选项,在单元格中。我非常困惑。
我希望可以将这么多代码发布到 StackOverflow 网站上,而不会惹恼所有人。我试图创建适当的通用示例,以帮助任何其他人尝试找出如何使用 DataGridViewComboBoxColumn 选择对象并将其分配给另一个对象的属性。所以希望这对其他人有用。如果有人需要解决此类问题,我还尝试使其相对容易重新创建。
我尝试了各种方法,包括使用 List 作为 DataGridViewComboBoxColumn 的数据源,使用 CurrentCellDirtyStateChanged 事件进行操作 - 均无济于事。
这是我的 2 节课:
public class CarPartChoice
{
public string Name { get; set; }
public int Value { get; set; }
public string Comment {get; set;}
public CarPartChoice(string name, int value, string comment)
{
Name = name;
Value = value;
Comment = comment;
}
}
public class Car
{
public string Manufacturer { get; set; }
public string Model { get; set; }
public CarPartChoice WheelChoice {get; set;}
public Car(string maker, string model, CarPartChoice wheel)
{
Manufacturer = maker;
Model = model;
WheelChoice = wheel;
}
public Car(string maker, string model)
{
Manufacturer = maker;
Model = model;
}
}
public static class GlobalVariables
{
public static BindingList<CarPartChoice> GlobalChoiceList { get; set; }
public static BindingList<Car> GlobalCarsList { get; set; }
}
我正在创建我的 dataGridView:
private void Form1_Load(object sender, EventArgs e)
{
//Setup the wheel choices to be selected from the DataGridViewComboBoxColumn.
CarPartChoice myWheelChoice = new CarPartChoice("Chrome", 19, "This is the chromes wheels option.");
CarPartChoice myWheelChoice2 = new CarPartChoice("HubCaps", 16, "This is the nasty plastic hubcaps option.");
BindingList<CarPartChoice> tempBLChoice = new BindingList<CarPartChoice>();
tempBLChoice.Add(myWheelChoice);
tempBLChoice.Add(myWheelChoice2);
GlobalVariables.GlobalChoiceList = tempBLChoice;
//Setup the cars to populate the datagridview.
Car car1 = new Car("Vauxhall", "Astra");
Car car2 = new Car("Mercedes", "S-class");
BindingList<Car> tempListCars = new BindingList<Car>();
tempListCars.Add(car1);
tempListCars.Add(car2);
GlobalVariables.GlobalCarsList = tempListCars;
dataGridView1.AutoGenerateColumns = false;
dataGridView1.CurrentCellDirtyStateChanged += new EventHandler(dataGridView1_CurrentCellDirtyStateChanged);
// Set up 2 DataGridViewTextBox columns, one to show the manufacturer and the other to show the model.
DataGridViewTextBoxColumn manufacturer_col = new DataGridViewTextBoxColumn();
manufacturer_col.DataPropertyName = "Manufacturer";
manufacturer_col.Name = "Manufacturer";
manufacturer_col.HeaderText = "Manufacturer";
DataGridViewTextBoxColumn model_col = new DataGridViewTextBoxColumn();
model_col.DataPropertyName = "Model";
model_col.Name = "Model";
model_col.HeaderText = "Model";
// Create a DataTable to hold the Wheel options available for the user to choose from. This DT will be the DataSource for the
// ...combobox column
DataTable wheelChoices = new DataTable();
DataColumn choice = new DataColumn("Choice", typeof(CarPartChoice));
DataColumn choiceDescription = new DataColumn("Description", typeof(String));
wheelChoices.Columns.Add(choice);
wheelChoices.Columns.Add(choiceDescription);
foreach (CarPartChoice wheelchoice in GlobalVariables.GlobalChoiceList)
{
wheelChoices.Rows.Add(wheelchoice, wheelchoice.Name + " - " + wheelchoice.Value.ToString() + " - " + wheelchoice.Comment);
}
// Create the Combobox column, populated with the wheel options so that user can pick one.
DataGridViewComboBoxColumn wheelOption_col = new DataGridViewComboBoxColumn();
wheelOption_col.DataPropertyName = "WheelChoice";
wheelOption_col.Name = "WheelChoice";
wheelOption_col.DataSource = wheelChoices;
wheelOption_col.ValueMember = "Choice";
wheelOption_col.DisplayMember = "Description";
wheelOption_col.ValueType = typeof(CarPartChoice);
// Add the columns and set the datasource for the DGV.
dataGridView1.Columns.Add(manufacturer_col);
dataGridView1.Columns.Add(model_col);
dataGridView1.Columns.Add(wheelOption_col);
dataGridView1.DataSource = GlobalVariables.GlobalCarsList;
}
更新: 我尝试使用“BindingSource”对象并将 BindingSource 的数据源设置为 DataTable。那没什么区别。我还尝试让 Car 实现“INotifyPropertyChanged”接口,但没有任何区别。
我注意到的一件事是 datagridview 中的 Car 项目确实更新了其 WheelChoice 属性。 Car 对象确实使用我从 ComboBox 中选择的值进行了更新。我认为这只是一个显示问题,并且 DataGridViewComboBoxColumn 没有填充正确的值。还是一头雾水。
【问题讨论】:
-
这是在单击时总是发生还是仅在下拉菜单仍然显示时发生?
-
解决方法:添加空的
DataError事件处理程序:this.dataGridView1.DataError += (sender, e) => { }; -
嗨 TaW:它发生在我从下拉列表中选择并单击另一个控件之后。换句话说,我从下拉列表中选择了我的选项,这导致该字段被填充并且下拉列表消失。我选择的选项保留在控件中,直到我单击下拉框外的任意位置。只要我这样做,控件中的值就会自动更改。
-
嗨,Fabio,添加一个空的 DataError 事件处理程序,没有任何区别,也没有捕获数据错误。
标签: c# winforms datagridview datagridviewcombobox databound