首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ModelMetadata TemplateHint总是空的

ModelMetadata TemplateHint总是空的
EN

Stack Overflow用户
提问于 2013-04-17 11:01:32
回答 1查看 1.4K关注 0票数 3

我正在尝试创建一个自定义ModelMetadataProvider,为JQuery UI自动完成小部件提供不显眼的属性。

我有一个如下所示的自定义属性:

代码语言:javascript
复制
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class AutocompleteAttribute : Attribute, IMetadataAware
{
    public void OnMetadataCreated(ModelMetadata metadata)
    {
        metadata.TemplateHint = "Autocomplete";
    }
}

还有一个编辑器模板,如下所示:

代码语言:javascript
复制
@{
    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

代码语言:javascript
复制
public class MyViewModel
{
    [Autocomplete]
    public string MyProperty { get; set; }
}

当我在视图中使用这个viewModel时,我会检查生成的html,并得到一个<input>标记,其属性如下:data-autocomplete-url="UrlPlaceholder"

接下来我要做的是能够在我的视图中指定使用viewModel的URL,如下所示:

代码语言:javascript
复制
@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如下所示:

代码语言:javascript
复制
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;
    }
}

我更新的编辑器模板如下所示:

代码语言:javascript
复制
@{
    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是正确注册的,因为它包含正在被调用的其他代码。
  • 当生成的Html包含一个名为"data-autocomplete-url"的属性时,将获取正确的编辑器模板。
  • 如果我在自动完成模板中放置了断点,Visual将转到调试器。

有人能帮我解释一下这个吗?我对ModelMetadataProvider系统有什么误解?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-04-17 20:01:11

在查看了ASP.NET MVC 3源代码之后,我发现原因是CreateMetadata方法是在应用到模型的任何IMetadataAware属性的OnMetadataCreated方法之前调用的。

我找到了一个替代的解决方案,可以让我做我想做的事。

首先我更新了我的AutocompleteAttribute

代码语言:javascript
复制
[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助手方法如下所示:

代码语言:javascript
复制
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;
}

然后我在编辑器模板中所要做的就是:

代码语言:javascript
复制
@{
    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)
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16058272

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档