Привязка данных WinForms DataGridView с ComboBoxColum - PullRequest
2 голосов
/ 21 июля 2009

Я пытаюсь использовать DataGridView с бизнес-объектом. Вот упрощенный сценарий: - вызвать объект «Рецепт», и у него есть BindingList нескольких объектов Ingredient в рецепте - У меня также есть «база данных», которая представляет собой 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());
        }
    }


}

Ответы [ 2 ]

1 голос
/ 24 июля 2009

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

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

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

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

Чтобы решить эту проблему, вам нужно добавить «Water» и «Gin» к вашему «componentDB»:

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 голос
/ 21 июля 2009

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...