inputタグに属性を追加するための自作属性「HtmlProperties」を作ってみました。
maxlength属性や、onkeyup等のイベントハンドラをメタデータクラスで設定できるようにします。
[Required]
[HtmlProperties(maxlength = 64, onkeyup = "AjaxCheck('UserName',value);")]
[DisplayName("氏名")]
[DataType(DataType.Text)]
public string UserName { get; set; }
こんな感じで使えるようにするのが目標です。
なお、作成にあたって以下のサイトが大変参考になりましたm(_ _)m
→Kiran Chand’s Blog : Adding html attributes support for Templates – ASP.Net MVC 2.0 Beta:
まず、属性クラスの本体を作成します。
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)] public class HtmlPropertiesAttribute : Attribute { public int maxlength { get; set; } public string onkeyup { get; set; } public IDictionary<string, object> HtmlAttributes() { IDictionary<string, object> htmlatts = new Dictionary<string, object>(); if (maxlength != 0) { htmlatts.Add("maxlength", maxlength); } if (!String.IsNullOrEmpty(onkeyup)) { htmlatts.Add("onkeyup", onkeyup); } return htmlatts; } }
属性の基本クラス Attribute を継承し、HtmlPropertiesAttribute クラスを作成し、
各プロパティにinputタグに設定したい属性を記載します。
ここでは、maxlength,onkeyupを指定しています。
次に、HtmlPropertiesAttributeのメタデータ属性追加処理を記述します。
public class MetadataProvider : DataAnnotationsModelMetadataProvider { protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName) { var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName); var additionalValues = attributes.OfType<HtmlPropertiesAttribute>().FirstOrDefault(); if (additionalValues != null) { metadata.AdditionalValues.Add("HtmlAttributes", additionalValues); } return metadata; } }
DataAnnotationsModelMetadataProvider クラスは規定のMVCフレームワークにおけるメタデータの総締めで、
メタデータを取得する CreateMetadata メソッドの内容を、HtmlAttributet を追加するように書き換えたクラス
MetadataProvider を作成します。
上記のクラスを、Global.asaxの中で、以下のようにしてModelMetadataProviders.Currentに指定します。
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ModelMetadataProviders.Current = new MetadataProvider();
}
次に、ビュー側で属性を埋め込むためのHtmlヘルパーメソッドを作成します。
namespace WebProject.Helpers { public static class Extensions { public static IDictionary<string, object> GetHtmlAttribute(this HtmlHelper htmlHelper) { return GetHtmlAttribute(htmlHelper, new Dictionary<string, Object>()); } public static IDictionary<string, object> GetHtmlAttribute(this HtmlHelper htmlHelper, IDictionary<string, Object> htmlAttributes) { var htmlPropertiesAttribute = new WebProject.Common.HtmlPropertiesAttribute(); if (htmlHelper.ViewData.ModelMetadata.AdditionalValues.ContainsKey("HtmlAttributes")) { htmlPropertiesAttribute = (WebProject.Common.HtmlPropertiesAttribute)htmlHelper. ViewData.ModelMetadata.AdditionalValues["HtmlAttributes"]; } var attributes = htmlPropertiesAttribute.HtmlAttributes(); attributes.Add("class", htmlHelper.ViewData.ModelMetadata.ContainerType.Name + "_" + htmlHelper.ViewData.ModelMetadata.PropertyName); foreach (KeyValuePair<string, object> kp in htmlAttributes) { attributes.Add(kp.Key, kp.Value); } return attributes; } } }
メタデータから取得した属性リストと、引数から渡された属性リストを合わせて返却します。
ついでに内部で class 属性も追加していますが、この辺りはお好みで変更して下さい。
以下はビュー側の処理です。
<%= Html.EditorFor(model => model.name, ViewData.TemplateInfo.FormattedModelValue) %> <%= Html.EditorFor(model => model.name, ViewData.TemplateInfo.FormattedModelValue, new { @style = "width:5em" })) %>
まずEditorFor から対象の画面項目の種類を判別し、カスタムテンプレートを呼び出します。
DataType 属性で Text を指定していれば、View→Shared→EditorTemplatesフォルダ配下の Text.ascx を使用します。
以下はText.ascxの全コードです。
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %> <%@ Import Namespace="WebProject.Helpers" %> <%= Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, Html.GetHtmlAttribute(ViewData)) %>
GetHtmlAttribute によって属性が付加されます。
HtmlProperthisを使いたい画面項目種別(Text や Password 等)ごとに
カスタムテンプレートを作成しなければならないので注意して下さい。
なお、検証用の属性を作成したい場合は、デフォルトのMVC2プロジェクトに存在するAccountModel.csの
ValidatePasswordLengthAttributeクラスが参考になるかと思います。