我正在尝试创建一个自定义ModelMetadataProvider,为JQuery UI自动完成小部件提供不显眼的属性。
我有一个如下所示的自定义属性:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class AutocompleteAttribute : Attribute, IMetadataAware
{
public void OnMetadataCreated(ModelMetadata metadata)
{
metadata.TemplateHint = "Autocomplete";
}
}还有一个编辑器模板,如下所示:
@{
var attributes = new RouteValueDictionary
{
{"class", "text-box single-line"},
{"autocomplete", "off"},
{"data-autocomplete-url", "UrlPlaceholder" },
};
}
@Html.TextBox("", ViewContext.ViewData.TemplateInfo.FormattedModelValue, attributes)我有一个viewModel,其属性为string类型,其中包括如下所示的AutocompleteAttribute:
public class MyViewModel
{
[Autocomplete]
public string MyProperty { get; set; }
}当我在视图中使用这个viewModel时,我会检查生成的html,并得到一个<input>标记,其属性如下:data-autocomplete-url="UrlPlaceholder"。
接下来我要做的是能够在我的视图中指定使用viewModel的URL,如下所示:
@model MyViewModel
@{ ViewBag.Title = "Create item"; }
@Html.AutoCompleteUrlFor(p => p.MyProperty, UrlHelper.GenerateUrl(null, "Autocomplete", "Home", null, Html.RouteCollection, Html.ViewContext.RequestContext, true))
// Other stuff here...
<div>
@Html.ActionLink("Back to List", "Index")
</div>我的AutoCompleteForUrl助手将生成的URL保存在字典中,使用属性名作为键。
接下来,我创建了一个自定义ModelMetadataProvider,并使用这行代码ModelMetadataProviders.Current = new CustomModelMetadataProvider();在global.asax中注册了它。
我想要做的是将JQuery UI自动完成小部件使用的URL插入到metadata.AdditionalValues字典中,供自动完成编辑器模板使用。
我的自定义ModelMetadataProvider如下所示:
public class CustomModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata CreateMetadata(IEnumerable<System.Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
{
var metadata = base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
if (metadata.TemplateHint == "Autocomplete")
{
string url;
if(htmlHelpers.AutocompleteUrls.TryGetValue(metadata.propertyName, out url)
{
metadata.AdditionalValues["AutocompleteUrl"] = url;
}
}
return metadata;
}
}我更新的编辑器模板如下所示:
@{
object url;
if (!ViewContext.ViewData.ModelMetadata.TryGetValue("AutocompleteUrl", out url))
{
url = "";
}
var attributes = new RouteValueDictionary
{
{"class", "text-box single-line"},
{"autocomplete", "off"},
{"data-autocomplete-url", (string)url },
};
}
@Html.TextBox("", ViewContext.ViewData.TemplateInfo.FormattedModelValue, attributes)问题是,在我的自定义模型元数据提供程序中,TemplateHint属性永远不等于“自动完成”,因此我生成该URL的逻辑永远不会被调用。我认为此时TemplateHint属性将被设置为我所称的CreateMetadata of DataAnnotationsModelMetadataProvider的基本实现。
我可以证实的是:
CustomModelMetadataProvider是正确注册的,因为它包含正在被调用的其他代码。"data-autocomplete-url"的属性时,将获取正确的编辑器模板。有人能帮我解释一下这个吗?我对ModelMetadataProvider系统有什么误解?
发布于 2013-04-17 20:01:11
在查看了ASP.NET MVC 3源代码之后,我发现原因是CreateMetadata方法是在应用到模型的任何IMetadataAware属性的OnMetadataCreated方法之前调用的。
我找到了一个替代的解决方案,可以让我做我想做的事。
首先我更新了我的AutocompleteAttribute
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class AutocompleteAttribute : Attribute, IMetadataAware
{
public const string Key = "autocomplete-url";
internal static IDictionary<string, string> Urls { get; private set; }
static AutocompleteAttribute()
{
Urls = new Dictionary<string, string>();
}
public void OnMetadataCreated(ModelMetadata metadata)
{
metadata.TemplateHint = "Autocomplete";
string url;
if (Urls.TryGetValue(metadata.PropertyName, out url))
{
metadata.AdditionalValues[Key] = url;
Urls.Remove(metadata.PropertyName);
}
}
}用于在视图中设置url的Html助手方法如下所示:
public static IHtmlString AutocompleteUrlFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, string url)
{
if (string.IsNullOrEmpty(url))
throw new ArgumentException("url");
var property = ModelMetadata.FromLambdaExpression(expression, html.ViewData).PropertyName;
AutocompleteAttribute.Urls[property] = url;
return MvcHtmlString.Empty;
}然后我在编辑器模板中所要做的就是:
@{
object url;
ViewData.ModelMetadata.AdditionalValues.TryGetValue(AutocompleteAttribute.Key, out url);
var attributes = new RouteValueDictionary
{
{"class", "text-box single-line"},
{"autocomplete", "off"},
{ "data-autocomplete-url", url },
};
}
@Html.TextBox("", ViewContext.ViewData.TemplateInfo.FormattedModelValue, attributes)https://stackoverflow.com/questions/16058272
复制相似问题