ViewModel имеет значение Null в методе HttpPost

я использую ASP.NET MVC 4 и я построили эти ViewModels:

public class NotificationViewModel
{

    public string GroupDesc { get; set; }

    public bool AM { get; set; }

    public bool PM { get; set; }

    public int MaxNotif { get; set; }
}

public class SettingsViewModel
{
    public List<NotificationViewModel> ListNotification { get; set; }

    public SettingsViewModel()
    {
        ListNotification = new List<NotificationViewModel>();
    }
}

Мое Мнение :

@model PortailT2A.Models.SettingsViewModel

@{
    ViewBag.Title = "Preferences";
    Layout = "~/Views/Shared/_LayoutAdmin.cshtml";
}

<h2>Preferences</h2>


@using(Html.BeginForm("Preferences", "Administrateur", FormMethod.Post))
{

    <table id="settingsTable">
        <tr>
            <th>Groupe</th>
            <th></th>
            <th>AM</th>
            <th>PM</th>
            <th>Limite de notifications</th>
        </tr>

    @for (int i = 0; i < Model.ListNotification.Count(); i++ )
    {
        var notif = Model.ListNotification[i];
        <tr>
            <td>@notif.GroupDesc </td>
            <td>Heure de notification</td>
            <td>@Html.CheckBoxFor(u => notif.AM)  </td>
            <td>@Html.CheckBoxFor(u => notif.PM)  </td>
            <td>@Html.TextBoxFor(u => notif.MaxNotif)</td>
        </tr>
        <tr/>


    }

    </table>


    <input type ="submit" value="Sauvegarder" />

}

мой метод HttpGet заполняет мою ViewModel и возвращает его.

    [HttpGet]
    public ActionResult Preferences(long idUser)
    {
        context = new MainDatabaseEntities();

        List<NotificationViewModel> notifications = new List<NotificationViewModel>();

        SettingsViewModel settings = new SettingsViewModel();

        //Population...

        return View(settings);
    }

однако, когда я хочу сохранить изменения, у меня есть ViewModel, который равен null, и я не понимаю, почему. Есть идеи, ребята?

редактировать: мой метод сообщения:

            [HttpPost]
            public ActionResult Preferences(SettingsViewModel sm)
            {
                //since here my ViewModel is null
                context = new MainDatabaseEntities();

                Utilisateur user = (from u in context.Utilisateurs where u.Username == User.Identity.Name select u).FirstOrDefault();

                //operations...

}

HTML-код генерируется :

<tr>
        <td>Groupe B </td>
        <td>Heure de notification</td>
        <td><input id="notif_AM" name="notif.AM" type="checkbox" value="true" /><input name="notif.AM" type="hidden" value="false" />  </td>
        <td><input checked="checked" id="notif_PM" name="notif.PM" type="checkbox" value="true" /><input name="notif.PM" type="hidden" value="false" />  </td>
        <td><input id="notif_MaxNotif" name="notif.MaxNotif" type="text" value="10" /></td>
    </tr>

5 ответов


List<T> может быть сложно при modelbinding, так как он сильно зависит от индексированных ключей. Помощники должны знать индекс, но путем присвоения notif в вашем цикле for они теряют ссылку. Вместо этого попробуйте что-то вроде следующего:

@for (int i = 0; i < Model.ListNotification.Count(); i++ )
{
    var notif = Model.ListNotification[i];
    <tr>
        <td>@notif.GroupDesc </td>
        <td>Heure de notification</td>
        <td>@Html.CheckBoxFor(u => u.ListNotification[i].AM)  </td>
        <td>@Html.CheckBoxFor(u => u.ListNotification[i].PM)  </td>
        <td>@Html.TextBoxFor(u => u.ListNotification[i].MaxNotif)</td>
    </tr>
    <tr/>
}

, который затем должен предоставить вам что-то вроде:

