2015-03-03 6 views
0

У меня есть следующий код (ASP.NET MVC/C#) ... упрощение для краткости.Html.DropDownListДля привязки к сложному дочернему объекту

public class UserViewModel 
{ 
    public int UserId { get; set; } 
    public string Name { get; set; } 
    public AddressViewModel Address { get; set; } 

    public IEnumerable<SelectListItem> CitySelectList { get; set; } 
} 

public class AddressViewModel 
{ 
    public int AddressId { get; set; } 
    public string StreetAddress { get; set; } 
    public int CityId { get; set; } 
} 

По мнению бритвы я следующее:

@Html.DropDownListFor(x => x.Address.CityId, Model.CitySelectList) 

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

Я добавил новое свойство к UserViewModel под названием «SelectedCityId» и связан, что к DropDownList, как это проверить сложный вложенный объект является проблемой:

@Html.DropDownListFor(x => x.SelectedCityId, Model.CitySelectList) 

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

Только для устранения неполадок, я проверил почтовое поле кода, поскольку она также связывается с ребенком свойством класса Address, но он связывается должным образом при использовании аналогичного помощника TextBoxFor:

@Html.TextBoxFor(x => x.Address.PostalCode) 

Итак, мой вопрос почему привязка к модели не работает с помощником DropDownListFor, когда выражение связывает элемент управления с вложенным дочерним свойством? Я уверен, что это что-то тривиальное, что мне не хватает, но я не вижу, что это такое, и не нашел здесь подобного ответа.

EDIT: Вот вся HTML форма из cshtml файла

@using (Html.BeginForm("MyProfile", "Account", FormMethod.Post, new { id = "myProfileForm" })) 
     { 
      @Html.HiddenFor(x => x.UserId) 
      @Html.HiddenFor(x => x.AddressId) 
      @Html.HiddenFor(x => x.Address.CityId) 

      <article class="mysettings"> 
       <h1>Personal details</h1> 
       <table> 
        <tr> 


       <th>E-mail:</th> 
        <td>@Model.Username 
         <!--edit fields--> 
         <div class="edit_field" id="field3"> 
          <label for="new_email">New Email:</label> 
          @Html.TextBoxFor(x => x.Username, new { id = "new_email" }) 
          <input type="submit" value="save" class="gradient-button" id="submit3"/> 
          <a href="#">Cancel</a> 
         </div> 
         <!--//edit fields--> 
        </td> 
        <td></td> 
       </tr> 
       <tr> 
        <th>First name:</th> 
        <td>@Model.FirstName 
         <!--edit fields--> 
         <div class="edit_field" id="field1"> 
          <label for="new_name">New First Name:</label> 
          @Html.TextBoxFor(x => x.FirstName, new { id = "new_name" }) 
          <input type="submit" value="save" class="gradient-button" id="submit1"/> 
          <a href="#">Cancel</a> 
         </div> 
         <!--//edit fields--> 
        </td> 
        <td><a href="#field1" class="gradient-button edit">Edit</a></td> 
       </tr> 
       <tr> 
        <th>Last name:</th> 
        <td>@Model.LastName 
         <!--edit fields--> 
         <div class="edit_field" id="field2"> 
          <label for="new_last_name">New Last Name:</label> 
          @Html.TextBoxFor(x => x.LastName, new { id = "new_last_name" }) 
          <input type="submit" value="save" class="gradient-button" id="submit2"/> 
          <a href="#">Cancel</a> 
         </div> 
         <!--//edit fields--> 
        </td> 
        <td><a href="#field2" class="gradient-button edit">Edit</a></td> 
       </tr> 
       <tr> 
        <th>Display name:</th> 
        <td>@Model.DisplayName 
         <!--edit fields--> 
         <div class="edit_field" id="field_display"> 
          <label for="new_display_name">New Display Name:</label> 
          @Html.TextBoxFor(x => x.DisplayName, new { id = "new_display_name" }) 
          <input type="submit" value="save" class="gradient-button" id="submit_display"/> 
          <a href="#">Cancel</a> 
         </div> 
         <!--//edit fields--> 
        </td> 
        <td><a href="#field_display" class="gradient-button edit">Edit</a></td> 
       </tr> 
       <tr> 
        <th>Password:</th> 
        <td><input type="password" value="@Model.Membership.Password" disabled="disabled" style="border: none; background-color: white; padding: 0;" /> 
         <!--edit fields--> 
         <div class="edit_field" id="field4"> 
          <label for="new_password">New Password:</label> 
          @Html.PasswordFor(x => x.Membership.Password, new { id = "new_password" }) 
          <input type="submit" value="save" class="gradient-button" id="submit4"/> 
          <a href="#">Cancel</a> 
         </div> 
         <!--//edit fields--> 
        </td> 
        <td></td> 
       </tr> 
       <tr> 
        <th>Cell phone:</th> 
        <td>@Model.CellPhone 
         <!--edit fields--> 
         <div class="edit_field" id="field_cell"> 
          <label for="new_cell">New Cell Phone:</label> 
          @Html.TextBoxFor(x => x.CellPhone, new { id = "new_cell" }) 
          <input type="submit" value="save" class="gradient-button" id="submit_cell"/> 
          <a href="#">Cancel</a> 
         </div> 
         <!--//edit fields--> 
        </td> 
        <td><a href="#field_cell" class="gradient-button edit">Edit</a></td> 
       </tr> 
       <tr> 
        <th>Home phone:</th> 
        <td>@Model.HomePhone 
         <!--edit fields--> 
         <div class="edit_field" id="field_home"> 
          <label for="new_home">New Home Phone:</label> 
          @Html.TextBoxFor(x => x.HomePhone, new { id = "new_home" }) 
          <input type="submit" value="save" class="gradient-button" id="submit_home"/> 
          <a href="#">Cancel</a> 
         </div> 
         <!--//edit fields--> 
        </td> 
        <td><a href="#field_home" class="gradient-button edit">Edit</a></td> 
       </tr> 
       <tr> 
        <th>Street Address:</th> 
        <td>@(Model.Address != null ? Model.Address.Address1 : "No address given") 
         <!--edit fields--> 
         <div class="edit_field" id="field5"> 
          <label for="new_address">New Address:</label> 
          @Html.TextBoxFor(x => x.Address.Address1, new { id = "new_address" }) 
          <input type="submit" value="save" class="gradient-button" id="submit5"/> 
          <a href="#">Cancel</a> 
         </div> 
         <!--//edit fields--> 
        </td> 
        <td><a href="#field5" class="gradient-button edit">Edit</a></td> 
       </tr> 

       <tr> 
        <th>Town/City:</th> 
        <td>@(Model.Address != null ? Model.Address.City.Name : "No address given") 
         <!--edit fields--> 
         <div class="edit_field" id="field6"> 
          <label for="new_city">New City:</label> 
          @Html.DropDownListFor(x => x.Address.CityId, Model.CitySelectList, new { @class = "f-item" }) 
          <input type="submit" value="save" class="gradient-button" id="submit6"/> 
          <a href="#">Cancel</a> 
         </div> 
         <!--//edit fields--> 
        </td> 
        <td><a href="#field6" class="gradient-button edit">Edit</a></td> 
       </tr> 

       <tr> 
        <th>Postal Code:</th> 
        <td>@(Model.Address != null ? Model.Address.PostalCode : "No address given") 
         <!--edit fields--> 
         <div class="edit_field" id="field7"> 
          <label for="new_zip">New Postal Code:</label> 
          @Html.TextBoxFor(x => x.Address.PostalCode, new { id = "new_zip" }) 
          <input type="submit" value="save" class="gradient-button" id="submit7"/> 
          <a href="#">Cancel</a> 
         </div> 
         <!--//edit fields--> 
        </td> 
        <td><a href="#field7" class="gradient-button edit">Edit</a></td> 
       </tr> 

       <tr> 
        <th>First Admin Division (State):</th> 
        <td>@(Model.Address != null ? Model.Address.City.FirstAdminDivision.Name : "No address given") 
         <!--edit fields--> 
         <div class="edit_field" id="field8"> 
          <label for="new_state">New First Admin Division (State):</label> 
          <input type="text" id="new_state"/> 
          <input type="submit" value="save" class="gradient-button" id="submit8"/> 
          <a href="#">Cancel</a> 
         </div> 
         <!--//edit fields--> 
        </td> 
        <td><a href="#field8" class="gradient-button edit">Edit</a></td> 
       </tr> 

       <tr> 
        <th>Country:</th> 
        <td>@(Model.Address != null ? Model.Address.City.FirstAdminDivision.Country.Name : "No address given") 
         <!--edit fields--> 
         <div class="edit_field" id="field9"> 
          <label for="new_country">New Country:</label> 
          <input type="text" id="new_country"/> 
          <input type="submit" value="save" class="gradient-button" id="submit9"/> 
          <a href="#">Cancel</a> 
         </div> 
         <!--//edit fields--> 
        </td> 
        <td><a href="#field8" class="gradient-button edit">Edit</a></td> 
       </tr> 
      </table> 

     </article> 
    } 

И действия два контроллера:

public ActionResult MyProfile() 
     { 
      IAccountService accountSvc = GetService<IAccountService>(); 
      UserProfileServiceRequest request = new UserProfileServiceRequest(); 

      int userId = int.Parse(SessionMgr.GetInstance().GetSessionValue(SessionTypes.UserId).ToString()); 

      if (userId == 0) 
      { 
       return RedirectToAction("Login", "Account"); 
      } 
      else 
      { 
       request.UserId = userId; 
       UserProfileServiceResponse response = accountSvc.GetUserProfile(request); 
       UserProfileViewModel model = AutoMapper.Mapper.Map<UserProfileViewModel>(response.UserProfile); 

       ICommonService commonSvc = GetService<ICommonService>(); 
       GetCitiesServiceRequest citiesRequest = new GetCitiesServiceRequest { FirstAdminDivisionId = model.Address.City.FirstAdminDivision.FirstAdminDivisionId }; 
       KeyValuePairServiceResponse citiesResponse = commonSvc.GetCitiesForSelect(citiesRequest); 
       model.CitySelectList = citiesResponse.KeyValuePairs.ToSelectList(); 

       List<RoleViewModel> roles = (List<RoleViewModel>)SessionMgr.GetInstance().GetSessionValue(SessionTypes.Roles); 
       RoleViewModel consumerRole = roles.FirstOrDefault(x => x.Meaning.Equals(DataEnumerations.GetRoleMeaning(DataEnumerations.Role.Consumer))); 

       if (consumerRole != null) 
       { 
        GetConsumerTripsServiceRequest consumerTripsRequest = new GetConsumerTripsServiceRequest() { UserId = userId }; 
        GetConsumerTripsServiceResponse consumerTripsResponse = commonSvc.GetConsumerTrips(consumerTripsRequest); 
        model.ConsumerTrips = AutoMapper.Mapper.Map<List<TripViewModel>>(consumerTripsResponse.Trips); 

        GetUserReviewsServiceRequest userReviewsRequest = new GetUserReviewsServiceRequest() { UserId = userId }; 
        GetUserReviewsServiceResponse userReviewsResponse = commonSvc.GetUserReviews(userReviewsRequest); 
        model.UserReviews = AutoMapper.Mapper.Map<List<UserReviewViewModel>>(userReviewsResponse.UserReviews); 
       } 

       return View(model); 
      } 
     } 

[HttpPost] 
     public ActionResult MyProfile(UserProfileViewModel model) 
     { 
      UpdateUserProfileServiceRequest request = AutoMapper.Mapper.Map<UpdateUserProfileServiceRequest>(model); 

      IAccountService accountSvc = GetService<IAccountService>(); 
      accountSvc.UpdateUserProfile(request); 

      return RedirectToAction("MyProfile", "Account"); 

     } 

Весь класс AddressViewModel:

public class AddressViewModel 
    { 
     public Int32 AddressId { get; set; } 
     public String Address1 { get; set; } 
     public String Address2 { get; set; } 
     public Int32 CityId { get; set; } 
     public String PostalCode { get; set; } 

     public CityViewModel City { get; set; } 

    } 

И весь UserProfileViewModel:

public class UserProfileViewModel : BaseViewModel 
    { 
     public int UserId { get; set; } 
     public string Username { get; set; } 
     public string FirstName { get; set; } 
     public string LastName { get; set; } 
     public string DisplayName { get; set; } 
     public string CellPhone { get; set; } 
     public string HomePhone { get; set; } 
     public int AddressId { get; set; } 

     public AddressViewModel Address { get; set; } 
     public MembershipViewModel Membership { get; set; } 

     public List<TripViewModel> ConsumerTrips { get; set; } 

     public List<UserReviewViewModel> UserReviews { get; set; } 

     public IEnumerable<SelectListItem> CitySelectList { get; set; } 
     public int SelectedCityId { get; set; } 
    } 
+0

То, что вы показали, отлично работает, поэтому я подозреваю, что вы опустили какой-то важный код (_ «упрощение некоторых для краткости» _) –

+0

«Краткость» действительно просто устраняла материал, который не касался адреса (минус код из самого представления). Я добавил все это сейчас, поэтому, если вы увидите что-нибудь, я бы очень признателен. Кажется, что он должен работать (я использовал подобный стиль раньше без проблем).Я надеялся, что это была одна из тех глупых ошибок с моей стороны, которые я мог видеть, так как я был так близко к коду. – user1011627

ответ

2

Ваша форма включает в себя скрытый вход для свойства в дополнение к выпадающий список

@Html.HiddenFor(x => x.Address.CityId) 
.... 
@Html.DropDownListFor(x => x.Address.CityId, Model.CitySelectList, ..) 

В действительности вы передаете назад 2 значения для того же свойства. DefaultModelBinder считывает первый (со скрытого ввода, который является исходным значением) и устанавливает значение Address.CityId. Любые последующие значения для одного и того же свойства (из раскрывающегося списка) игнорируются.

Удалите скрытый ввод, и ваша модель будет правильно связана с выбранным значением.

+0

Спасибо .... Я знал, что это было что-то глупое на моем конце, которого я просто не видел. – user1011627