Я пытаюсь использовать 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());
}
}
}
У вас нет ингредиентов "Вода" или "Джин" в вашем списке "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));
}
Проблема в том, что DataGridViewComboBoxColumn
не редактируется, поэтому он будет принимать значение только из своего источника данных.
Итак, у вас есть 2 варианта:
Простое решение: убедитесь, что все возможные ингредиенты для рецепта установлены до создания рецепта и выбора их из DataGridViewComboBoxColumn
.
Более сложное решение: когда пользователь редактирует один ингредиент рецепта, обработайте это событие и измените стиль базового Control
от DataGridViewComboBoxColumn
до DropDown
. Когда пользователь закончит редактирование, проверьте, не ввел ли он новое значение (а не в источник данных) и эффективно добавит его в источник данных (создайте новый компонент). Вы можете найти информацию о реализации этого подхода здесь.