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