我需要ComboBoxes
在几DataGridView
秒钟内实现级联。作为概念验证,我整理了以下代码。3列(“客户”,“国家/地区”,“城市”)在选择“国家/地区”时,应填充城市,但不起作用。
有没有更好的方法来实现这一目标并解决我做错的事情?
public partial class Form1 : Form
{
private List<Customer> customers;
private List<Country> countries;
private List<City> cities;
private ComboBox cboCountry;
private ComboBox cboCity;
public Form1()
{
InitializeComponent();
countries = GetCountries();
customers = GetCustomers();
SetupDataGridView();
}
private List<Customer> GetCustomers()
{
var customerList = new List<Customer>
{
new Customer {Id=1,Name = "Jo",Surname = "Smith"},
new Customer {Id=2,Name = "Mary",Surname = "Glog"},
new Customer {Id=3,Name = "Mark",Surname = "Bloggs"}
};
return customerList;
}
private List<Country> GetCountries()
{
var countryList = new List<Country>
{
new Country {Id=1,Name = "England"},
new Country {Id=2,Name = "Spain"},
new Country {Id=3,Name = "Germany"}
};
return countryList;
}
private List<City> GetCities(string countryName)
{
var cityList = new List<City>();
if (countryName == "England") cityList.Add(new City { Id = 1, Name = "London" });
if (countryName == "Spain") cityList.Add(new City { Id = 2, Name = "Madrid" });
if (countryName == "Germany") cityList.Add(new City { Id = 3, Name = "Berlin" });
return cityList;
}
private void SetupDataGridView()
{
dataGridView1.CellLeave += dataGridView1_CellLeave;
dataGridView1.EditingControlShowing += dataGridView1_EditingControlShowing;
DataGridViewTextBoxColumn colCustomer = new DataGridViewTextBoxColumn();
colCustomer.Name = "colCustomer";
colCustomer.HeaderText = "CustomerName";
DataGridViewComboBoxColumn colCountry = new DataGridViewComboBoxColumn();
colCountry.Name = "colCountry";
colCountry.HeaderText = "Country";
DataGridViewComboBoxColumn colCity = new DataGridViewComboBoxColumn();
colCity.Name = "colCity";
colCity.HeaderText = "City";
dataGridView1.Columns.Add(colCustomer);
dataGridView1.Columns.Add(colCountry);
dataGridView1.Columns.Add(colCity);
//Databind gridview columns
((DataGridViewComboBoxColumn)dataGridView1.Columns["colCountry"]).DisplayMember = "Name";
((DataGridViewComboBoxColumn)dataGridView1.Columns["colCountry"]).ValueMember = "Id";
((DataGridViewComboBoxColumn)dataGridView1.Columns["colCountry"]).DataSource = countries;
((DataGridViewComboBoxColumn)dataGridView1.Columns["colCity"]).DisplayMember = "Name";
((DataGridViewComboBoxColumn)dataGridView1.Columns["colCity"]).ValueMember = "Id";
((DataGridViewComboBoxColumn)dataGridView1.Columns["colCity"]).DataSource = cities;
foreach (Customer cust in customers)
{
dataGridView1.Rows.Add(cust.Name + " " + cust.Surname);
}
}
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
//register a event to filter displaying value of items column.
if (dataGridView1.CurrentRow != null && dataGridView1.CurrentCell.ColumnIndex == 2)
{
cboCity = e.Control as ComboBox;
if (cboCity != null)
{
cboCity.DropDown += cboCity_DropDown;
}
}
//Register SelectedValueChanged event and reset item comboBox to default if category changes
if (dataGridView1.CurrentRow != null && dataGridView1.CurrentCell.ColumnIndex == 1)
{
cboCountry = e.Control as ComboBox;
if (cboCountry != null)
{
cboCountry.SelectedValueChanged += cboCountry_SelectedValueChanged;
}
}
}
void cboCountry_SelectedValueChanged(object sender, EventArgs e)
{
//If category value changed then reset item to default.
dataGridView1.CurrentRow.Cells[2].Value = 0;
}
void cboCity_DropDown(object sender, EventArgs e)
{
string countryName = dataGridView1.CurrentRow.Cells[1].Value.ToString();
List<City> cities = new List<City>();
cities = GetCities(countryName);
cboCity.DataSource = cities;
cboCity.DisplayMember = "Name";
cboCity.ValueMember = "Id";
}
private void dataGridView1_CellLeave(object sender, DataGridViewCellEventArgs e)
{
if (cboCity != null) cboCity.DropDown -= cboCity_DropDown;
if (cboCountry != null)
{
cboCountry.SelectedValueChanged -= cboCountry_SelectedValueChanged;
}
}
}
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
}
public class City
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
}
如上述评论所述,DataGridViewComboBox
相关问题可能会变得棘手(基本上是在一个已经非常复杂的控件中添加了另一个控件);而您的目标确实使该配置达到了极限。DataGridView
是一种旨在减轻中等复杂性,数据相关问题的管理的控件;您可以通过其最具定义性的功能(例如,基于文本框的单元格,在验证单元格之后触发的事件等)来获得最佳性能。因此,包括组合框(或复选框或等效框)单元是可以的,只要您不使其性能达到极限即可。为了获得最佳效果(协调不同的组合框),我建议您不要依赖于DataGridView
控制(或至少不是针对组合框协调部分),只要实现有问题,最终结果就不会像它可能获得的那样可靠,并且在任何情况下,总体结构都比由a产生的结构更严格不依赖DGV的方法(即单个ComboBox
控件)。
无论如何,我对此实现方式感到好奇(主要是在初步测试中看到了很多问题之后),并决定编写此代码来回答您的问题。
private void Form1_Load(object sender, EventArgs e)
{
dataGridView1.EditingControlShowing +=new DataGridViewEditingControlShowingEventHandler(dataGridView1_EditingControlShowing);
DataGridViewComboBoxColumn curCol1 = new DataGridViewComboBoxColumn();
List<string> source1 = new List<string>() { "val1", "val2", "val3" };
curCol1.DataSource = source1;
DataGridViewComboBoxColumn curCol2 = new DataGridViewComboBoxColumn();
dataGridView1.Columns.Add(curCol1);
dataGridView1.Columns.Add(curCol2);
for (int i = 0; i <= 5; i++)
{
dataGridView1.Rows.Add();
dataGridView1[0, i].Value = source1[0];
changeSourceCol2((string)dataGridView1[0, i].Value, (DataGridViewComboBoxCell)dataGridView1[1, i]);
}
}
private void changeSourceCol2(string col1Val, DataGridViewComboBoxCell cellToChange)
{
if (col1Val != null)
{
List<string> source2 = new List<string>() { col1Val + "1", col1Val + "2", col1Val + "3" };
cellToChange.DataSource = source2;
cellToChange.Value = source2[0];
}
}
private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
if (dataGridView1.CurrentRow != null)
{
ComboBox col1Combo = e.Control as ComboBox;
if (col1Combo != null)
{
if (dataGridView1.CurrentCell.ColumnIndex == 0)
{
col1Combo.SelectedIndexChanged += col1Combo_SelectedIndexChanged;
}
}
}
}
private void col1Combo_SelectedIndexChanged(object sender, EventArgs e)
{
if (dataGridView1.CurrentCell.ColumnIndex == 0)
{
dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
changeSourceCol2(dataGridView1.CurrentCell.Value.ToString(), (DataGridViewComboBoxCell)dataGridView1[1, dataGridView1.CurrentCell.RowIndex]);
}
}
这段代码可以很好地工作,但有一个限制:更改第一个组合框的索引时,该值不会立即提交(因此,第二个组合框无法更新)。经过一些测试,我确认了建议的配置(即,仅编写了dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
在填充第二个组合框源之前,可以提供最佳性能)。尽管如此,请注意,此代码在此方面并不完美:从第二个选择开始,它开始工作(每次在第一个选择新项目时,都会自动更新第二个组合框);我不确定这个的确切原因,但是,正如我所说,我尝试过的任何其他选择都会带来更差的性能。由于前面提到的评论(实际上,甚至不建议这样做),并且感觉到您必须做一部分工作,因此我在这方面的工作还没有太多。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句