如何创建自定义 Html.ControlFor

本文关键字:自定义 Html ControlFor 创建 何创建 | 更新日期: 2023-09-27 17:55:12

我有一个名为Entity的类

public class Entity
{
    public string Name { get; set; }
    public Location Place { get; set; }
}

还有一类叫Location

public class Location
{
    public string Country { get; set; }
    public string State { get; set; }
    public string City { get; set; }
}

一个Entity包含一个Location,所以我想为Location生成 3 个下拉列表。

  • 国家
  • 城市

我可以像手动一样做

@Html.DropDownListFor(o => o.Country, new [] { new SelectListItem() { Text = "United States", Value="US" } })
<br />
@Html.DropDownListFor(o => o.State, new [] { new SelectListItem() { Text = "Some State", Value="SS" } })
<br />
@Html.DropDownListFor(o => o.City, new[] { new SelectListItem() { Text = "Some city", Value = "City" } })

但是我的网站上有几个地方需要完全相同的 3 个下拉菜单,例如 RestaurantHotel 和其他也有Location的类。我试图制作一个启动新表单的部分视图,但我得到了一个例外:

传递到字典中的模型项的类型为"TestMVC3Razor.Controllers.Entity",但此字典需要类型为"TestMVC3Razor.Controllers.Location"的模型项,代码如下:

@model TestMVC3Razor.Controllers.Entity
@using (Html.BeginForm())
{
    @Html.Partial("LocationSelector", Model.Place)
    <br />
    <input type="submit" value="Submit" />
}

部分观点是

@model TestMVC3Razor.Controllers.Location
@using (Html.BeginForm())
{
    @Html.DropDownListFor(o => o.Country, new [] { new SelectListItem() { Text = "United States", Value="US" } })
    <br />
    @Html.DropDownListFor(o => o.State, new [] { new SelectListItem() { Text = "Some State", Value="SS" } })
    <br />
    @Html.DropDownListFor(o => o.City, new[] { new SelectListItem() { Text = "Some city", Value = "City" } })
}

这显然不应该起作用,但我想做类似的事情,像这样的助手将是完美的

@Html.LocationSelectFor(o => o.Location)

但是我该怎么做呢?我需要生成3 dropdowns,当我发布到操作时,我需要获取具有出价值的对象。

public ActionResult(Location loc)
{
    var x = String.Format("{0}, {1} - {2}", loc.City, loc.Country, loc.State);
}

如何使此助手在发布时创建 3 个下拉列表绑定值

如何创建自定义 Html.ControlFor

只需在 HtmlHelper 中创建自己的扩展:

public static HtmlHelperExtensions {
  public static MvcString LocationSelectFor<TModel, TProperty>(this HtmlHelper<TModel> helper, System.Linq.Expressions.Expression<Func<TModel,TProperty>> expression) {
    // examine expression and build html
  }
}

诀窍是看表情。 这篇博文应该能帮助你入门:http://geekswithblogs.net/Madman/archive/2008/06/27/faster-reflection-using-expression-trees.aspx

或者,您可以为 Location 类创建编辑器模板。 只需谷歌搜索 asp.net mvc 编辑器模板。 http://www.codecapers.com/post/Display-and-Editor-Templates-in-ASPNET-MVC-2.aspx

就个人而言,我会坚持使用编辑器模板,因为您可以更改视图而无需通常重新编译。

您可以按照此示例使用表达式和表达式主体

从 Lambda 属性表达式获取自定义属性

或者只是使用字符串表达式并按照此处 http://www.joelscode.com/post/Use-MVC-Templates-with-Dynamic-Members-with-custom-HtmlHelper-Extensions.aspx 进行操作

按照xixonia的小提示,我得到了我需要的东西。

@Html.EditorFor(o => o.Place, "LocationSelector",
    new CreateLocation{ Country = "US", State = "A", City = "Y" })

我在下面有一个模板

Views
|- Shared
   |- EditorTemplates

LocationSelector.cshtml

@model TestMVC3Razor.Controllers.CreateLocation
@using TestMVC3Razor.Controllers
@Html.DropDownListFor(o => o.Country, Model.CountryList)
<br />
@Html.DropDownListFor(o => o.State, Model.StateList)
<br />
@Html.DropDownListFor(o => o.City, Model.CityList)

然后我做了

public class CreateEntity
{
    [Required]
    public string Name { get; set; }
    public CreateLocation Place { get; set; }
}
public class CreateLocation
{
    public CreateLocation(Location location = null)
    {
        if (location != null)
        {
            Country = location.Country;
            State = location.State;
            City = location.City;
        }
    }
    public string Country { get; set; }
    public string State { get; set; }
    public string City { get; set; }
    public IEnumerable<SelectListItem> CountryList
    {
        get
        {
            var list = new[]
            {
                new SelectListItem() { Text = "US", Value = "US" },
                new SelectListItem() { Text = "BR", Value = "BR" },
                new SelectListItem() { Text = "ES", Value = "ES" },
            };
            var selected = list.FirstOrDefault(o => o.Value == Country);
            if (selected != null)
            {
                selected.Selected = true;
            }
            return list;
        }
    }
    public IEnumerable<SelectListItem> StateList
    {
        get
        {
            var list = new[]
            {
                new SelectListItem() { Text = "A", Value = "A" },
                new SelectListItem() { Text = "B", Value = "B" },
                new SelectListItem() { Text = "C", Value = "C" },
            };
            var selected = list.FirstOrDefault(o => o.Value == State);
            if (selected != null)
            {
                selected.Selected = true;
            }
            return list;
        }
    }
    public IEnumerable<SelectListItem> CityList
    {
        get
        {
            var list = new[]
            {
                new SelectListItem() { Text = "X", Value = "X" },
                new SelectListItem() { Text = "Y", Value = "Y" },
                new SelectListItem() { Text = "Z", Value = "Z" },
            };
            var selected = list.FirstOrDefault(o => o.Value == City);
            if (selected != null)
            {
                selected.Selected = true;
            }
            return list;
        }
    }
}

还有我的控制器

public class HomeController : Controller
{
    public ActionResult Index()
    {
        // can load data for edit
        return View(new CreateEntity { Place = new CreateLocation(TempData["Location"] as Location) });
    }
    [HttpPost]
    public ActionResult Index(Entity ent)
    {
        var loc = ent.Place;
        var x = String.Format("{0} {1} {2}", loc.Country, loc.State, loc.City);
        ViewBag.Result = x; // display selected values
        TempData["Location"] = loc;
        return Index();
    }
}

我不知道这是否是最好的解决方案,但至少我可以打电话

@Html.EditorFor(o => o.Place, "LocationSelector", obj)

从任何地方,在我的网站上有一个默认的地方选择器。