自定义MVC HtmlHelper,使用已有的HtmlHelper with Expressions

本文关键字:HtmlHelper with Expressions MVC 自定义 | 更新日期: 2023-09-27 18:12:22

我正在尝试制作一个自定义HtmlHelper,它将在现有HtmlHelper的帮助下生成多个HTML元素,如Html.TextBoxForHtml.LabelFor。我遇到的主要问题是,我不能创建表达式由这些现有的助手使用,除非他们都传递到我的自定义HtmlHelper单独。我希望能够将整个模型传递给自定义HtmlHelper,并创建helper内部的表达式,并将它们传递给现有的表达式。我试图这样做,希望属性仍然可以工作,例如DisplayName的Required和国际化。这可能吗?

我知道我可以通过表达式将每个Address属性传递到自定义HtmlHelper中,但是感觉不像在helper中那样干净和容易使用。

地址模型
public class Address
{
    [Required(ErrorMessage = "Required"), DisplayName("First Name")]
    public String FirstName { get; set; }
    [Required(ErrorMessage = "Required"), DisplayName("Last Name")]
    public String LastName { get; set; }
    [Required(ErrorMessage = "Required"), DisplayName("Line 1")]
    public String Line1 { get; set; }
    [Required(ErrorMessage = "Required"), DisplayName("Line 2")]
    public String Line2 { get; set; }
    [Required(ErrorMessage = "Required"), DisplayName("City")]
    public String City { get; set; }
    [Required(ErrorMessage = "Required"), DisplayName("State")]
    public String State { get; set; }
    [Required(ErrorMessage = "Required"), DisplayName("Country")]
    public String Country { get; set; }
    [Required(ErrorMessage = "Required"), DisplayName("Postal Code")]
    public String PostalCode { get; set; }
}
定制HtmlHelper

public static class AddressExtension
{
    public static MvcHtmlString AddressEditorForModel<TModel>(this HtmlHelper<TModel> helper, Address address, String prefix, Boolean showLabels)
    {          
        // There will be more markup in here, this is just slimmed down..
        StringBuilder sb = new StringBuilder();
        sb.AppendLine(String.Format("<div id='{0}_AddressContainer' >", prefix));
        // First Name
        if (showLabels)
            sb.AppendLine(helper.DisplayFor(????).ToString());            
        sb.AppendLine(helper.EditorFor(????).ToString());
        // Last Name
        if (showLabels)
            sb.AppendLine(helper.DisplayFor(????).ToString());            
        sb.AppendLine(helper.EditorFor(????).ToString());
        // Line 1
        if (showLabels)
            sb.AppendLine(helper.DisplayFor(????).ToString());            
        sb.AppendLine(helper.EditorFor(????).ToString());
        // Line 2
        if (showLabels)
            sb.AppendLine(helper.DisplayFor(????).ToString());            
        sb.AppendLine(helper.EditorFor(????).ToString());
        // City
        if (showLabels)
            sb.AppendLine(helper.DisplayFor(????).ToString());            
        sb.AppendLine(helper.EditorFor(????).ToString());
        // State
        if (showLabels)
            sb.AppendLine(helper.DisplayFor(????).ToString());            
        sb.AppendLine(helper.EditorFor(????).ToString());
        // Country
        if (showLabels)
            sb.AppendLine(helper.DisplayFor(????).ToString());            
        sb.AppendLine(helper.EditorFor(????).ToString());
        // Postal Code
        if (showLabels)
            sb.AppendLine(helper.DisplayFor(????).ToString());            
        sb.AppendLine(helper.EditorFor(????).ToString());
        sb.AppendLine("</div>");
        return MvcHtmlString.Create(sb.ToString());
    }

视图(cshtml)

@Html.AddressEditorForModel(Model, "test", true)

自定义MVC HtmlHelper,使用已有的HtmlHelper with Expressions

您可以通过如下方式使用反射和表达式树:

public static MvcHtmlString AddressEditorForModel<TModel>(this HtmlHelper<TModel> helper, string prefix, bool showLabels)
{          
    // There will be more markup in here, this is just slimmed down..
    StringBuilder sb = new StringBuilder();
    sb.AppendLine(String.Format("<div id='{0}_AddressContainer' >", prefix));
         //Create a parameter expression for the model type
         ParameterExpression paramExpr = Expression.Parameter(typeof (TModel));
         //Loop through the properties you want to create a DisplayFor for
         foreach (var property in typeof (TModel).GetProperties())
         {
             //Create a member access expression for accessing this property
             MemberExpression propertyAccess = Expression.MakeMemberAccess(paramExpr, property);
             //Create the lambda expression (eg. "x => x.Name")
             var lambdaExpr = Expression.Lambda<Func<TModel, string>>(propertyAccess, paramExpr);
             //Pass this lambda to the DisplayFor method
             sb.AppendLine(helper.DisplayFor(lambdaExpr).ToString());
         }
...rest of your method
然而,这假设TModel是你的Address对象,所以你也不需要传递它。HTML helper中的TModel来自强类型视图,所以如果你有一个视图,其中@model类型是Address,那么你可以使用上面的方法

视图会这样使用它:

@model Address
@Html.AddressEditorForModel("prefix", true)