Domanda

I have User and UserGroup tables in my database:

enter image description here

I generated EF model (Database first) and DataSource for User following this tutorial http://msdn.microsoft.com/en-us/data/jj682076.aspx

On my form I created BindingSource (bsUsers) and bound DataGridView to it, so it shows Ids and Usernames.

Here is how I load data on form startup:

_myDbContext = new MyDbContext();

_myDbContext.Users.Load();

bsUsers.DataSource = _myDbContext.Users.Local.ToBindingList();

But now I want to display GroupName in the same DataGridView. What is the best way to do that?

I tried just to specify UserGroup.GroupName in column DataPropertyName but it doesn't work, cells remain empty.

The only solution I found so far is creating a new unbound column and filling it manually:

foreach (var item in (IList<User>)bsUsers.DataSource) 
{
    dgw.Rows[i].Cells["GroupName"].Value = item.UserGroup.Name; 
}

But it doesn't look like a good approach. For example after changing group of a user I will need to update it again, or when adding new records.

È stato utile?

Soluzione

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:

enter image description here

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

Altri suggerimenti

You can simply override ToString() in your model. Even though I strongly suggest to use ViewModel.

public class UserGroup{

public int Id { get; set; }
public string GroupName { get; set; }

public override string ToString() {

    return GroupName;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top