DropDownListFor 未绑定到具有重复项目的编辑视图 (List)

发布于 2024-09-14 16:03:38 字数 5536 浏览 4 评论 0原文

事情是这样的。我有一个编辑视图,当我打开它时,它不会绑定下拉列表的值。

    [NonAction]
    public List<SelectListItem> VraagType() {
        List<SelectListItem> l = new List<SelectListItem>();
        SelectListItem a = new SelectListItem();
        SelectListItem b = new SelectListItem();

        a.Text = "Meerkeuze";
        a.Value = "M";

        b.Text = "Open";
        b.Value = "O";

        l.Add(a);
        l.Add(b);

        return l;
    }

    [NonAction]
    public List<SelectListItem> getSchalen() {
        return _db.EvalSchaals.ToList().ToSelectList(q => q.Sch_Naam, q => q.Sch_ID.ToString(), q => q.Sch_ID == -1).ToList();
    }

    public ActionResult Edit(int id) {
        ViewData["vraagtype"] = VraagType();
        ViewData["schaal"] = getSchalen();

        EvalVragenBlok evb = _db.EvalVragenBloks.First(q => q.Vrbl_ID == id);
        List<EvalVragen> ev = _db.EvalVragens.Where(q => q.Vrbl_ID == id).ToList();

        FlatEvalVragenBlok fevb = Mapper.Map<EvalVragenBlok, FlatEvalVragenBlok>(evb);
        fevb.Vragen = new List<FlatEvalVragen>();

        return View(fevb);
    }

这是来自控制器的代码。

这是来自 Edit.aspx 视图的代码,

        <h2>
            Edit</h2>
        <% using (Html.BeginForm()) {%>
        <%: Html.ValidationSummary(true) %>
        <fieldset>
            <legend>Fields</legend>
    <legend>Fields</legend>
            <div class="editor-label">
                <%: Html.LabelFor(model => model.Vrbl_Titel) %>
            </div>
            <div class="editor-field">
                <%: Html.TextBoxFor(model => model.Vrbl_Titel) %>
                <%: Html.ValidationMessageFor(model => model.Vrbl_Titel) %>
            </div>
            <div class="editor-label">
                <%: Html.LabelFor(model => model.Sch_ID) %>
            </div>
            <div class="editor-field">
                <%: Html.DropDownListFor(model => model.Sch_ID, ViewData["schaal"] as List<SelectListItem>, "Selecteer een schaal...") %>
                <%: Html.ValidationMessageFor(model => model.Sch_ID) %>
            </div>
            <%= Html.ValidationMessageFor(model => model.Vragen) %>
            <table id="vragentbl">
                <tr>
                    <th>
                    </th>
                    <th>
                        Vraag
                    </th>
                    <th>
                        Soort
                    </th>
                </tr>
                <% if (Model.Vragen != null) { %>
                <% for (int i = 0; i < Model.Vragen.Count; i++) {  %>
                <tr>
                    <td>
                        <%=i + 1%>
                    </td>
                    <td>
                        <%= Html.TextBoxFor(model => model.Vragen[i].Evvr_Vraag, new { style = "width:400px" })%><br />
                        <%= Html.ValidationMessageFor(model => model.Vragen[i].Evvr_Vraag)%>
                    </td>
                    <td>
                        <%= Html.DropDownListFor(model => model.Vragen[i].Evvr_Type, ViewData["vraagtype"] as List<SelectListItem>, new { style = "width:95px" })%><br />
                        <%= Html.ValidationMessageFor(model => model.Vragen[i].Evvr_Type)%>
                    </td>
                </tr>
                <% }
                   } %>
                <tr>
                    <td>
                    </td>
                    <td>
                        <a id="addnew" href="#">Voeg extra keuze toe</a>
                    </td>
                    <td>
                    </td>
                </tr>
            </table>
            <p>
                <input type="submit" value="Save" />
            </p>
        </fieldset>
        <% } %>

