Как создать собственный Html.ControlFor? - PullRequest
1 голос
/ 06 мая 2011

У меня есть класс с именем 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; }
}

One Entity содержит Location, поэтому я хочу сгенерировать 3 выпадающих списка для Location.

  • Страна
  • Государство
  • Город

Я мог бы сделать это вручную, как

@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" } })

Но у меня есть несколько мест на моем веб-сайте, которые будут нуждаться в тех же трех выпадающих списках, как Restaurant, Hotel и другие классы, которые также имеют 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 ]

1 голос
/ 06 мая 2011

Просто создайте свое собственное расширение из 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

Кроме того, вы можете создать EditorTemplate для вашего класса Location. Просто Google для asp.net MVC редактор шаблонов. http://www.codecapers.com/post/Display-and-Editor-Templates-in-ASPNET-MVC-2.aspx

Лично я бы остановился на EditorTemplates, так как вы можете изменить представление без необходимости перекомпиляции.

0 голосов
/ 06 мая 2011

Следуя маленьким подсказкам Сиксонии, я получил то, что мне было нужно.

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

из любого места и на моем сайте есть селектор мест по умолчанию.

0 голосов
/ 06 мая 2011

Вы можете следовать этому примеру, чтобы использовать выражение и тело выражения

Получение пользовательских атрибутов из выражения лямбда-свойства

Или просто используйте строковое выражение и манипулируйте им, как здесь http://www.joelscode.com/post/Use-MVC-Templates-with-Dynamic-Members-with-custom-HtmlHelper-Extensions.aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...