Связывание объектов DataGridView C#
У меня есть DataGridView и список объектов, которые я хотел бы показать.
Объекты это:
public class Entity
{
public int ID { get; set; }
}
public class Travel: Entity
{
public Service Service { get; set; }
public City Source { get; set; }
public City Destiny { get; set; }
public decimal Price { get; set; }
}
public class Service: Entity
{
public string Name { get; set; }
}
public class City: Entity
{
public string Name { get; set; } // Max 50 chars
}
В своей форме я связываю список объектов путешествия следующим образом:
List<Travel> travels = logic.GetAllTravels();
DgvRecorridos.DataSource = travels;
И я получаю следующее:
Я хотел бы получить название службы, исходный город и город судьбы.
Заранее спасибо.
4 ответа
Вместо того, чтобы делать следующие коды ниже:
List<Travel> travels = logic.GetAllTravels();
DgvRecorridos.DataSource = travels;
Сделай это:
List<Travel> travels = logic.GetAllTravels();
BindingSource bs = new BindingSource();
bs.DataSource = travels;
DgvRecorridos.AutoGenerateColumn = false;
DgvRecorridos.DataSource = bs;
Затем добавьте столбцы вручную:
DataGridViewColumn col1 = new DataGridViewTextBoxColumn();
col1.DataPropertyName = "Service.Name";
col1.HeaderText = "Service Name";
dataGridView1.Columns.Add(col1);
DataGridViewColumn col2 = new DataGridViewTextBoxColumn();
col2.DataPropertyName = "City.Name";
col2.HeaderText = "City Name";
dataGridView1.Columns.Add(col2);
DataGridViewColumn col3 = new DataGridViewTextBoxColumn();
col3.DataPropertyName = "City.Name";
col3.HeaderText = "Destiny Name";
dataGridView1.Columns.Add(col3);
DataGridViewColumn col4 = new DataGridViewTextBoxColumn();
col4.DataPropertyName = "Price";
col4.HeaderText = "Price";
dataGridView1.Columns.Add(col4);
Затем добавьте обработчик события форматирования ячейки для DataGridView:
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (dataGridView1.Rows[e.RowIndex].DataBoundItem != null &&
dataGridView1.Columns[e.ColumnIndex].DataPropertyName.Contains("."))
{
e.Value = BindProperty(dataGridView1.Rows[e.RowIndex].DataBoundItem,
dataGridView1.Columns[e.ColumnIndex].DataPropertyName);
}
}
private string BindProperty(object property, string propertyName)
{
string retValue = "";
if (propertyName.Contains("."))
{
PropertyInfo[] arrayProperties;
string leftPropertyName;
leftPropertyName = propertyName.Substring(0, propertyName.IndexOf("."));
arrayProperties = property.GetType().GetProperties();
foreach (PropertyInfo propertyInfo in arrayProperties)
{
if (propertyInfo.Name == leftPropertyName)
{
retValue = BindProperty(propertyInfo.GetValue(property, null),
propertyName.Substring(propertyName.IndexOf(".") + 1));
break;
}
}
}
else
{
Type propertyType;
PropertyInfo propertyInfo;
propertyType = property.GetType();
propertyInfo = propertyType.GetProperty(propertyName);
retValue = propertyInfo.GetValue(property, null).ToString();
}
return retValue;
}
Для полного руководства по форматированию ячеек, просмотрите здесь в блоге Антонио Белло, это - то, где я получил идею. ^_^ Я также задавал здесь на SO тот же вопрос два дня назад, и получил такие же ответы, как и вы, и я знаю, что это не то, что вы хотите сделать тоже. Надеюсь, это поможет вам.
List<Travel> travels = logic.GetAllTravels();
var _bind = from a in travels
select new
{
Servicename = a.Service.Name,
SourceName = a.Source.Name,
DestinyName = a.Destiny.Name,
Price = a.Price
};
DgvRecorridos.DataSource = _bind;
или же
List<Travel> travels = logic.GetAllTravels();
var _bind = travels.Select(a => new
{
Servicename = a.Service.Name,
SourceName = a.Source.Name,
DestinyName = a.Destiny.Name,
Price = a.Price
});
DgvRecorridos.DataSource = _bind;
Весь этот код в методах CellFormatting и BindProperty кажется чрезмерным. Я имею в виду, что что-то должно в основном делать это, но я думаю, что это уже сделано. Я реализую INotifyPropertyChanged в объекте, который я хочу привязать к строке сетки, и помещаю эти объекты в BindingList. BindingList напрямую используется в качестве источника данных для сетки.
Этот подход означает немного больше ввода в базовый класс сущностей, который вы отображаете в строку сетки, но я думаю, что это намного экономит в других местах. Для реализации INotifyPropertyChanged в вашем классе:
public class Entity: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public Entity()
{
Selected = false;
}
private bool _selected;
public bool Selected
{
get
{
return _selected;
}
set
{
if (_selected != value)
{
_selected = value;
OnPropertyChanged(nameof(Selected));
}
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Затем поместите столбец в свою сетку и присвойте ему значение DataPropertyName "Выбрано", чтобы оно соответствовало имени свойства в Entity, которое должно появиться в этом столбце. Очевидно, добавьте любые свойства, которые вы хотите в вашей сетке, соответствующие свойствам объекта. Ключ должен быть уверен, что реализован установщик свойств с помощью вызова PropertyChanged.
Это дает вам двустороннюю связь между сеткой и списком объектов.
Мое личное мнение: даже это слишком много кода. Я постоянно пишу такие вещи, которые делают очевидное: взять свойство по имени и сопоставить его с чем-то другим, которое знает это имя (например, столбец сетки в этом примере). Это просто за пределами моего понимания, почему эти вещи не просто автоматически подключаются. Список и сетка должны иметь достаточно смысла, чтобы самостоятельно составить эту базовую схему. ноль строк кода. Хорошо, одна строка кода. Grid.Datasource = Список. Так вот как я это делаю. Я хотел бы знать меньше строк кода, способ сделать это.
Ваш дизайн такой странный. У меня есть другой подход, чтобы переопределить ToString()
Метод ваших классов (Служба и Город), как это:
public class Service: Entity
{
public string Name { get; set; }
public override string ToString(){
return Name;
}
}
public class City: Entity
{
public string Name { get; set; } // Max 50 chars
public override string ToString(){
return Name;
}
}
И это работает хорошо. Опять же, ваш дизайн немного странно ^_^