ASP.Net MVC 2 - 模型绑定和字典

发布于 2024-09-03 02:40:49 字数 1379 浏览 8 评论 0原文

在我的界面中,我有一个文本框列表,如下所示: 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 是模板 ID,另一个是用户给出的计数。

这就是我想要的:

public ActionResult Save(int? id, Dictionary<int, int> countByTemplate)

我尝试了很多方法,但没有任何效果。我尝试阅读源代码,但它是一个迷宫,并且我在尝试获取有关模型绑定的信息时感到头疼。

问题:

  • 是否有关于模型绑定如何工作的良好资源? 我想要一些详尽的内容,我厌倦了谈论给定具体示例的 84093043 博客。
  • 我如何构建我的 HTML,使用它来获取 IDictionary (或者甚至在我的控制器操作中获取 IDictionary ?

非常感谢您的帮助

In my interface I have a list of text boxes, something like this :
http://screencast.com/t/YjIxNjUyNmU

The number of textboxes is unknown as each of them is associated with a Template.
In my page, the goal is to associate a number to some of those templates.

Here is a sample HTML code :

<%  // 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 />
<%  }
%>

What I expect, in my controller, is to get a IDictionary where the first int is the template ID , and the other is the count given by the user.

Here is what I want :

public ActionResult Save(int? id, Dictionary<int, int> countByTemplate)

I tried a lot of things but nothing worked. I tried to read the sources but it's a maze, and I'm getting a headhache trying to get information about model binding.

Questions :

  • is there a good ressource on how the modelbinding works ?
    I'd like someting exhaustive, I'm tired of the 84093043 blogs that talk about a given specific example.
  • how can I build my HTML, using to get a IDictionary (or even a IDictionary in my controller's action ?

Thanks a lot for your help

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

南…巷孤猫 2024-09-10 02:40:49

有关如何编写输入元素以绑定到数组、字典和其他集合的信息,请访问 http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

Information on how to write your input elements for binding to arrays, dictionaries, and other collections can be found at http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx.

十雾 2024-09-10 02:40:49

好吧……多亏了利维,我才找到了解决方案。
不是最干净的,但它确实有效。

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 被认为无效,因为“需要一个值”。我不希望我的值是必需的,但是查看 modelbinder 代码,我没有找到一种方法来告诉绑定器不需要值。

所以我欺骗了控制器中的 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 - 更好的字典模型绑定< ;int, int>

编辑 - 感谢 Pavel Chuchuva,有一个更干净的解决方案。

在控制器代码中,使用可为空的 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);
    }

Ok... Thanks to Levi I was able to get on a solution.
Not the cleaner one, but it works.

The HTML should be written this way:

<%
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 />
<%  }
%>

I had to add a hidden field to store the value.
I introduced a 'fake' counter just to loop over the dictionary the way ASP.Net MVC wants it.
As a result I got a dictionary filled with my values and '0' when the textbox is empty.

Another problem appeared: the ModelState was considered not valid because "a value is required". I don't want my values to be required, but looking at the modelbinder code, I did not found a way to tell the binder that a value is NOT required.

So I tricked the ModelState in my controller, removing all error, like this:

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();

Well... I effectively got a solution, but the HTML is kind of ugly now, and counterintuitive (using an index to loop over a non-indexed collection ??).
And I need to trick each time I'll use this kind of binding to have it all work properly.

So I will now open a new post to make dictionary binder something better.
Here it is: ASP.Net MVC 2 - better ModelBinding for Dictionary<int, int>

EDIT - There is a cleaner solution, thanks to Pavel Chuchuva.

In the controller code, use a nullable int as value for the dictionary.
A bit more code to add, but much cleaner.

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);
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文