Как позволить методу post action принять подобъект исходной модели представления в качестве параметра? - PullRequest
2 голосов
/ 22 апреля 2011

Это моя модель:

public class IndexViewModel
{
    public FilterConditions conditions { get; set }
    public IEnumerable<SelectListItem> Countries { get; set }
}

public class FilterConditions
{
    public string condition11 { get; set }
    // ...
}

И у меня есть Index метод действия, подобный так:

public ActionResult Index()
{
    var model = new IndexViewModel();

    // fill the model here with default values

    return View(model);
}

Представление отображает форму с условиями фильтра в качестве типов ввода.

Теперь я хочу, чтобы сообщение из этой формы обрабатывалось этим методом действия:

[HttpPost]
public ActionResult Index(FilterConditions model)
{
    // do some magic with model and return another view here
}

и это действительно работает (я поставил точку останова в методе, и он вызывается), но свойства моей модели всегда пусты (значения по умолчанию), в то время как они должны содержать значения, которые были отправлены формой.

Когда я изменяю метод действия следующим образом:

[HttpPost]
public ActionResult Index(IndexViewModel model)
{
    // do some magic with model.conditions and return another view here
}

Все работает так, как должно, но это не «правильно» (ИМХО), поскольку мне не нужен список «Страна» по возвращении, мне нужна только выбранная страна (что является одним из условий).

Каков хороший (лучший метод) способ выполнить эту работу, не принимая всю исходную модель представления в качестве входного параметра?

Кстати, я использую ASP.NET MVC 2 (я не думаю, что это действительно имеет значение, поскольку я думаю, что это та же проблема в MVC 3, но я не совсем уверен в этом).

(Я искал в интернете «лучшие практики» в отношении выпадающих списков и моделей представления в рамках asp.net mvc, но разные рекомендации, которые я нашел, на самом деле не совпадали друг с другом, и многие из них уже устарели Я не нашел «официальной» лучшей практики по этому поводу. Я надеюсь, что я иду в правильном направлении (имея список как часть моей модели представления), не стесняйтесь поправлять меня в этом вопросе, если я нет. Также не стесняйтесь указывать мне «одобренные лучшие практики» по этому поводу, если вы знаете что-либо.

Обновление :

Я обнаружил, что могу использовать атрибут [Bind] с префиксом «условия фильтра». И это действительно работает для этого взгляда. Но моя первоначальная проблема (я признаю, она не была включена в мой вопрос) не решена.

Бывает, что этот конкретный метод действия также вызывается из другого представления (это ajax-вызов), где у него нет этого префикса, в этом случае он больше не работает. Есть предложения?

Ответы [ 2 ]

4 голосов
/ 26 апреля 2011

Я нашел решение.

По-видимому, когда я использую то же имя переменной параметра, что и имя типа (регистр не обязательно должен совпадать), например:

[HttpPost]
public ActionResult Index(FilterConditions filterConditions)
{
    // do some magic with model and return another view here
    // now the filterConditions variable actually contains values!
}

Все работает так, как должно (значения моих условий фильтра больше не пустые / нулевые).По-видимому, связующее устройство по умолчанию использует имя параметра в качестве потенциального префикса для привязки.

Я рад, что узнал, но было бы неплохо, если бы это было где-то более четко задокументировано.Это совсем не очевидно.

Редактировать : По запросу: это код на мой взгляд (aspx):

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MyProject.Models.IndexViewModel>" %>

<%-- ... more stuff here ... --%>

<% using (Html.BeginForm())
   {%>
    <%= Html.ValidationSummary(true)%>

    <fieldset>
        <div class="editor-label">
            <%= Html.LabelFor(model => model.FilterConditions.Country)%>
        </div>
        <div class="editor-field">
            <%= Html.DropDownListFor(model => model.FilterConditions.Country, Model.Countries)%>
            <%= Html.ValidationMessageFor(model => model.FilterConditions.Country)%>
        </div>

        <div class="editor-label">
            <%= Html.LabelFor(model => model.FilterConditions.Make)%>
        </div>
        <div class="editor-field">
            <%= Html.TextBoxFor(model => model.FilterConditions.Make)%>
            <%= Html.ValidationMessageFor(model => model.FilterConditions.Make)%>
        </div>

        <%-- ... more fields inserted here ... --%>

        <p>
            <input type="submit" value="  Search...  " />
        </p>
    </fieldset>

<% } %>
1 голос
/ 22 апреля 2011

Hi fretje: теперь я могу использовать ваш способ решения вашей проблемы. Сначала у меня есть две модели "IndexViewModel" и "Index" и DropDownList (это не имеет значения, просто предлагают элементы DropDown):

public class IndexViewModel : Index
{
   //public  int value { get; set; }
   public   List<System.Web.Mvc.SelectListItem> items { get; set; }
}

public class Index
{
    public int value { get; set; }
}


class DropDownList
{
   public List<System.Web.Mvc.SelectListItem> GetDropDownList()
   {
       List<System.Web.Mvc.SelectListItem> result = new List<System.Web.Mvc.SelectListItem>();
       result.Add(new System.Web.Mvc.SelectListItem
       {
           Value = "1",
           Text = "Apple"
       });
       result.Add(new System.Web.Mvc.SelectListItem
       {
           Value = "2",
           Text = "Milk"
       });
       return result;
   }
}

И два контроллера это Test () и Test (Models.Index), я передаю IndexViewModel и обратную передачу IndexModel:

public ActionResult Test()
{
    var result =
        new Models.IndexViewModel
        {
            value = 1,
            items = new Models.DropDownList().GetDropDownList()
        };
    return View(result);
}
[HttpPost]
public ActionResult Test(Models.Index posatback)
{
    return View();
}

Представление Test ():

<% using (Html.BeginForm()) {%>
    <%: Html.ValidationSummary(true) %>        
    <fieldset>
        <legend>Fields</legend>            
        <div class="editor-field">
                    <%: Html.DropDownListFor(m=>m.value, Model.items )%>
        </div>            
        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
<% } %>

это работа!спасибо fretje, я узнал еще одну технологию.:)


Может быть, вы можете попробовать

[HttpPost]
public ActionResult Index([Bind(Exclude="Countries")]IndexViewModel model)
{
    // do some magic with model.conditions and return another view here
}

Привет ~ Вам не нужно объединять весь SelectListItem с ViewModel, на самом деле ваш ViewModel просто имеет поле для хранения пользователяchoise, integer или string, затем используйте DropDownListFor, например:

<%: Html.DropDownListFor(item.WeaponID, MyApplication.Models.DropDownList.GetDropDownList() )%>

пожалуйста, смотрите мой пост в моем блоге, я использую очень простой пример, чтобы объяснить: http://maidot.blogspot.com/2011/04/aspnet-mvc-viewdropdownlistfor.html

дайте мне знатьу вас есть какие-либо проблемы:)

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