开发者

Overriding the default EditorFor template-selecting in ASP.NET MVC 3 RC

开发者 https://www.devze.com 2023-01-24 11:43 出处:网络
I\'m creating a MVC-application which currently uses EditorFor to gennerate a lot of views. The whole 开发者_JAVA百科view is basically just an EditorForModel, and it works great. However, I\'ve reache

I'm creating a MVC-application which currently uses EditorFor to gennerate a lot of views. The whole 开发者_JAVA百科view is basically just an EditorForModel, and it works great. However, I've reached one small problem, which I can't seem to find a solution for, and it is important that it works the way I need it to, and that is when trying to render EditorFor an interface. The bindings and everything like that's been taken care of, but the problem is that the EditorFor sees that it's an interface, and defaults to the "Object" template. I need it to look at the interface and see if it can find a template with that name, and if it can't, I need it to look trough all the interfaces present to see if it matches any of them. To explain it more simply look at this example:

interfaces:

public interface IAppProvider
{
    string Name { get; set; }
}

public interface IAppMusicProvider : IAppProvider
{
    int GetPlaylistCount();
} // Yeah, I know, this interface is not smart, but it's only for show.

If I now create a View with model = "IAppMusicProvider", and run Html.EditorForModel(), I need it to find the "~Views\Shared\EditorTemplates\IAppProvider.cshtml"-template. Is there any simple way I can achieve this?


You could try changing ModelMetadata.TemplateHint in the ModelMetadataProvider. One way to do this is with the decorator pattern:

public class AbstractTypeTemplateSupportingModelMetadataProvider : ModelMetadataProvider
{
    private readonly ModelMetadataProvider wrapped;

    public AbstractTypeTemplateSupportingModelMetadataProvider(ModelMetadataProvider wrapped)
    {
        this.wrapped = wrapped;
    }

    public override IEnumerable<ModelMetadata> GetMetadataForProperties(object container, Type containerType)
    {
        var result = this.wrapped.GetMetadataForProperties(container, containerType).ToList();
        result.ForEach(ChangeTemplateHint);

        return result;
    }

    public override ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, string propertyName)
    {
        var result = this.wrapped.GetMetadataForProperty(modelAccessor, containerType, propertyName);
        ChangeTemplateHint(result);

        return result;
    }

    public override ModelMetadata GetMetadataForType(Func<object> modelAccessor, Type modelType)
    {
        var result = this.wrapped.GetMetadataForType(modelAccessor, modelType);
        ChangeTemplateHint(result);

        return result;
    }

    private void ChangeTemplateHint(ModelMetadata source)
    {
        if (source.Model is IAppProvider) //Or use source.ModelType if you want to support the model being null.
            source.TemplateHint = typeof(IAppProvider).Name;
    }
}

And in your start-up logic:

ModelMetadataProviders.Current = new AbstractTypeTemplateSupportingModelMetadataProvider(ModelMetadataProviders.Current);


Did you try using the [TemplateHint] attribute?

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号