ASP.Net MVC 2 - привязка модели и словарь<int, int>
В моем интерфейсе у меня есть список текстовых полей, что-то вроде этого: http://screencast.com/t/YjIxNjUyNmU
Количество текстовых полей неизвестно, так как каждое из них связано с шаблоном. На моей странице цель состоит в том, чтобы связать число с некоторыми из этих шаблонов.
Вот пример кода HTML:
<% // loop on the templates
foreach(ITemplate template in templates)
{
// get the content from the input dictionary
int val;
content.TryGetValue(template.Id, out val);
// convert it as a string
string value = ((val > 0) ? val.ToString() : string.Empty);
// compute the element name/id (for dictionary binding)
string id = ??????????
string name = ??????????????
%>
<label for="<%= name %>"><%= template.Name %></label>
<input type="text" id="<%= id %>" name="<%= name %>" value="<%= value %>" />
<br />
<% }
%>
В моем контроллере я ожидаю получить IDictionary, где первое int - это идентификатор шаблона, а другое - количество, указанное пользователем.
Вот что я хочу:
public ActionResult Save(int? id, Dictionary<int, int> countByTemplate)
Я много чего перепробовал, но ничего не получалось. Я пытался прочитать источники, но это лабиринт, и у меня болит голова, пытаясь получить информацию о привязке модели.
Вопросы:
- Есть ли хороший ресурс о том, как работает связывание моделей? Я хотел бы получить исчерпывающий, я устал от блогов 84093043, которые говорят о данном конкретном примере.
- Как я могу построить свой HTML, используя для получения IDictionary (или даже IDictionary в действии моего контроллера?
Большое спасибо за вашу помощь
2 ответа
Хорошо... Благодаря Леви я смог найти решение. Не чище, но это работает.
HTML должен быть написан так:
<%
int counter = 0;
// loop on the templates
foreach(ITemplate template in templates)
{
// get the value as text
int val;
content.TryGetValue(template.Id, out val);
var value = ((val > 0) ? val.ToString() : string.Empty);
// compute the element name (for dictionary binding)
string id = "cbts_{0}".FormatMe(template.Id);
string dictKey = "cbts[{0}].Key".FormatMe(counter);
string dictValue = "cbts[{0}].Value".FormatMe(counter++);
%>
<input type="hidden" name="<%= dictKey %>" value="<%= template.Id %>" />
<input type="text" id="<%= id %>" name="<%= dictValue %>" value="<%= value %>" />
<label for="<%= id %>"><%= template.Name %></label>
<br />
<% }
%>
Мне пришлось добавить скрытое поле для хранения значения. Я ввел "фальшивый" счетчик, чтобы просто перебрать словарь так, как этого хочет ASP.Net MVC. В результате я получил словарь, заполненный моими значениями и "0", когда текстовое поле пусто.
Появилась еще одна проблема: ModelState
был признан недействительным, потому что "значение требуется". Я не хочу, чтобы мои значения были обязательными, но, глядя на код связывателя модели, я не нашел способа сказать связующему, что значение НЕ требуется.
Так что я обманул ModelState
в моем контроллере, удалив все ошибки, вот так:
public ActionResult Save(int? id, Dictionary<int, int> cbts)
{
// clear all errors from the modelstate
foreach(var value in this.ModelState.Values)
value.Errors.Clear();
Ну... я действительно нашел решение, но HTML теперь уродлив и контринтуитивен (используя индекс для циклического перемещения по неиндексированной коллекции??). И мне нужно обманывать каждый раз, когда я буду использовать этот вид привязки, чтобы все это работало должным образом.
Так что теперь я открою новый пост, чтобы сделать словарь лучше. Вот оно: ASP.Net MVC 2 - лучшее связывание моделей для словаря
РЕДАКТИРОВАТЬ - Есть более чистое решение, благодаря Павлу Чучува.
В коде контроллера используйте значение nullable int в качестве значения для словаря. Немного больше кода, чтобы добавить, но намного чище.
public ActionResult Save(int? id, Dictionary<int, int?> cbts)
{
// this is our final dictionary<int, int>
Dictionary<int, int> cbtsFinal = new Dictionary<int, int>();
// loop on the dicitonary with nullable values
foreach(var key in cbts.Keys)
{
// if we have a value
if(cbts[key].HasValue)
// then put it in the final dictionary
cbtsFinal.Add(key, cbts[key].Value);
}
Информацию о том, как записать элементы ввода для привязки к массивам, словарям и другим коллекциям, можно найти по адресу http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx.