【发布时间】:2014-01-07 20:35:41
【问题描述】:
我需要在几个DataGridViews 中实现级联ComboBoxes。作为概念证明,我将下面的代码放在一起。 3 列(Customer、Country、City) 选择Country 时,City 应填充,但它不起作用。
有没有更好的方法来实现这一点并解决我做错的事情?
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; }
}
}
【问题讨论】:
-
你的代码不是太小,你打算做的也不是直截了当的。在任何情况下,请注意您将 ValueMember 设置为“Id”(因此 Value 属性返回“Id”),但随后您检查国家名称,因此根本不会发生城市人口。只需将所有 ValueMember 更改为“Name”,城市人口应该可以工作(但恐怕这还不是全部)。
-
@varocarbas 感谢您抽出宝贵的时间。很难平衡要放多少代码,我也很快把一些东西放在一起,因为我不想问“你如何在没有任何代码的情况下做到这一点!”。我知道并不简单,正在寻找样本但找不到任何实际工作的样本。我收到错误“datagridcomboboxcell.value 无效”。你知道我可以下载并查看它是如何工作的任何示例吗?
-
datagridview 的问题在于它是一个相当复杂的控件,有很多事件被系统地调用。组合框类型的单元格接受一种非常特定的格式。您提到的错误表明在某些时候缺少正确的格式。这很难跟踪。我建议你一步一步做事,并确认每个中间步骤都很好。如果你没有得到任何帮助,我可能会在一段时间内编写一些小代码。
标签: c# winforms datagridview cascadingdropdown