Found a bit better approach: http://www.developer-corner.com/blog/2007/07/19/datagridview-how-to-bind-nested-objects/ (works only for read-only, not for editing in DataGridView)
public static class BindingHelper
{
// Recursive method that returns value of property (using Reflection)
// Example: string groupName = GetPropertyValue(user, "UserGroup.GroupName");
public static object GetPropertyValue(object property, string propertyName)
{
object retValue = "";
if (propertyName.Contains("."))
{
string leftPropertyName = propertyName.Substring(0, propertyName.IndexOf("."));
PropertyInfo propertyInfo = property.GetType().GetProperties().FirstOrDefault(p => p.Name == leftPropertyName);
if (propertyInfo != null)
{
retValue = GetPropertyValue(
propertyInfo.GetValue(property, null),
propertyName.Substring(propertyName.IndexOf(".") + 1));
}
}
else
{
Type propertyType = property.GetType();
PropertyInfo propertyInfo = propertyType.GetProperty(propertyName);
retValue = propertyInfo.GetValue(property, null);
}
return retValue;
}
}
In the column I have DataPropertyName
set to UserGroup.GroupName
:
And in CellFormatting
event I call this method for all columns "binded" to nested properties (that have .
in DataPropertyName
) to display their values:
private void dgwUsers_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
var dgw = (DataGridView) sender;
DataGridViewColumn column = dgw.Columns[e.ColumnIndex];
DataGridViewRow row = dgw.Rows[e.RowIndex];
if (column.DataPropertyName.Contains("."))
{
e.Value = BindingHelper.GetPropertyValue(row.DataBoundItem, column.DataPropertyName);
}
}
Also I have ComboBox binded to the same BindingSource which allows to change group of currently selected user. To update value in the corresponding DataGridView cell I do this in SelectedIndexChanged
event of the ComboBox:
private void cbbUserGroup_SelectedIndexChanged(object sender, EventArgs e)
{
Validate();
dgwUsers.UpdateCellValue(dgwUsers.Columns["GroupName"].Index, dgwUsers.CurrentRow.Index);
}