2011-03-23 16 views
1

我目前可以使用以下模型註釋,視圖模型和自定義編輯器模板來填充和顯示下拉菜單 - 但是存在問題持續提交低於更多):使用MVC存儲SelectList ID的問題EditFor模板和註釋(.net 4,mvc3)

//Domain 
Public class Person 
{ 
    public string FirstName {get;set;} 
    public string LastName {get;set;} 
    public string ClassName {get;set;} 
    public int ClassId {get;set;} 
    ... 
} 

//ViewModel 
Public class PersonViewModel 
{ 
    public Person Person {get;set;} 
    [UIHint("SelectList")] 
    public IEnumerable<SelectListItems> Classes {get;set;} 

    public PersonViewModel 
    { 
    Person = new Person(); 
    } 
} 

//Controller 
public ActionResult Create() 
{ 
    var PersonViewModel = new PersonViewModel(); 
    _PersonService.PopulateClassList(PersonViewModel); 
    return View("Create", PersonViewModel); 
} 

[HttpPost] 
public ActionResult Create(PersonViewModel PersonViewModel) 
{ 
try 
    { 
    if (!ModelState.IsValid) 
    { 
    _PersonService.PopulateClassList(PersonViewModel); 
    return View("Create", PersonViewModel); 
    } 

    var Person = new Person(); 
    Person.InjectFrom(PersonViewModel.Person);  
    _PersonService.Save(Person); 

    return RedirectToAction("Index"); 
} 
catch 
{ 
    return View(); 
} 
} 

//View (just the pertinent part) 
@Html.EditorFor(m => m.Classes)<br /> 
@Html.EditorFor(m => m.Person) 

自動使用下面的模板 - 由於視圖模型註釋

// Views/Shared/EditorTemplates/SelectList.cshtml 
@model IEnumerable<SelectListItem> 
@Html.DropDownListFor(m => m, Model) 

就像我提到的,以上工作正常 - 因爲在下拉顯示正常,但顯然在目前的狀態下不把classID(或名稱)保存到Person實體,我理解這個問題,但不知道如何解決它。

我的問題:

  1. 我怎樣才能從下拉保存選擇的值下降到Person實體

  2. 我怎樣才能節省的ID和名稱到Person實體 - 我猜只有一個方法是一個隱藏的字段,它會被一個onchange事件填充(這聽起來很奇怪,我敢肯定,但它存儲在一個文檔數據庫中,所以它沒有被標準化 - 我可能只是將Name存儲在最後)

在此先感謝! 邁克

回答

3

我認爲在你的視圖模型,你需要改變你的代碼,使類是

IEnumerable<SelectListItem> 

<SelectListItems>,你就需要添加一個字段中選擇的項目。

Public class PersonViewModel 
{ 
    public Person Person {get;set;} 
    public IEnumerable<SelectListItem> Classes {get;set;} 
    public string SelectedClassId {get; set;} 
} 

然後你可以在你的視圖中使用這樣的代碼來填充下拉菜單。

@Html.DropDownListFor(x => x.SelectedClassId, Model.Classes, new { id = "classSelect" }) 

[編輯]

我看着你實際上在做什麼一點點接近,它看起來像你創建一個表單到一個新的人輸入信息,然後選擇一個類人,然後將創建新的人並堅持他們。

首先,您不應該將您的PersonViewModel傳遞給您的服務。視圖模型不是您的域的一部分。它應該用於促進View和Controller之間的通信。

其次,由於您還沒有Person,您的_PersonService.PopulateClassList()方法應該看起來更像這樣。

public IQueryable<Class> GetClasses() 
{ 
    //Data access logic 
    //return classes .AsQueryable() 
} 

這樣,您可以在需要時獲得類的列表。你的控制器會看起來像這樣。

