【问题标题】:Bound DataGridView: the DataGridViewComboBoxColumn changes to a different value when I click outside it绑定的 DataGridView:当我在外部单击时,DataGridViewComboBoxColumn 更改为不同的值
【发布时间】: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) =&gt; { };
  • 嗨 TaW:它发生在我从下拉列表中选择并单击另一个控件之后。换句话说,我从下拉列表中选择了我的选项,这导致该字段被填充并且下拉列表消失。我选择的选项保留在控件中,直到我单击下拉框外的任意位置。只要我这样做,控件中的值就会自动更改。
  • 嗨,Fabio,添加一个空的 DataError 事件处理程序,没有任何区别,也没有捕获数据错误。

标签: c# winforms datagridview datagridviewcombobox databound


【解决方案1】:

感谢那些离开 cmets 的人。我终于找到了答案。

我的答案是简单地为我的“CarPartChoice”类(即用于通过单击 ComboBoxColumn 来提供要查找的项目的类)定义一个覆盖的“ToString()”方法。我猜当我将控制权从单元格移开时,它在用一个漂亮的字符串格式化我的单元格时遇到了问题。

因此,对于将来想要这样做的任何人,这里有一个完整示例,说明如何使用 datagridview 更新某个类的对象列表,并使用 DataGridViewComboBoxColumn 为用户提供选择对象,并将其选择的对象(他们从下拉列表中选择)填充到列表中(准确地说:在列表中的对象字段中,该对象的类型是用户在下拉菜单)。是的,我知道这是一个非常可怕的句子。

这是完成这项任务的完整代码(我原以为这是人们经常想做的事情)。

向大家致以最诚挚的问候。

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        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.");
            CarPartChoice myWheelChoice3 = new CarPartChoice("Iron", 15, "These are metal wheels.");
            CarPartChoice myWheelChoice4 = new CarPartChoice("Spoked", 15, "This is the fancy classic hubcaps option.");
            CarPartChoice myWheelChoice5 = new CarPartChoice("solid", 13, "This wheels has no spokes or holes.");
            CarPartChoice myWheelChoice6 = new CarPartChoice("SpaceHubCaps", 17, "Newly developed space hubcaps.");

            BindingList<CarPartChoice> tempBLChoice = new BindingList<CarPartChoice>();
            tempBLChoice.Add(myWheelChoice);
            tempBLChoice.Add(myWheelChoice2);
            tempBLChoice.Add(myWheelChoice3);
            tempBLChoice.Add(myWheelChoice4);
            tempBLChoice.Add(myWheelChoice5);
            tempBLChoice.Add(myWheelChoice6);

            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.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;
        }

        void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
        {
            var grid = sender as DataGridView;
            if (grid.IsCurrentCellDirty)
                grid.CommitEdit(DataGridViewDataErrorContexts.Commit);
        }
    }

    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 override string ToString()
        {
            return Name.ToString() + " - " + Value.ToString() + " - " + Comment.ToString();
        }
    }

    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; }
    }

【讨论】:

    【解决方案2】:

    我也有同样的问题,但数据集不同。我试图向组合框添加一个键值对,每次点击外部时,它都会重置为第一个项目。我缺少的是我没有设置组合框的 displayMember 属性。 (如果有其他人遇到同样的问题,希望这会有所帮助)

    【讨论】:

      猜你喜欢
      • 2014-04-06
      • 2021-09-22
      • 1970-01-01
      • 2011-03-21
      • 2013-06-10
      • 2013-01-19
      • 1970-01-01
      • 2010-09-25
      • 1970-01-01
      相关资源
      最近更新 更多