如何在DataGridView控件中实现级联ComboBox?

用户名

我需要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] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何在Objectify中实现级联删除?

来自分类Dev

如何在Delphi控件中实现接口

来自分类Dev

如何在WPF中为控件实现收缩动画

来自分类Dev

如何在PHP和AJAX中实现级联下拉菜单?

来自分类Dev

如何在mysql中查看级联?

来自分类Dev

如何在PostgreSQL中执行级联舍入?

来自分类Dev

如何在级联中设置UIPickerView

来自分类Dev

如何在Linux中杀死级联?

来自分类Dev

级联如何在双向关系中工作

来自分类Dev

如何在excel中创建级联列表?

来自分类Dev

如何在DataGridView显示对象的值中具有自定义控件?

来自分类Dev

如何建议在DataGridView中追加ComboBox?

来自分类Dev

如何在Java中实现自定义选项卡控件

来自分类Dev

如何在ASP.NET中实现N级嵌套的Repeater控件?

来自分类Dev

如何在Java中实现自定义选项卡控件

来自分类Dev

如何在ASP.NET中实现N级嵌套的Repeater控件?

来自分类Dev

如何在mysql中添加删除级联选项?

来自分类Dev

如何在Laravel4中级联软删除?

来自分类Dev

如何在数据库中存储级联类别

来自分类Dev

如何在黑莓级联中拆分字符串

来自分类Dev

如何在Javascript / HTML中创建级联下拉列表?

来自分类Dev

如何在Fluent NHibernate中设置默认级联

来自分类Dev

如何在实体框架中设置OnDelete级联

来自分类Dev

如何在C#中处理级联删除异常

来自分类Dev

如何在angularJS2中进行级联?

来自分类Dev

如何在顺序级联 Observables 中捕获错误?

来自分类Dev

如果控件名称在Datagridview中,则禁用控件

来自分类Dev

如何从ComboBox控件获取ToggleButton

来自分类Dev

如何在面板控件中动态创建控件