[HttpPost] 
public ActionResult Create(PersonViewModel model) 
{ 
    try 
    { 
     if (!ModelState.IsValid) 
     { 
      model.Classes = _PersonService.GetClasses().Select(c => new SelectListItem 
                   { 
                    Text = c.Name, 
                    Value = "" + c.Id 
                   }; 
      return View("Create", PersonViewModel); 
     } 
      model.Person.ClassId = model.SelectedClassId; 
      //You can ditch ClassName since you'll just look it up by ID 
      _PersonService.Save(model.Person); 
      return RedirectToAction("Index"); 
} 

[在回答您的問題]

如果你想獲得選擇列表的邏輯移出控制器,你可以修改屬性在模型中是這個樣子。

Public class PersonViewModel 
{ 
    public Person Person {get;set;} 
    public string SelectedClassId {get; set;} 
    public IEnumerable<SelectListItem> Classes 
    { 
     get 
     { return _PersonService.GetClasses().Select(c => new SelectListItem 
                  { 
                   Text = c.Name, 
                   Value = "" + c.Id 
                  }; 
     } 
    } 
} 

這將訪問該服務時,該屬性被讀取。我記不得了,但你可能需要在最後調用.AsEnumerable()。

我目前正在使用下拉框來查看是否可以綁定到模型中的複雜對象。更多來。

[繼續]

是可以下拉值直接綁定到模型中的人的CLASSID屬性。我能夠在我的模型/視圖中使用下面的代碼。我的Person和Class對象可能與您的並不完全相同,但您會明白。我不確定你的域名,但是如果一個類可以在沒有人的情況下存在,那麼將它們的數據訪問邏輯分隔成一個PersonRepository和一個ClassRepository(或PersonService等)可能更有意義。 ),但是我會給你留下領域類型的想法。

型號

using System; 
    using System.Collections.Generic; 
    using System.Linq; 
    using System.Web; 
    using DropDownTest.Classes; 
    using System.Web.Mvc; 

    namespace DropDownTest.Models 
    { 
     public class PersonViewModel 
     { 
      private ClassRepository _classRepository = new ClassRepository(); 

      public Person Person { get; set; } 
      public IEnumerable<SelectListItem> Classes 
      { 
       get 
       { 
        return _classRepository.GetClasses().Select(c => new SelectListItem 
                   { 
                    Text = c.Name, 
                    Value = "" + c.ClassId 
                   }); 
       } 
      } 
     } 
    } 

查看

@model DropDownTest.Models.PersonViewModel 

@{ 
    ViewBag.Title = "Create"; 
} 

<h2>Create</h2> 

@using (Html.BeginForm("Create", "Person", FormMethod.Post)) 
{ 
    <fieldset> 
     <legend>New Person</legend> 
     @Html.LabelFor(c => c.Person.FirstName) 
     @Html.TextBoxFor(c => c.Person.FirstName) 
     <br /> 

     @Html.LabelFor(c => c.Person.LastName) 
     @Html.TextBoxFor(c => c.Person.LastName) 
     <br /> 

     @Html.LabelFor(c => c.Person.ClassId) 
     @Html.DropDownListFor(c => c.Person.ClassId, Model.Classes, new { id = "classSelect" }) 
     <input type="submit" value="submit" /> 
    </fieldset> 
} 

類信息庫(認爲它是在這種情況下,服務) 這顯然是僞造的,但如果你使用抽象存儲庫,你可以在單元測試中使用類似的東西,並使用真正的存儲庫用於生產只要實現了IClassRepository並且你使用了某種類型的依賴注入(DI) - 就像Ninject一樣 - 但這是一個完全不同的主題:)。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 

namespace DropDownTest.Classes 
{ 
    public class ClassRepository 
    { 
     private static IQueryable<Class> _classes = new List<Class> 
     { 
      new Class { ClassId = 0, Name = "Class 0" }, 
      new Class { ClassId = 1, Name = "Class 1" }, 
      new Class { ClassId = 2, Name = "Class 2" } 
     }.AsQueryable(); 

     public IQueryable<Class> GetClasses() 
     { 
      return _classes; 
     } 
    } 
} 
+0

@GregB感謝您的建議,我不太確定我是否做得正確。也就是說,我有很多下拉菜單和其他邏輯,如果我將它們全部放在控制器上,它會變得笨重,我想避免。這就是爲什麼我認爲在服務層做所有這些都是一個好主意,但是你說這不是什麼?你會建議創建一個'builder'類,我可以實例化並從控制器傳遞一個視圖模型來完成所有這些? – Mikalee 2011-03-25 16:22:41

+0

@GregB同樣,關於您給出的下拉代碼「@ Html.DropDownListFor(x => x.SelectedClassId,Model.Classes,new {id =」classSelect「})」,我想將該值插入Person viewModel中嵌入Person的.ClassId,而不是在viewmodel中創建ClassId,這可能嗎?再次感謝。 – Mikalee 2011-03-25 16:25:58

+0

@Mikalee我不認爲在服務層創建下拉列表是有意義的,因爲下拉列表只在視圖的上下文中才有意義。如果你在服務層實現了一個返回一堆SelectListItems的方法,但是隻想在另一個視圖中列出所有的類,那麼你必須編寫一個全新的方法來實現這一點。更好地保持服務層專注於數據訪問,並擔心控制器中的格式化。如果你真的想把邏輯從控制器中拿出來,你可以把它放在模型中。我會編輯我的答案,告訴你如何。 – GregB 2011-03-25 20:49:08