我有 2 个 List 。其中 1 个位于表单的非重复部分(Schalen),另一个(VraagType)位于重复部分内。

对于沙伦来说,一切都很顺利。我打开编辑视图,所有字段都按应有的方式填写。 Vrbl_Titel 有它的值,Sch_ID 的下拉列表有它从我随视图发送的对象接收的值,该对象来自数据库。

问题出在重复部分。 model.Vragen[i].Evvr_Vraag 的文本框获取其值,并显示 model.Vragen[i].Evvr_Type 的下拉列表,但是,此下拉列表获取发送的值物体。它保留了默认的标准值,这是“选择列表”中的第一项,

我如何从“Vragen”对象中获取我的值,进入下拉列表。如果我将值放入一个简单的文本框中

<%= Html.TextBoxFor(model => model.Vragen[i].Evvr_Type)%>

,那么文本框就会获取该值。所以问题是下拉值不会改变它的初始值... MVC 中的错误?

仅供参考,这是对象发送到视图的方式:

        namespace MVC2_NASTEST.Models {

            public partial class FlatEvalVragenBlok {
                public int Vrbl_ID { get; set; }
                public int Sch_ID { get; set; }
                public string Vrbl_Titel { get; set; }
                public List<FlatEvalVragen> Vragen { get; set; }
            }
        }

        namespace MVC2_NASTEST.Models {

            public partial class FlatEvalVragen {
                public int Evvr_ID { get; set; }
                public int Vrbl_ID { get; set; }
                public int Evvr_rang { get; set; }
                public string Evvr_Vraag { get; set; }
                public char Evvr_Type { get; set; }
            }
        }

Here is the thing. I have an Edit view, which doesnt bind the dropdowns' value when I open it.

    [NonAction]
    public List<SelectListItem> VraagType() {
        List<SelectListItem> l = new List<SelectListItem>();
        SelectListItem a = new SelectListItem();
        SelectListItem b = new SelectListItem();

        a.Text = "Meerkeuze";
        a.Value = "M";

        b.Text = "Open";
        b.Value = "O";

        l.Add(a);
        l.Add(b);

        return l;
    }

    [NonAction]
    public List<SelectListItem> getSchalen() {
        return _db.EvalSchaals.ToList().ToSelectList(q => q.Sch_Naam, q => q.Sch_ID.ToString(), q => q.Sch_ID == -1).ToList();
    }

    public ActionResult Edit(int id) {
        ViewData["vraagtype"] = VraagType();
        ViewData["schaal"] = getSchalen();

        EvalVragenBlok evb = _db.EvalVragenBloks.First(q => q.Vrbl_ID == id);
        List<EvalVragen> ev = _db.EvalVragens.Where(q => q.Vrbl_ID == id).ToList();

        FlatEvalVragenBlok fevb = Mapper.Map<EvalVragenBlok, FlatEvalVragenBlok>(evb);
        fevb.Vragen = new List<FlatEvalVragen>();

        return View(fevb);
    }

this is the code from the controller.

