Как позволить методу post action принять подобъект исходной модели представления в качестве параметра?

2

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

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
}

Все работает так, как должно, но это не "правильно" (IMHO), так как мне не нужен список "Страны" по возвращении, мне нужна только выбранная страна (что является одним из условий).

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

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

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

Обновить:

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

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

  • 0
    Похоже, вы хотите назвать это двумя способами ... Может быть, вы могли бы иметь один параметр каждый путь и выбрать, какой из них использовать на основе установленных значений.
  • 0
    Используете ли вы AjaxForm для выполнения вызовов AJAX или JQuery AJAX?
Показать ещё 3 комментария
Теги:
asp.net-mvc
viewmodel

2 ответа

4
Лучший ответ

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

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

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

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

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

Edit: По запросу: это код на мой взгляд (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>

<% } %>
  • 0
    Поздравляем! :)
  • 0
    Вы изменили имя параметра, и он начал работать? Меня может раздражать, не могли бы вы показать нам свою форму / представление (которое содержит элементы filterConditions). только для наших учебных целей. Я всегда думал, что Model Binder связывает элементы (используя атрибут name) с именем параметра контроллера.
Показать ещё 1 комментарий
1

Привет, 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 и postback 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();
}

Вид теста():

<% 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>
<% } %>

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


Возможно, вы можете попробовать

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

Привет ~ Вам не нужно комбинировать весь SelectListItem с ViewModel, на самом деле ваш ViewModel имеет только поле для хранения выбора пользователя, целого или строкового, а затем использовать DropDownListFor, например:

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

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

сообщите мне, если у вас есть проблемы:)

  • 1
    Насколько я понимаю, наилучшей практикой является то, что контроллер должен собрать все данные и передать их в представление. В вашем примере само представление запрашивает модель. Я не думаю, что это правильный способ сделать вещи в ASP.NET MVC.
  • 0
    Вы также можете передать две модели для просмотра одновременно, одна из них - наша модель представления, другая - наша модель списка <system.web.mvc.selectlistitem>, это нормально.
Показать ещё 9 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню