【问题标题】:Overriding the default EditorFor template-selecting in ASP.NET MVC 3 RC覆盖 ASP.NET MVC 3 RC 中的默认 EditorFor 模板选择
【发布时间】:2010-11-12 02:22:28
【问题描述】:

我正在创建一个当前使用 EditorFor 生成大量视图的 MVC 应用程序。整个视图基本上只是一个 EditorForModel,而且效果很好。但是,我遇到了一个小问题,我似乎无法找到解决方案,重要的是它按我需要的方式工作,那就是在尝试渲染 EditorFor 界面时。绑定和类似的一切都已处理,但问题是 EditorFor 认为它是一个接口,并默认为“对象”模板。我需要它查看接口,看看它是否可以找到具有该名称的模板,如果不能,我需要它查看所有存在的接口,看看它是否与其中任何一个匹配。为了更简单地解释它,请看这个例子:

接口:

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.

如果我现在使用 model = "IAppMusicProvider" 创建一个视图并运行 Html.EditorForModel(),我需要它来找到 "~Views\Shared\EditorTemplates\IAppProvider.cshtml" 模板。有什么简单的方法可以实现吗?

【问题讨论】:

    标签: asp.net-mvc templates editorfor


    【解决方案1】:

    您可以尝试将ModelMetadata.TemplateHint 更改为ModelMetadataProvider。一种方法是使用装饰器模式:

    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;
        }
    }
    

    在你的启动逻辑中:

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

    【讨论】:

      【解决方案2】:

      您是否尝试过使用[TemplateHint] 属性?

      【讨论】:

      • 是的,这行得通,但这不是解决问题的方法(或者更确切地说,我实际上使用了[DataType] 属性)。我正在制作的应用程序将运行插件,我只需要通过设置界面来使其工作,而不必强制所有插件开发人员使用用户[DataType("IAppProvider")]
      • 尝试将模板命名为与界面相同的名称?如果我记得那是仅有的两个选择。
      • 这也行不通,因为模板需要对所有IAppProviders 都有效。我正在寻找某种方法来覆盖此默认行为,以便如果我提供 IAppProvider 实现接口,它将使用 IAppProvider 模板。这可能需要在 MVC 中的某个地方进行编码(一些需要更改的组件,例如您可以使用 ControllerFactory 等),但我什至不知道从哪里开始。
      • 我想你的意思是[UIHint]TemplateHint 似乎是 ModelMetadata 的属性。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-21
      • 2012-03-15
      • 1970-01-01
      • 2012-05-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多