here is the code from the Edit.aspx view

        <h2>
            Edit</h2>
        <% using (Html.BeginForm()) {%>
        <%: Html.ValidationSummary(true) %>
        <fieldset>
            <legend>Fields</legend>
    <legend>Fields</legend>
            <div class="editor-label">
                <%: Html.LabelFor(model => model.Vrbl_Titel) %>
            </div>
            <div class="editor-field">
                <%: Html.TextBoxFor(model => model.Vrbl_Titel) %>
                <%: Html.ValidationMessageFor(model => model.Vrbl_Titel) %>
            </div>
            <div class="editor-label">
                <%: Html.LabelFor(model => model.Sch_ID) %>
            </div>
            <div class="editor-field">
                <%: Html.DropDownListFor(model => model.Sch_ID, ViewData["schaal"] as List<SelectListItem>, "Selecteer een schaal...") %>
                <%: Html.ValidationMessageFor(model => model.Sch_ID) %>
            </div>
            <%= Html.ValidationMessageFor(model => model.Vragen) %>
            <table id="vragentbl">
                <tr>
                    <th>
                    </th>
                    <th>
                        Vraag
                    </th>
                    <th>
                        Soort
                    </th>
                </tr>
                <% if (Model.Vragen != null) { %>
                <% for (int i = 0; i < Model.Vragen.Count; i++) {  %>
                <tr>
                    <td>
                        <%=i + 1%>
                    </td>
                    <td>
                        <%= Html.TextBoxFor(model => model.Vragen[i].Evvr_Vraag, new { style = "width:400px" })%><br />
                        <%= Html.ValidationMessageFor(model => model.Vragen[i].Evvr_Vraag)%>
                    </td>
                    <td>
                        <%= Html.DropDownListFor(model => model.Vragen[i].Evvr_Type, ViewData["vraagtype"] as List<SelectListItem>, new { style = "width:95px" })%><br />
                        <%= Html.ValidationMessageFor(model => model.Vragen[i].Evvr_Type)%>
                    </td>
                </tr>
                <% }
                   } %>
                <tr>
                    <td>
                    </td>
                    <td>
                        <a id="addnew" href="#">Voeg extra keuze toe</a>
                    </td>
                    <td>
                    </td>
                </tr>
            </table>
            <p>
                <input type="submit" value="Save" />
            </p>
        </fieldset>
        <% } %>

I have 2 List 's. 1 of them is in the non-repeating part of the form (Schalen), the other one (VraagType) is Inside the repeating part.

for Schalen, everything works fine. i open the edit view, and all fields are filled in like it should be. the Vrbl_Titel has its value, and the dropdown of Sch_ID has the value it received from the object which i sent with the view, which came from the DB.

The problem lies in the repeating part.
the textbox for model.Vragen[i].Evvr_Vraag get's its value, and the dropdown for model.Vragen[i].Evvr_Type is shown, however, this dropdown does not get the value which was sent in the object. it keeps it's default standard value, which is the first item in the 'selectlist'

how do i get my value from my 'Vragen' object, into the dropdown. if i put the value in a simple textbox

<%= Html.TextBoxFor(model => model.Vragen[i].Evvr_Type)%>

then the textbox does get the value. so the problem is that the dropdownvalue doesnt change form it's initial value... bug in MVC?

just for info, this is how the object(s) look sent to the view:

        namespace MVC2_NASTEST.Models {

            public partial class FlatEvalVragenBlok {
                public int Vrbl_ID { get; set; }
                public int Sch_ID { get; set; }
                public string Vrbl_Titel { get; set; }
                public List<FlatEvalVragen> Vragen { get; set; }
            }
        }

        namespace MVC2_NASTEST.Models {

            public partial class FlatEvalVragen {
                public int Evvr_ID { get; set; }
                public int Vrbl_ID { get; set; }
                public int Evvr_rang { get; set; }
                public string Evvr_Vraag { get; set; }
                public char Evvr_Type { get; set; }
            }
        }

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

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

发布评论

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

评论(1

终难遇 2024-09-21 16:03:38

看来这确实是一个错误,或者至少是 ASP.NET MVC 2 中的不一致。我检查了它的源代码,发现从 TextBoxFor() 帮助器调用的 InputHelper() 方法接收使用

ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData).Model

从 DropDownListFor( 调用的 But SelectInternal() 方法计算的默认值) ) 帮助程序仅接收使用 ExpressionHelper.GetExpressionText() 方法找到的控件的名称。

因此 SelectInternal() 尝试使用 MVC 1 中的 ViewData.Eval() 方法查找默认值。众所周知,该方法无法通过数字索引从数组中提取值。

所以在你的情况下是适用的,

<%: Html.DropDownListFor(model => model.Sch_ID) %>
<%= Html.TextBoxFor(model => model.Vragen[i].Evvr_Type)%>

