다음 뷰 모델이 있습니다.
public class ProjectVM
{
....
[Display(Name = "Category")]
[Required(ErrorMessage = "Please select a category")]
public int CategoryID { get; set; }
public IEnumerable<SelectListItem> CategoryList { get; set; }
....
}
다음 컨트롤러 메서드를 사용하여 새 프로젝트를 만들고 Category
public ActionResult Create()
{
ProjectVM model = new ProjectVM
{
CategoryList = new SelectList(db.Categories, "ID", "Name")
}
return View(model);
}
public ActionResult Create(ProjectVM model)
{
if (!ModelState.IsValid)
{
return View(model);
}
// Save and redirect
}
그리고보기에서
@model ProjectVM
....
@using (Html.BeginForm())
{
....
@Html.LabelFor(m => m.CategoryID)
@Html.DropDownListFor(m => m.CategoryID, Model.CategoryList, "-Please select-")
@Html.ValidationMessageFor(m => m.CategoryID)
....
<input type="submit" value="Create" />
}
보기가 올바르게 표시되지만 양식을 제출할 때 다음 오류 메시지가 표시됩니다.
InvalidOperationException : ‘CategoryID’키가있는 ViewData 항목은 ‘System.Int32’형식이지만 ‘IEnumerable <SelectListItem>’형식이어야합니다.
@Html.DropDownList()
메서드를 사용하여 동일한 오류가 발생 하고 ViewBag
또는을 사용하여 SelectList를 전달하면 ViewData
.
답변
오류는의 값 CategoryList
이 null 임을 의미합니다 (결과적으로 DropDownListFor()
메서드는 첫 번째 매개 변수가 유형 인 것으로 예상합니다 IEnumerable<SelectListItem>
).
각 각 속성에 대한 입력을 생성하지 SelectListItem
에 CategoryList
(그리고 없으며해야한다)에 대한 값이되도록 SelectList
제어부 방법으로 전기 없으며, 따라서의 값이된다 model.CategoryList
POST 메소드이다에서 null
. 뷰를 반환하는 경우 CategoryList
GET 메서드에서와 마찬가지로 먼저의 값을 다시 할당해야합니다 .
public ActionResult Create(ProjectVM model)
{
if (!ModelState.IsValid)
{
model.CategoryList = new SelectList(db.Categories, "ID", "Name"); // add this
return View(model);
}
// Save and redirect
}
내부 작동을 설명하기 위해 (소스 코드는 여기에서 볼 수 있습니다 )
각 오버로드 DropDownList()
및 DropDownListFor()
결국 다음 메서드를 호출합니다.
private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, ModelMetadata metadata,
string optionLabel, string name, IEnumerable<SelectListItem> selectList, bool allowMultiple,
IDictionary<string, object> htmlAttributes)
체크되는 경우, selectList
(두 번째 파라미터는 @Html.DropDownListFor()
) 인null
// If we got a null selectList, try to use ViewData to get the list of items.
if (selectList == null)
{
selectList = htmlHelper.GetSelectData(name);
usedViewData = true;
}
차례로 전화
private static IEnumerable<SelectListItem> GetSelectData(this HtmlHelper htmlHelper, string name)
@Html.DropDownListFor()
(이 경우 CategoryID
) 의 첫 번째 매개 변수를 평가합니다.
....
o = htmlHelper.ViewData.Eval(name);
....
IEnumerable<SelectListItem> selectList = o as IEnumerable<SelectListItem>;
if (selectList == null)
{
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
MvcResources.HtmlHelper_WrongSelectDataType,
name, o.GetType().FullName, "IEnumerable<SelectListItem>"));
}
속성 CategoryID
이 typeof 이므로 int
캐스트 할 수없고 IEnumerable<SelectListItem>
예외가 throw됩니다 ( MvcResources.resx
파일에 다음과 같이 정의 됨).
<data name="HtmlHelper_WrongSelectDataType" xml:space="preserve">
<value>The ViewData item that has the key '{0}' is of type '{1}' but must be of type '{2}'.</value>
</data>
답변
stephens (user3559349) 답변에 따르면 이것은 유용 할 수 있습니다.
@Html.DropDownListFor(m => m.CategoryID, Model.CategoryList ?? new List<SelectListItem>(), "-Please select-")
또는 ProjectVM에서 :
public class ProjectVM
{
public ProjectVM()
{
CategoryList = new List<SelectListItem>();
}
...
}
답변
페이지로 리디렉션되는 오류와 모델의 드롭 다운 목록을 다시 초기화하지 않을 가능성이 가장 높습니다.
모델의 생성자에서 또는 해당 모델을 페이지로 보내기 전에 매번 드롭 다운을 초기화해야합니다.
그렇지 않으면 뷰 백이나 숨겨진 값 도우미를 통해 드롭 다운 목록의 상태를 유지해야합니다.
답변
나는 같은 문제가 있었고, 양식을 게시하려고 할 때 잘못된 ModelState가 발생했습니다. 나를 위해 이것은 CategoryId를 int로 설정했기 때문에 발생했습니다. 문자열로 변경했을 때 ModelState가 유효하고 Create 메서드가 예상대로 작동했습니다.
답변
좋습니다. 포스터의 미리 준비된 답변 은 오류가 발생한 이유를 깔끔하게 설명 했지만 작동 방법은 설명 하지 않았습니다. 그게 정말 답인지는 모르겠지만 올바른 방향으로 안내해주었습니다.
나는 같은 문제에 부딪 쳤고 그것을 해결할 수있는 매끄러운 방법을 찾았다. 여기에서 캡처 해 보겠습니다. 면책 조항-1 년에 한 번 정도 웹 페이지에서 작업하며 대부분의 시간 동안 무엇을하는지 잘 모르겠습니다. 이 답변은 “전문가”답변으로 간주되어서는 안되지만 작업이 거의 수행되지 않습니다.
드롭 다운 목록을 사용하여 필드에 유효한 값을 제공하려는 데이터 개체 (대부분 데이터 전송 개체)가 있다는 점을 감안하면 다음과 같습니다.
public class MyDataObject
{
public int id;
public string StrValue;
}
그러면 ViewModel은 다음과 같습니다.
public class MyDataObjectVM
{
public int id;
public string StrValue;
public List<SectListItem> strValues;
}
여기서 진짜 문제는 @Stephen이 위에서 설명한 것처럼 컨트롤러의 POST 메서드에 선택 목록이 채워지지 않는다는 것입니다. 따라서 컨트롤러 메서드는 다음과 같습니다.
// GET
public ActionResult Create()
{
var dataObjectVM = GetNewMyDataObjectVM();
return View(dataObjectVM); // I use T4MVC, don't you?
}
private MyDataObjectVM GetNewMyDataObjectVM(MyDataObjectVM model = null)
{
return new MyDataObjectVM
{
int id = model?.Id ?? 0,
string StrValue = model?.StrValue ?? "",
var strValues = new List<SelectListItem>
{
new SelectListItem {Text = "Select", Value = ""},
new SelectListITem {Text = "Item1", Value = "Item1"},
new SelectListItem {Text = "Item2", Value = "Item2"}
};
};
}
// POST
public ActionResult Create(FormCollection formValues)
{
var dataObject = new MyDataObject();
try
{
UpdateModel(dataObject, formValues);
AddObjectToObjectStore(dataObject);
return RedirectToAction(Actions.Index);
}
catch (Exception ex)
{
// fill in the drop-down list for the view model
var dataObjectVM = GetNewMyDataObjectVM();
ModelState.AddModelError("", ex.Message);
return View(dataObjectVM);
)
}
거기에 있습니다. 이것은 작동하는 코드가 아니며 복사 / 붙여 넣기 및 편집하여 간단하게 만들었지 만 아이디어를 얻었습니다. 원본 데이터 모델과 파생 된 뷰 모델의 데이터 멤버가 같은 이름을 가진 경우 UpdateModel ()은 FormCollection 값에서 올바른 데이터를 채우는 멋진 작업을 수행합니다.
필연적으로이 문제가 다시 발생할 때 답을 찾을 수 있도록 여기에 게시하고 있습니다. 다른 사람에게도 도움이되기를 바랍니다.
답변
제 경우에는 목록의 첫 번째 ID가 0이었고 ID를 1에서 시작하도록 변경하면 작동했습니다.