【问题标题】:Stronglytyped html helper with different model for get and post具有不同模型的强类型 html 助手,用于获取和发布
【发布时间】:2012-03-10 08:58:25
【问题描述】:

如果一个 Get Action 返回一个带有“汽车”模型的视图。视图显示来自对象的信息,并接受输入以在表单中发布到另一个采用“付款”类型对象的操作

视图上的模型是 Car 类型,它为我提供了强类型的 html 支持和一些其他功能,例如 displaytext。但是对于发布我没有像 TextBox(x => x.amount 这样的 Htmlhelper 支持我需要让它像 @Html.TextBox("Amount"... 有可能,但这是唯一的选择吗?

【问题讨论】:

    标签: asp.net-mvc


    【解决方案1】:

    对于 ASP.NET Core 2

    public static class HtmlHelperFactoryExtensions
    {
        public static IHtmlHelper<TModel> HtmlHelperFor<TModel>(this IHtmlHelper htmlHelper)
        {
            return HtmlHelperFor(htmlHelper, default(TModel));
        }
    
        public static IHtmlHelper<TModel> HtmlHelperFor<TModel>(this IHtmlHelper htmlHelper, TModel model)
        {
            return HtmlHelperFor(htmlHelper, model, null);
        }
    
        public static IHtmlHelper<TModel> HtmlHelperFor<TModel>(this IHtmlHelper htmlHelper, TModel model, string htmlFieldPrefix)
        {
            ViewDataDictionary<TModel> newViewData;
            var runtimeType = htmlHelper.ViewData.ModelMetadata.ModelType;
            if (runtimeType != null && typeof(TModel) != runtimeType && typeof(TModel).IsAssignableFrom(runtimeType))
            {
                newViewData = new ViewDataDictionary<TModel>(htmlHelper.ViewData, model);
            }
            else
            {
                newViewData = new ViewDataDictionary<TModel>(htmlHelper.MetadataProvider, new ModelStateDictionary())
                {
                    Model = model
                };
            }
    
            if (!String.IsNullOrEmpty(htmlFieldPrefix))
                newViewData.TemplateInfo.HtmlFieldPrefix = newViewData.TemplateInfo.GetFullHtmlFieldName(htmlFieldPrefix);
    
            ViewContext newViewContext = new ViewContext(htmlHelper.ViewContext, htmlHelper.ViewContext.View, newViewData, htmlHelper.ViewContext.Writer);
    
            var newHtmlHelper = htmlHelper.ViewContext.HttpContext.RequestServices.GetRequiredService<IHtmlHelper<TModel>>();
            ((HtmlHelper<TModel>)newHtmlHelper).Contextualize(newViewContext);
            return newHtmlHelper;
        }
    }
    

    【讨论】:

      【解决方案2】:

      添加到 Max Toro 的实现中,当您有一个非空模型但没有静态类型信息时,这里还有几个(这两种方法需要嵌入到 Max 提供的实现中)。

      当您动态检索模型的属性名称并且需要调用采用名称而不是表达式的非泛型 HtmlHelper 方法时,这些方法可以很好地工作:

      @Html.TextBox(propertyName)
      

      例如。

          public static HtmlHelper HtmlHelperFor( this HtmlHelper htmlHelper, object model )
          {
              return HtmlHelperFor( htmlHelper, model, null );
          }
      
          public static HtmlHelper HtmlHelperFor( this HtmlHelper htmlHelper, object model, string htmlFieldPrefix )
          {
              var t = model.GetType();
              var viewDataContainer = CreateViewDataContainer( htmlHelper.ViewData, model );
      
              TemplateInfo templateInfo = viewDataContainer.ViewData.TemplateInfo;
      
              if( !String.IsNullOrEmpty( htmlFieldPrefix ) )
                  templateInfo.HtmlFieldPrefix = templateInfo.GetFullHtmlFieldName( htmlFieldPrefix );
      
              ViewContext viewContext = htmlHelper.ViewContext;
              ViewContext newViewContext = new ViewContext( viewContext.Controller.ControllerContext, viewContext.View, viewDataContainer.ViewData, viewContext.TempData, viewContext.Writer );
      
              var gt = typeof( HtmlHelper<> ).MakeGenericType( t );
      
              return Activator.CreateInstance( gt, newViewContext, viewDataContainer, htmlHelper.RouteCollection ) as HtmlHelper;
          }
      

      【讨论】:

        【解决方案3】:

        你可以这样做:

        @{
        var paymentHtml = Html.HtmlHelperFor<Payment>();
        }
        
        @paymentHtml.EditorFor(p => p.Amount)
        

        使用此扩展方法:

        public static class HtmlHelperFactoryExtensions {
        
           public static HtmlHelper<TModel> HtmlHelperFor<TModel>(this HtmlHelper htmlHelper) {
              return HtmlHelperFor(htmlHelper, default(TModel));
           }
        
           public static HtmlHelper<TModel> HtmlHelperFor<TModel>(this HtmlHelper htmlHelper, TModel model) {
              return HtmlHelperFor(htmlHelper, model, null);
           }
        
           public static HtmlHelper<TModel> HtmlHelperFor<TModel>(this HtmlHelper htmlHelper, TModel model, string htmlFieldPrefix) {
        
              var viewDataContainer = CreateViewDataContainer(htmlHelper.ViewData, model);
        
              TemplateInfo templateInfo = viewDataContainer.ViewData.TemplateInfo;
        
              if (!String.IsNullOrEmpty(htmlFieldPrefix))
                 templateInfo.HtmlFieldPrefix = templateInfo.GetFullHtmlFieldName(htmlFieldPrefix);
        
              ViewContext viewContext = htmlHelper.ViewContext;
              ViewContext newViewContext = new ViewContext(viewContext.Controller.ControllerContext, viewContext.View, viewDataContainer.ViewData, viewContext.TempData, viewContext.Writer);
        
              return new HtmlHelper<TModel>(newViewContext, viewDataContainer, htmlHelper.RouteCollection);
           }
        
           static IViewDataContainer CreateViewDataContainer(ViewDataDictionary viewData, object model) {
        
              var newViewData = new ViewDataDictionary(viewData) {
                 Model = model
              };
        
              newViewData.TemplateInfo = new TemplateInfo { 
                 HtmlFieldPrefix = newViewData.TemplateInfo.HtmlFieldPrefix 
              };
        
              return new ViewDataContainer {
                 ViewData = newViewData
              };
           }
        
           class ViewDataContainer : IViewDataContainer {
        
              public ViewDataDictionary ViewData { get; set; }
           }
        }
        

        【讨论】:

          【解决方案4】:

          如果我正确理解了您的问题,以下是我刚刚为我的一个项目编写的一些代码,用于执行类似的操作。它不需要像 Max Toro 所建议的那样特别。

          @{
              var teamHelper = new HtmlHelper<Team>(ViewContext, this);
          }
          
          @using (teamHelper.BeginForm())
          {
              @teamHelper.LabelFor(p => p.Name)
              @teamHelper.EditorFor(p => p.Name)  
          }
          

          【讨论】:

          • 最干净的解决方案。像魅力一样工作。
          【解决方案5】:

          如果我正确理解您的问题,请尝试:

          @Html.EditorFor(x => x.Amount)
          

          您还可以为付款创建一个编辑器模板。有关执行此操作的详细信息,请参阅this page

          如果我误解了,一些示例代码可能会有所帮助。

          【讨论】:

            猜你喜欢
            • 2011-11-02
            • 1970-01-01
            • 2011-04-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多