但不是

<%: Html.DropDownListFor(model => model.Vragen[i].Evvr_Type) %>

因为它相当于

<%: Html.DropDownList("Vragen[" + i + "].Evvr_Type") %>

同时我想再次强调什么

<%= Html.TextBoxFor(model => model.Vragen[i].Evvr_Type)%>

不相当于

<%= Html.TextBox("model.Vragen[" + i + "].Evvr_Type")%>

因为后者即使在 MVC 2 中也不能绑定默认值。

可能的解决方法

首先。由于 SelectInternal() 还会检查 ModelState 字典,因此您可以在返回视图之前填充此字典。

for (int i=0; i < fevb.Vragen.Count(); i++)
    ModelState.Add("Vragen[" + i + "].Evvr_Type", new ModelState
    {
        Value = new ValueProviderResult(fevb.Vragen[i].Evvr_Type, null, 
            CultureInfo.CurrentCulture) 
    });

这将由 MVC 本身在发布后完成,因此您应该仅在第一次手动执行此操作。

第二。 而是

<%= Html.DropDownListFor(model => model.Vragen[i].Evvr_Type, 
    ViewData["vraagtype"] as List<SelectListItem>)%>

使用

<%= Html.DropDownListFor(model => model.Vragen[i].Evvr_Type, 
    new SelectList(ViewData["vraagtype"] as IEnumerable, "Value", "Text",
        Model.Vragen[i].Evvr_Type))%>

在这种情况下,不必包含 SelectListItem 的对象, ViewData["vraagt​​ype"] ,任何 IEnumerable 就足够了。如果需要,您可以查看 SelectList() 方法的说明。

It seems this is really a bug or at least inconsistency in ASP.NET MVC 2. I have examined its source and found what InputHelper() method called from TextBoxFor() helper receives default value calculated with

ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData).Model

But SelectInternal() method called from DropDownListFor() helper receives only a name of a control found with ExpressionHelper.GetExpressionText() method.

So SelectInternal() tries to find default value using ViewData.Eval() method from MVC 1. It's known what this method isn't able to extract values from arrays by numeric index.

So in your case are applicable

<%: Html.DropDownListFor(model => model.Sch_ID) %>
<%= Html.TextBoxFor(model => model.Vragen[i].Evvr_Type)%>

but not

<%: Html.DropDownListFor(model => model.Vragen[i].Evvr_Type) %>

because it's equivalent to

<%: Html.DropDownList("Vragen[" + i + "].Evvr_Type") %>

At the same time I want to emphasize again what

<%= Html.TextBoxFor(model => model.Vragen[i].Evvr_Type)%>

isn't equivalent to

<%= Html.TextBox("model.Vragen[" + i + "].Evvr_Type")%>

because latter even in MVC 2 can't bind default value.

Possible workarounds

First. Since SelectInternal() also checks ModelState dictionary you can fill this dictionary before returning the view.

for (int i=0; i < fevb.Vragen.Count(); i++)
    ModelState.Add("Vragen[" + i + "].Evvr_Type", new ModelState
    {
        Value = new ValueProviderResult(fevb.Vragen[i].Evvr_Type, null, 
            CultureInfo.CurrentCulture) 
    });

This will be done by MVC itself after from post, so you should do it manually only first time.

Second. Instead of

<%= Html.DropDownListFor(model => model.Vragen[i].Evvr_Type, 
    ViewData["vraagtype"] as List<SelectListItem>)%>

use

<%= Html.DropDownListFor(model => model.Vragen[i].Evvr_Type, 
    new SelectList(ViewData["vraagtype"] as IEnumerable, "Value", "Text",
        Model.Vragen[i].Evvr_Type))%>

ViewData["vraagtype"] in this case doesn't have to contain objects of SelectListItem, any IEnumerable is enough. You may check SelectList() method description in case of need.

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