Lion
Lion

Reputation: 17879

Custom DataAnnotations-Attribute like UIHint

I want to create a custom DataAnnotations-Attribute for my editor as a clean and reuseable way to load the editor in a model like this:

class MyModel {
    [MyEditor(ShowPreview: true)]
    public string Text{ get; set; }
}

I found out that a custom attribute can be done by inherit from Attribute:

class MyEditorAttribute : Attribute { }

The problem is: How can I get information about the field like id or name (in this example Text) and how can I return my custom template when the html should get rendered in the view like

@Html.EditorFor(model => model.Text)

The only way I found out which works is using the UIHint-Attribute.

class MyModel {
    [UIHint("MyEditor"), AllowHtml]
    public string Text{ get; set; }
}

In this example I can add a view named Views/Shared/EditorTemplates/MyEditor.cshtml which gets automatically rendered for this attribute. There I can get for example the id of the field with ViewData.TemplateInfo.GetFullHtmlFieldId(string.Empty)

But I want to create a custom attribute because its cleaner, I can specify there some attributes for my editor in a clean way. How can I do this using DataAnnotations? I couldn't find information about this. I also searched for the source of the UIHint-Class to see how it works, but although the .NET framework is open source I can't find the source of those class.

Upvotes: 0

Views: 535

Answers (1)

Erik Philips
Erik Philips

Reputation: 54618

I want to create a custom attribute because its cleaner, I can specify there some attributes for my editor in a clean way.

Yes you can do this.

How can I do this using DataAnnotations?

DataAnnotations is a namespace, don't confuse a name space with a class like attribute. What you want is an Attribute.

First create an attribute that derives from the UIHintAttribute.

public UIDateTimeAttribute : UIHintAttribute
{
  public UIDateTimeAttribute(bool canShowSeconds)
    : base("UIDateTime", "MVC")
  {
    CanShowSeconds = canShowSeconds;
  }

  public bool CanShowSeconds { get; private set; }
}

Then apply it to a model:

public class Person
{
  [UIDateTime(false)]
  public DateTime Birthday { get; set; }
}

Then create your /Views/Shared/DisplayTemplates/UIDateTime.cshtml file:

@model DateTime

@{
  var format = "dd-MM-yy hh:mm:ss";

  // Get the container model (Person for example)
  var attribute = ViewData.ModelMetadata.ContainerType
    // Get the property we are displaying for (Birthday)
    .GetProperty(ViewData.ModelMetadata.PropertyName)
    // Get all attributes of type UIDateTimeAttribute
    .GetCustomAttributes(typeof(UIDateTimeAttribute))
    // Cast the result as UIDateTimeAttribute
    .Select(a => a as UIDateTimeAttribute)
    // Get the first one or null
    .FirstOrDefault(a => a != null);

  if (attribute != null && !attribute.CanShowSeconds)
  {
    format = "dd-MM-yy hh:mm";
  }
}

@Model.ToString(format)

Upvotes: 2

Related Questions