如何创建自定义Html.Control?

时间:2011-05-05 20:00:40

标签: c# asp.net-mvc asp.net-mvc-3 razor

我有一个名为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下拉绑定值

3 个答案:

答案 0 :(得分:1)

只需从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类创建EditorTemplate。只需google for asp.net mvc editortemplate。 http://www.codecapers.com/post/Display-and-Editor-Templates-in-ASPNET-MVC-2.aspx

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

答案 1 :(得分:0)

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

Get Custom Attributes from Lambda Property Expression

或者只使用字符串表达式并将其操作为http://www.joelscode.com/post/Use-MVC-Templates-with-Dynamic-Members-with-custom-HtmlHelper-Extensions.aspx

答案 2 :(得分:0)

在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)

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