Geeks With Blogs
Brian Schroer Don't Call Me Mort!

 

In a prior post, I blogged about creating a custom class inheriting from System.Web.Mvc.DataAnnotationsModelMetadataProvider to provide localized display names for my models.

I was disappointed to find that the MvcContrib grid doesn't use the metadata provider for column names - it just splits "Pascal-case" property names into words (e.g. "FromDate" to "From Date") if a name hasn't been explicitly assigned.

    public string DisplayName
    {
        get
        {
            if (this._doNotSplit)
            {
                return this._displayName;
            }
            return this.SplitPascalCase(this._displayName);
        }
    }

 

…so I had to use the "Named" method to assign my localized column names:

Html.Grid(Model.Items)
    .Attributes(@class => "mvcContribGrid jqStyleAlternateItems", border => "1")
    .HeaderRowAttributes(new Dictionary<string, object> { { "valign", "bottom" } })
    .RowStart(row => "<tr valign=\"top\">")
    .Sort(Model.MvcContribGridSortOptions)
    .Columns(column =>
    {
        column.For(x => x.BarCode)
         .Named(LocalizedResource.BarCode)
            .Action(x => Response.Write(string.Format(barCodeFormat, x.BarCode, x.Id)));
        column.For(x => x.Owner)
            .Named(LocalizedResource.Owner);
        column.For(x => x.Description)
            .Named(LocalizedResource.Description);
        column.For(x => x.RetentionCode)
            .Named(LocalizedResource.RetentionCode);
        column.For(x => x.StatusDescription)
            .Named(LocalizedResource.Status);
        column.For(x => x.LegalHold)
            .Named(LocalizedResource.LegalHold)
            .Action(x => Response.Write((x.LegalHold) ? checkMarkCell : emptyCell));
        column.For(x => x.TaxHold)
            .Named(LocalizedResource.TaxHold)
            .Action(x => Response.Write((x.TaxHold) ? checkMarkCell : emptyCell));
        column.For(x => x.FromDate)
            .Named(LocalizedResource.FromDate)
            .Format(dateFormat)
            .Attributes(data => dateColumnAttributes);
        column.For(x => x.ToDate)
            .Named(LocalizedResource.ToDate)
            .Format(dateFormat)
            .Attributes(data => dateColumnAttributes);
        column.For(x => x.EligibleRetirementDate)
            .Named(LocalizedResource.EligibleRetirementDate)
            .Format(dateFormat)
            .Attributes(data => dateColumnAttributes);
    }).Render();

 

That seemed like a lot of extra work though, since I'd already gone to the trouble of creating a custom model metadata provider, so I created an extension method for ColumnBuilder<T>:

   1:  public static class MvcContribGridColumnExtensionMethods
   2:  {
   3:      public static IGridColumn<T> WithAutonamedColumnFor<T>(
   4:          this ColumnBuilder<T> @this, 
   5:          Expression<Func<T, object>> propertySpecifier) where T : class 
   6:      {
   7:          var column = (GridColumn<T>) @this.For(propertySpecifier);
   8:   
   9:          ModelMetadata metadata = ModelMetadataProviders.Current
  10:              .GetMetadataForProperty(() => null, typeof(T), column.Name);
  11:   
  12:          return column.Named(metadata.DisplayName);
  13:      }
  14:  }

Line 7 uses the ColumnBuilder object's standard "For" method to initialize the column.

Line 9 gets the current model metadata provider for the model class and the current property (which for my site is my custom provider).

Line 12 returns the IGridColumn<T> object with the DisplayName assigned by the model metadata provider.

Now in my view I can get rid of the ".Named" calls and just use my ".WithAutomatedColumnFor" extension instead of the standard ".For" and ".Named" methods to initialize each column:

Html.Grid(Model.Items)
    .Attributes(@class => "mvcContribGrid jqStyleAlternateItems", border => "1")
    .HeaderRowAttributes(new Dictionary<string, object> { { "valign", "bottom" } })
    .RowStart(row => "<tr valign=\"top\">")
    .Sort(Model.MvcContribGridSortOptions)
    .Columns(column =>
    {
        column.WithAutonamedColumnFor(x => x.BarCode)
            .Action(x => Response.Write(string.Format(barCodeLinkFormat, x.BarCode, x.Id)));
        column.WithAutonamedColumnFor(x => x.Owner);
        column.WithAutonamedColumnFor(x => x.Description);
        column.WithAutonamedColumnFor(x => x.RetentionCode);
        column.WithAutonamedColumnFor(x => x.StatusDescription);
        column.WithAutonamedColumnFor(x => x.LegalHold)
            .Action(x => Response.Write((x.LegalHold) ? checkMarkCell : emptyCell));
        column.WithAutonamedColumnFor(x => x.TaxHold)
            .Action(x => Response.Write((x.TaxHold) ? checkMarkCell : emptyCell));
        column.WithAutonamedColumnFor(x => x.FromDate)
            .Format(dateFormat)
            .Attributes(data => dateColumnAttributes);
        column.WithAutonamedColumnFor(x => x.ToDate)
            .Format(dateFormat)
            .Attributes(data => dateColumnAttributes);
        column.WithAutonamedColumnFor(x => x.EligibleRetirementDate)
            .Format(dateFormat)
            .Attributes(data => dateColumnAttributes);
    }).Render();
Posted on Tuesday, July 6, 2010 9:44 PM | Back to top


Comments on this post: Extending MvcContrib grid with custom DataAnnotationsModelMetadataProvider

# re: Extending MvcContrib grid with custom DataAnnotationsModelMetadataProvider
Requesting Gravatar...
I started using the Attributes to create our field labels, but stopped. The more I thought about it the more I decided that the label of the field shouldn't be a concern of the model, but more of a concern of the view. This became clear as we wanted a field to appear with a different name depending on if the view was for internal or external customers.

Left by Mark Borcherding on Jul 07, 2010 8:33 AM

# re: Extending MvcContrib grid with custom DataAnnotationsModelMetadataProvider
Requesting Gravatar...
I suppose if you have a specific View Model data annotations work well. For me, the more of the HTML I give up, the less my designers can tweak without my help.
Left by Mark Borcherding on Jul 07, 2010 9:51 AM

# re: Extending MvcContrib grid with custom DataAnnotationsModelMetadataProvider
Requesting Gravatar...
My custom DataAnnotationsModelMetadataProvider is strictly for localization. It's just looking at my resource files using the property name as the key, so the behavior is the same if there were no custom provider (the display name is the property name), only localized.

If they need to be different on different views, that can still be done, but the default will be in the right language.
Left by Brian Schroer on Jul 09, 2010 7:44 AM

# re: Extending MvcContrib grid with custom DataAnnotationsModelMetadataProvider
Requesting Gravatar...
Thanks! Usefully
Left by Sergeu on Nov 25, 2010 8:39 PM

# re: Extending MvcContrib grid with custom DataAnnotationsModelMetadataProvider
Requesting Gravatar...
Thanks for this post! How do I create the same extension method for AutoColumnBuilder<T>?

Thanks,
Aliyar
Left by Aliyar on Nov 17, 2011 3:06 PM

Your comment:
 (will show your gravatar)


Copyright © Brian Schroer | Powered by: GeeksWithBlogs.net