Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to retrieve GroupName data annotation from ModelMetadata

The DisplayAttribute in System.ComponentModel.DataAnnotations has a GroupName property, which allows you to logically group fields together in a UI control (e.g. a property grid in WPF/WinForms).

I am trying to access this metadata in an ASP.NET MVC3 application, essentially to create a property grid. If my model looks like this:

public class Customer
{
    [ReadOnly]
    public int Id { get;set; }

    [Display(Name = "Name", Description = "Customer's name", GroupName = "Basic")]
    [Required(ErrorMessage = "Please enter the customer's name")]
    [StringLength(255)]
    public string Name { get;set; }

    [Display(Name = "Email", Description = "Customer's primary email address", GroupName = "Basic")]
    [Required]
    [StringLength(255)]
    [DataType(DataType.Email)]
    public string EmailAddress { get;set; }

    [Display(Name = "Last Order", Description = "The date when the customer last placed an order", GroupName = "Status")]
    public DateTime LastOrderPlaced { get;set; }

    [Display(Name = "Locked", Description = "Whether the customer account is locked", GroupName = "Status")]
    public bool IsLocked { get;set; }
}

and my view looks like this:

@model Customer

<div class="edit-customer">
    @foreach (var property in ViewData.ModelMetadata.Properties.Where(p => !p.IsReadOnly).OrderBy(p => p.Order))
    {
        <div class="editor-row">
            @Html.DevExpress().Label(settings =>
                {
                    settings.AssociatedControlName = property.PropertyName;
                    settings.Text = property.DisplayName;
                    settings.ToolTip = property.Description;
                }).GetHtml()
            <span class="editor-field">
                @Html.DevExpress().TextBox(settings =>
                    {
                        settings.Name = property.PropertyName;
                        settings.Properties.NullText = property.Watermark;
                        settings.Width = 200;
                        settings.Properties.ValidationSettings.RequiredField.IsRequired = property.IsRequired;
                        settings.ShowModelErrors = true;
                    }).Bind(ViewData[property.PropertyName]).GetHtml()
            </span>
        </div>
    }
</div>

then the form is laid out very nicely based on the metadata, with labels, tooltips, watermarks etc all pulled out of the model's metadata; but, I would like to be able to group the items together, for instance in a <fieldset> per group. Does anyone know how to get the GroupName out of the metadata, short of writing an extension method for ModelMetadata?

like image 963
David Keaveny Avatar asked Feb 21 '12 23:02

David Keaveny


2 Answers

GroupName is not parsed by the DataAnnotationsModelMetadataProvider. So there's no way to get it right off the ModelMetadata object, even with an extension method.

You could implement your own provider that extends the existing one to add support for GroupName, which Brad Wilson explains in his blog.

You could also write your own attribute instead of using Display(GroupName = ) and implement the IMetadataAware interface to add the groupname to ModelMetadata.AdditionalValues.

like image 186
bhamlin Avatar answered Sep 18 '22 11:09

bhamlin


You can also use this Extension Method:

public static class ModelMetadataExtensions
{
  public static T GetPropertyAttribute<T>(this ModelMetadata instance)
    where T : Attribute
  {
    var result = instance.ContainerType
      .GetProperty(instance.PropertyName)
      .GetCustomAttributes(typeof(T), false)
      .Select(a => a as T)
      .FirstOrDefault(a => a != null);

    return result;
  } 
}

Then

var display= this.ViewData.ModelMetadata
  .GetPropertyAttribute<DisplayAttribute>();

var groupName = display.Groupname;
like image 38
Erik Philips Avatar answered Sep 19 '22 11:09

Erik Philips