<tr>
    <td>Groupe B </td>
    <td>Heure de notification</td>
    <td>
        <input id="ListNotification[0]_AM" name="ListNotification[0].AM" type="checkbox" value="true" />
        <input name="ListNotification[0].AM" type="hidden" value="false" />
    </td>
    <td>
        <input checked="checked" id="ListNotification[0]_PM" name="ListNotification[0].PM" type="checkbox" value="true" />
        <input name="ListNotification[0].PM" type="hidden" value="false" />
    </td>
    <td>
        <input id="ListNotification[0]_MaxNotif" name="ListNotification[0].MaxNotif" type="text" value="10" />
    </td>
</tr>

кроме того, не забудьте проверить ModelState.IsValid в вашем опубликованном действии, чтобы подтвердить, что модель была привязана правильно. Если нет, вы должны увидеть список ошибок в ModelState это даст вам некоторое представление о том, где он мог потерпеть неудачу.

кроме того, я не вижу, чтобы вы сваливали GroupDesc в любом месте (за исключением выходных). Если это необходимо для входящей модели, вы можете использовать @Html.HiddenFor(x => x.ListNotifications[i].GroupDesc).


вы неправильно строите свой HTML. Что передается обратно не будет пути связыватель модели ожидает.

подумайте о замене этого:

@for (int i = 0; i < Model.ListNotification.Count(); i++ )
{
    var notif = Model.ListNotification[i];
    <tr>
        <td>@notif.GroupDesc </td>
        <td>Heure de notification</td>
        <td>@Html.CheckBoxFor(u => notif.AM)  </td>
        <td>@Html.CheckBoxFor(u => notif.PM)  </td>
        <td>@Html.TextBoxFor(u => notif.MaxNotif)</td>
    </tr>
    <tr/>
}

С этого:

@Html.DisplayModelFor(m => m.ListNotification)

и добавьте такой шаблон в /Views/{YourController}/{YourAction}/EditorTemplates/NotificationViewModel.cshtml

@model NotificationViewModel
<tr>
    <td>@Model.GroupDesc</td>
    <td>Heure de notification</td>
    <td>@Html.CheckBoxFor(m => m.AM)</td>
    <td>@Html.CheckBoxFor(m => m.PM)</td>
    <td>@Html.TextBoxFor(m => m.MaxNotif)</td>
</tr>

моим первым предложением было бы попытаться добавить некоторое случайное свойство в вашу SettingValueModel и добавить его в форму как скрытый.

что-то вроде

 public class SettingsViewModel
 {
  public List<NotificationViewModel> ListNotification { get; set; }
  public string TestValue { get; set; }

  public SettingsViewModel()
  {
    ListNotification = new List<NotificationViewModel>();
    TestValue = "Test";   
  }
 }

затем на ваш взгляд добавить

@Html.HiddenFor(s=> s.TestValue)

когда вы отправляете свою форму, проверьте, не является ли SettingsViewModel нулевым. Если проблема заключается только в сериализации ListNotification, вы можете получить объект с TestValue уведомлений "Test" и null List. Если это кейс, по крайней мере, вы знаете, что проблема в ListNotifications.

также попробуйте изменить цикл for На этот

  @for (int i = 0; i < Model.ListNotification.Count(); i++ )
     {

         <tr>
             <td>@Model.ListNotification[i].GroupDesc </td>
             <td>Heure de notification</td>
             <td>@Html.CheckBoxFor(u => u.ListNotification[i].AM)  </td>
             <td>@Html.CheckBoxFor(u => u.ListNotification[i].PM)  </td>
             <td>@Html.TextBoxFor(u => u.ListNotification[i].MaxNotif)</td>

также я не думаю, что FormMethod.Post требуется в определении формы. Попробуйте все это. Если никто из них не поможет, то я могу только предположить, что ваш компьютер преследует=)


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

public int PaymentType { get; internal set; }

в POST action вы используете правильный тип модели?

[HttpPost]
public ActionResult Preferences(PortailT2A.Models.SettingsViewModel model)
{
   //...
}