Привязка данных WinForms DataGridView с ComboBoxColum

2

Я пытаюсь использовать DataGridView с бизнес-объектом. Здесь упрощенный сценарий: - вызвать объект "Рецепт", и он имеет BindingList из нескольких объектов Ингредиента в Рецепте - У меня также есть "база данных", которая является BindingList всех доступных объектов Ingredient

Я хотел бы отобразить DataGridView всех ингредиентов в рецепте и позволить пользователю выбирать новые ингредиенты из поля со списком в поле "Имя".

Когда я пытаюсь настроить это так, как мне кажется, имя Ингредиенты в Рецепте не отображается, хотя я могу выбрать из IngredientDB, а выбор нового Ингридиента обновляет список в Рецепте.

Как мне правильно отобразить имя?

Вот что я до сих пор:

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


}
  • 0
    это работает для меня, я получаю выпадающий список с рисом, цельной пшеничной мукой и маслом в качестве значений.
  • 0
    Да, но в выпадающем списке не отображаются названия существующих ингредиентов - воды и джина.
Теги:
winforms
data-binding

2 ответа

1
Лучший ответ

У вас нет ингредиентов "Вода" или "Джин" в вашем списке "componentientDB". Источник данных DataGridView установлен в список ингредиентов. Когда форма загружается, она автоматически создает 3 столбца (Имя, Описание, Сумма) на основе свойств вашего бизнес-объекта (т.е. Ингредиент). Затем строки добавляются в соответствии с вашим списком ингредиентов ( "Вода" и "Джин" ). Таким образом, чистый результат состоит в том, что у вас есть 3 столбца и 2 строки в DataGridView, и это выглядит так:

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

Однако вы вставляете DataGridViewComboBoxColumn в столбец 0 (т.е. первый столбец) и что там проблема.

Источник данных DataGridVidwComboBoxColumn установлен в ваш BBSSource, который, в свою очередь, настроен на "componentientDB". "Ингредиент ДБ" содержит только записи для "риса", "цельной пшеничной муки" и "сливочного масла". Когда столбец отображается для первой строки, он ищет Ингредиент с именем == "Вода" в своем источнике данных ( "componentDB" ). Этот "ингредиентDB" не содержит Ингредиент для воды и обычно поднимает DataGridViewDataErrorEvent. Однако вы сами обрабатываете событие и ничего не делаете с ним. Поэтому в ComboBox ничего нет. То же самое происходит с ингредиентом "Джин". Компонент "Джин" не может быть найден внутри вашего "ингредиентаDB", поэтому его нельзя выбрать.

Чтобы устранить проблему, вам нужно добавить "Water" и "Gin" в ваш "component.gd":

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

Проблема в том, что DataGridViewComboBoxColumn не редактируется, поэтому он будет принимать значение только из своего источника данных.

Итак, у вас есть 2 варианта:

  • Простое решение: убедитесь, что все возможные ингредиенты для рецепта установлены до создания рецепта и выбора их из DataGridViewComboBoxColumn.

  • Более сложное решение: когда пользователь редактирует один ингредиент рецепта, обработайте это событие и измените стиль базового Control от DataGridViewComboBoxColumn до DropDown. Когда пользователь закончит редактирование, проверьте, не ввел ли он новое значение (а не в источник данных) и эффективно добавит его в источник данных (создайте новый компонент). Вы можете найти информацию о реализации этого подхода здесь.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню