【问题标题】:WinForms Databinding DataGridView with ComboBoxColum带有 ComboBoxColum 的 WinForms 数据绑定 DataGridView
【发布时间】:2009-07-20 21:02:06
【问题描述】:

我正在尝试将 DataGridView 与业务对象一起使用。这是一个简化的场景: - 调用对象“Recipe”,它有一个 BindingList,其中包含 Recipe 中的一些成分对象 - 我还有一个“数据库”,它是所有可用成分对象的 BindingList

我想显示配方中所有成分的 DataGridView,并允许用户从名称字段的组合框中选择新成分。

当我尝试按照我认为应该的方式进行设置时,配方中的成分名称不会显示,尽管我可以从成分数据库中进行选择,并且选择新成分确实会更新配方中的列表。

如何让名称正确显示?

这是我目前所拥有的:

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;

namespace WindowsFormsApplication1 {
    public class Ingredient {

        private String name;
        public String Name {
            get { return name; }
            set { name = value; }
        }

        private string description;
        public String Description {
            get { return description; }
            set { description = value; }
        }

        private int amount;
        public int Amount {
            get { return amount; }
            set { amount = value; }
        }

        public Ingredient(String n, String d, int a) {
            Name = n;
            Description = d;
            Amount = a;
        }

        public Ingredient() { }

    }

    public class Data {
        BindingList<Ingredient> ingredientDB = null;
        public BindingList<Ingredient> IngredientDB {
            get { return ingredientDB; }
        }

        public Data() {
            ingredientDB = new BindingList<Ingredient>();
            ingredientDB.Add(new Ingredient("rice", "a grain", 2));
            ingredientDB.Add(new Ingredient("whole wheat flour", "for baking", 1));
            ingredientDB.Add(new Ingredient("butter", "fatty", 3));
        }

    }

    public class Recipe : INotifyPropertyChanged {

        public String Name {
            get;
            set;
        }

        BindingList<Ingredient> ingredients = null;
        public BindingList<Ingredient> Ingredients {
            get { return ingredients; }
            set {
                ingredients = value;
                NotifyPropertyChanged("Ingredients");
            }
        }

        public Recipe() {
            Ingredients = new BindingList<Ingredient>();
            Ingredients.Add(new Ingredient("Water", "Wet", 2));
            Ingredients.Add(new Ingredient("Gin", "Yummy", 2));
        }


        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String info) {
            if (PropertyChanged != null) {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

        #endregion
    }

    public class myForm : Form {

        private DataGridView dgv;
        private BindingSource recipeBS;
        private BindingSource dataBS;
        public myForm() {
            this.Height = 200;
            this.Width = 400;
            Recipe myRecipe = new Recipe();
            Data myData = new Data();
            recipeBS = new BindingSource(myRecipe, null);
            dataBS = new BindingSource(myData, "IngredientDB");
            dgv = new DataGridView();
            dgv.Width = 400;
            dgv.DataError += new
            DataGridViewDataErrorEventHandler(DataGridView1_DataError);
            dgv.DataSource = myRecipe.Ingredients;
            // dgv.Columns.Remove("Name");
            DataGridViewComboBoxColumn comboboxColumn = new DataGridViewComboBoxColumn();
            comboboxColumn.DataPropertyName = "Name";
            comboboxColumn.HeaderText = "Name";
            comboboxColumn.DataSource = dataBS;
            comboboxColumn.DisplayMember = "Name";
            comboboxColumn.ValueMember = "Name";
            dgv.Columns.Insert(0, comboboxColumn);
            this.Controls.Add(dgv);
        }
        private void DataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs anError) { }

        [STAThreadAttribute()]
        static void Main() {
            Application.EnableVisualStyles();
            Application.Run(new myForm());
        }
    }


}

【问题讨论】:

  • 它对我有用,我得到一个下拉菜单,其中包含大米、全麦面粉和黄油作为值。
  • 是的,但组合框不显示现有成分的名称 - 水和杜松子酒。

标签: c# winforms data-binding


【解决方案1】:

您的“ingredientDB”列表中没有水或杜松子酒成分。 DataGridView 的数据源设置为成分列表。加载表单时,它会根据您的业务对象(即成分)的属性自动创建 3 列(名称、描述、金额)。然后根据您的成分列表(“水”和“杜松子酒”)添加行。所以最终结果是您的 DataGridView 中有 3 列和 2 行,它看起来像这样:

Name  | Description | Amount
Water | Wet         | 2
Gin   | Yummy       | 2

但是,您将 DataGridViewComboBoxColumn 插入到第 0 列(即第一列)中,这就是问题所在。

DataGridVidwComboBoxColumn 的数据源设置为您的 dataBs BindingSource,而后者又设置为“ingredientDB”。 “ingredientDB”仅包含“大米”、“全麦面粉”和“黄油”的条目。当第一行显示该列时,它会在其数据源(“ingredientDB”)中查找名称 == “水”的成分。此“ingredientDB”不包含水的成分,通常会引发 DataGridViewDataErrorEvent。但是,您正在自己处理事件,而不是对它做任何事情。因此,ComboBox 中没有任何内容。 “杜松子酒”成分也会发生同样的事情。在您的“ingredientDB”中找不到“Gin”成分,因此无法选择。

要解决此问题,您需要将“Water”和“Gin”都添加到“ingredientDB”中:

public Data()
{
    ingredientDB = new BindingList<Ingredient>();
    ingredientDB.Add(new Ingredient("rice", "a grain", 2));
    ingredientDB.Add(new Ingredient("whole wheat flour", "for baking", 1));
    ingredientDB.Add(new Ingredient("butter", "fatty", 3));
    ingredientDB.Add(new Ingredient("Water", "Wet", 2));
    ingredientDB.Add(new Ingredient("Gin", "Yummy", 2));
}

【讨论】:

    【解决方案2】:

    问题是DataGridViewComboBoxColumn 是不可编辑的,所以它只接受来自其数据源的值。

    所以,你有两个选择:

    1. 简单的解决方案:确保在创建配方并从 DataGridViewComboBoxColumn 中选择之前设置配方的所有可能成分。

    2. 更难的解决方案:当用户编辑配方的一种成分时,处理此事件并将DataGridViewComboBoxColumn的底层Control的样式更改为DropDown。用户完成编辑后,检查他是否输入了新值(不在数据源中)并有效地将其添加到数据源中(创建新成分)。您可以找到有关实施此方法的信息here。

    【讨论】:

      猜你喜欢
      • 2019-07-21
      • 2012-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-26
      • 2011-09-15
      • 2010-09-12
      • 1970-01-01
      相关资源
      最近更新 更多