В некоторых особых случаях вам понадобится список текстовых полей (для работы с n - n ассоциациями), чей идентификатор не известен до выполнения.
Примерно так: http://screencast.com/t/YjIxNjUyNmU
В этом конкретном примере я хочу связать счет с некоторыми из моих «шаблонов».
в ASP.Net MVC 1 Я закодировал словарь ModelBinder, чтобы иметь чистый и интуитивно понятный HTML.
Это позволило такие вещи:
// 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);
%>
<input type="text" id="<%= id %>" name="<%= id %>" value="<%= value %>" />
<label for="<%= id %>"><%= template.Name %></label>
<br />
Вот код связующего:
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
IDictionary<int, int> retour = new Dictionary<int, int>();
// get the values
var values = bindingContext.ValueProvider;
// get the model name
string modelname = bindingContext.ModelName + '_';
int skip = modelname.Length;
// loop on the keys
foreach(string keyStr in values.Keys)
{
// if an element has been identified
if(keyStr.StartsWith(modelname))
{
// get that key
int key;
if(Int32.TryParse(keyStr.Substring(skip), out key))
{
int value;
if(Int32.TryParse(values[keyStr].AttemptedValue, out value))
retour.Add(key, value);
}
}
}
return retour;
}
При переходе на ASP.Net MVC 2 проблема заключается в том, что ValueProvider больше не является словарем. Нет способа перебрать значения для их анализа, как я.
И я не нашел другого способа сделать это (если вы знаете один, скажите мне).
Я наконец переключился на «стандартный» способ привязки словаря, но HTML уродлив, контринтуитивен (использует счетчики для циклического перебора неиндексированной коллекции ??) и все значения требуются, в отличие от поведения, которое мне нужно (и это прекрасно работало в ASP.Net MVC 1).
Это выглядит так:
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 />
В контроллере мне нужно обмануть 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();
Это слишком сложно.
Вскоре мне понадобится многократно использовать этот тип привязки, и, возможно, разработчик приложения поработает над приложением.
Вопрос:
- Знаете ли вы, как сделать это лучше?
Что мне нужно, IMO, это ModelBinder для словаря, который позволяет лучше HTML и не учитывает, что все значения требуются.