绑定DataGridView:当我在其外部单击时,DataGridViewComboBoxColumn将更改为其他值

时间:2015-06-19 14:38:15

标签: c# winforms datagridview datagridviewcombobox databound

我希望有人可以帮助我解决一个让我完全陷入困境的晦涩难题。

我希望设置一个DataGridView,它允许用户从DataGridViewComboBoxColumn中选择一个选项,并使用用户在ComboBox中选择的对象来更新DataGridView的数据源对象。 / p>

[我希望DataGridViewComboBoxColumn在下拉列表中显示多个属性,因此我使用DataTable作为DataGridViewComboBoxColumn数据源。换句话说,我希望他们看到一个描述,它是连接在一起的其他属性的组合。]

我的代码有效,但是当我在ComboBox单元格外部单击时,该值会自动设置(它将被设置回BindingList中的第一个项目)。我无法坚持用户选择的价值。最终,错误的对象实例被分配给DataGridView的dataSource。

我会张贴一张照片,但我没有足够的代表。

所以我的问题是,当我在单元格外部单击时,为什么DataGridViewComboBoxColumn会切换到其数据源中的第一项(DataTable)。如何让它在单元格中保留我选择的选项。我绝对是BAFFLED。

我希望可以将这么多代码发布到StackOverflow网站,而不会让每个人烦恼。我试图创建适当的通用示例,以帮助任何其他灵魂尝试找出如何使用DataGridViewComboBoxColumn选择并将对象分配给另一个对象的属性。所以希望这对其他人有用。如果有人需要解决这类问题,我也试图让它重新创建起来相对容易。

我尝试了各种各样的方法,包括使用List作为DataGridViewComboBoxColumn的数据源,使用CurrentCellDirtyStateChanged事件做事 - 一切都无济于事。

这是我的两个班级:

    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属性。使用从ComboBox中选择的值更新Car对象IS INDEED。我认为这只是一个显示问题,DataGridViewComboBoxColumn只是没有填充正确的值。仍然感到困惑。

2 个答案:

答案 0 :(得分:0)

感谢那些发表评论的人。我最终找到了答案。

答案是我只需为我的“CarPartChoice”类定义一个重写的“ToString()”方法(即用于通过单击ComboBoxColumn来提供要查找的项目的类)。我想当我把控件移开时,用一个很好的字符串格式化我的单元格时遇到了麻烦。

因此,对于将来想要这样做的任何人,这里有一个完整的示例,说明如何使用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; }
    }

答案 1 :(得分:0)

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