Search code examples
entity-frameworksilverlight-4.0data-annotationsentity-relationshipwcf-ria-services

Using DataAnnotations (DisplayColumn) in WCF RIA Services


I have created an entity framework 4.0 (DB-First) model, added my partial classes and used DataAnnotations on them to have a perfect UI on the client.

I have some relations between my tables and used DisplayColumn on top my classes. e.g. I have a User class that has [DataColumn("UserName")] attribute on top of the class. And a Message class which has "public User Sender" which has [Include] attribute on top of the property.

Also, I have used .Include("User") in my DomainService to load the User who's related to a message.

But in my datagrid, I see User : (UserID) (UserID=Key property of User entity) instead of UserName that I have specified. I looked in the generated code in my SL project and it correctly decorated my User class with DisplayColumn attribute. But still, I cannot see UserName in my grid.

Any help would be greatly appreciated.
Update: Here's my question in code:

As I have mentioned, Owner, UserName, MessageId, UserId have been defined in my auto-generated model. UserMeta class has nothing special.

[MetadataType(typeof(MessageMeta))]
public partial class Message
{
}  

public class MessageMeta
{
 [Include()]
 [Display(Name = "Belongs to", Order = 4)]
 [Association("Message_User","MessageId","UserId",IsForeignKey =  true)]
 public virtual User Owner { get; set; }
}

[MetadataType(typeof(UserMeta))]
[DisplayColumn("UserName")]
public partial class User
{
}  

In my DomainService:

public IQueryable<Message> GetMessages()
{
    return this.ObjectContext.Messages.Include("Owner");
}

Solution

  • At last, I had to use Reflection. For DataGrid:

    private void OnAutoGenerateColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
        {
            //Need to get an array, but should always just have a single DisplayColumnAttribute
            var atts = e.PropertyType.GetCustomAttributes(typeof(DisplayColumnAttribute),true);
    
            foreach (DisplayColumnAttribute d in atts)
            {
                DataGridTextColumn col = (DataGridTextColumn)e.Column;
    
                //Make sure that we always have the base path
                if(col.Binding.Path.Path!="")
                {
                    col.Binding = new Binding()
                    {
                        Path = new PropertyPath(col.Binding.Path.Path + "." + d.DisplayColumn)
                    };
                }
    
                //Only do the first one, just in case we have more than one in metadata
                break;
            }
    
        } 
    

    And for Telerik RadGridView:

    var column = e.Column as GridViewDataColumn;
    if (column == null)
    {
        return;
    }
    
    // Need to get an array, but should always just have a single DisplayColumnAttribute  
    var atts = column.DataType.GetCustomAttributes(typeof(DisplayColumnAttribute), true);
    
    foreach (DisplayColumnAttribute d in atts)
    {
        // Make sure that we always have the base path
        if (column.DataMemberBinding.Path.Path != "")
        {
            column.DataMemberBinding = new Binding()
            {
                Path = new PropertyPath(column.DataMemberBinding.Path.Path + "." + d.DisplayColumn)
            };
         }
         // Only do the first one, just in case we have more than one in metadata
         break;
     }