回发时丢失 ViewModel 内模型和集合中的数据

发布于 2024-12-25 03:20:16 字数 2659 浏览 2 评论 0原文

我正在使用一个视图模型,其中每个部分视图包含一些其他模型(实体)。 我通过传递 ViewModel 内部的实体来渲染部分视图。我的部分视图有一些字段和一些按钮。单击按钮(位于我的部分视图内)时,表单将与子实体中的数据一起回发,而我的视图模型始终以空值回发... 我需要数据在回发时出现在我的视图模型中。

所有视图都是强类型的:

代码:

public class OrdersVM
{
    public FiltersVM filterCriteria { get; set; }
    public IEnumerable<MeterInventory> meters { get; set; }
    public string assignTo { get; set; }
    public IEnumerable<SelectListItem> AssigneeOptions { get; set; }
}

public partial class Meters
{
    public int MTRNO { get; set; }
    public string LOCName { get; set; }
}

public class FiltersVM
{
    public string Center { get; set; }
    public DateTime? DueDate { get; set; }
}

查看代码

@model OrdersVM
@{
    ViewBag.Title = "Orders";
}
@using (Html.BeginForm())
{   
    <div>
        @Html.Partial("~/Views/Base/Filters.cshtml", Model.filterCriteria)
    </div>
    @foreach (var item in Model.meters)
    {  
    <table>
        <tr>
            <td>
                @Html.Encode(item.LOCNAME)
            </td>
        </tr>
    </table>
    }
}

控制器代码

[HttpPost]
public ActionResult Index(OrdersVM orders, FiltersVM filters)
{
    //orders is null
    //filters has values
}

感谢 Olivehour。我正在使用部分视图“Filters.cshtml”。并且渲染相同。

下面是部分视图的代码:

@model ViewModels.FiltersVM  <fieldset>
    <legend>Order Assignment</legend>
    <table id="tbl1" class="tableforcontrols">
        <tr>
            <td>
                <div class="editor-label">
                    @Html.LabelFor(model => model.LDC)
                </div>
            </td>
            <td>
                <div class="editor-field">
                    <input type="submit" value="Search" id="btnSearch" name="button" />
                </div>
            </td>
            <td>
                <div class="editor-field">
                    <input type="submit" class="cancel" value="Reset" id="btnReset" name="button" />
                </div>
            </td>
        </tr>
    </table>    </fieldset>     

我尝试使用单个参数“OrdersVM”(父视图模型),但没有运气。

[HttpPost]
public ActionResult Index(OrdersVM orders)

但如果我将父视图模型传递给部分视图,它会将数据保存在 OrdersVM.filterCriteria 中,但不保存属性(IEnumerable 仪表、字符串 allocateTo 和 Enumerable AssigneeOptions),

@Html.Partial("~/Views/Base/Filters.cshtml", Model)

我是 MVC 的新手。如果有人找到解决方案,请告诉我。

提前致谢。

I am using a viewmodel that contains a few other models(entities) for each partial view.
I am rendering a partial view by passing the entity which is inside the ViewModel. My partial view has a few fields and some buttons. On click of button (which is inside my partial view) the form is being posted back with the data in a sub entity, whereas my viewmodel is always posted back as null...
I need the data to be present in my viewmodel on post back.

All views are strongly typed:

Code:

public class OrdersVM
{
    public FiltersVM filterCriteria { get; set; }
    public IEnumerable<MeterInventory> meters { get; set; }
    public string assignTo { get; set; }
    public IEnumerable<SelectListItem> AssigneeOptions { get; set; }
}

public partial class Meters
{
    public int MTRNO { get; set; }
    public string LOCName { get; set; }
}

public class FiltersVM
{
    public string Center { get; set; }
    public DateTime? DueDate { get; set; }
}

View Code

@model OrdersVM
@{
    ViewBag.Title = "Orders";
}
@using (Html.BeginForm())
{   
    <div>
        @Html.Partial("~/Views/Base/Filters.cshtml", Model.filterCriteria)
    </div>
    @foreach (var item in Model.meters)
    {  
    <table>
        <tr>
            <td>
                @Html.Encode(item.LOCNAME)
            </td>
        </tr>
    </table>
    }
}

Controller code

[HttpPost]
public ActionResult Index(OrdersVM orders, FiltersVM filters)
{
    //orders is null
    //filters has values
}

Thanks Olivehour. I am using the partial view "Filters.cshtml". and am rendering the same.

Below is the code for partial view :

@model ViewModels.FiltersVM  <fieldset>
    <legend>Order Assignment</legend>
    <table id="tbl1" class="tableforcontrols">
        <tr>
            <td>
                <div class="editor-label">
                    @Html.LabelFor(model => model.LDC)
                </div>
            </td>
            <td>
                <div class="editor-field">
                    <input type="submit" value="Search" id="btnSearch" name="button" />
                </div>
            </td>
            <td>
                <div class="editor-field">
                    <input type="submit" class="cancel" value="Reset" id="btnReset" name="button" />
                </div>
            </td>
        </tr>
    </table>    </fieldset>     

I tried with single argument "OrdersVM" (parent view model) but no luck.

[HttpPost]
public ActionResult Index(OrdersVM orders)

but if I pass the parent viewmodel to the partial view it was holding the data in OrdersVM.filterCriteria but not for properties (IEnumerable meters, string assignTo and Enumerable AssigneeOptions)

@Html.Partial("~/Views/Base/Filters.cshtml", Model)

I am new to MVC. Please let me know if any one finds the solution.

Thanks in advance.

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

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

发布评论

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

评论(2

小瓶盖 2025-01-01 03:20:16

看起来你这里有几个问题。操作方法中 order arg 为 null 的一个可能原因是它看起来不像您正在渲染任何输入元素。您只有 @Html.Encode(item.LOCNAME)

为了让默认模型绑定器构造 OrdersVM 实例并将其传递给操作方法,它需要来自 HTTP POST 的输入。您需要更像 @Html.TextBoxFor(m => item.LOCNAME) 的内容。

我认为第二个问题是操作方法中有两个参数。由于 OrdersVM 已经具有 FiltersVM 属性,因此您应该只能为操作方法添加一个 OrdersVM 参数。在 HTTP POST 期间,您只需从 OrdersVM.filterCriteria 访问 FiltersVM 属性。不过,这将给您带来第三个挑战,因为 OrdersVM 上的 meters 属性是一个 IEnumerable 集合。

要解决这个问题,首先阅读这个关于模型绑定集合的文章。它很旧,但在 MVC3 中仍然适用。阅读它并真正理解它。

如果您不喜欢使用整数为集合字段建立索引,可以使用 由 Steve Sanderson 编写的 HTML 帮助程序,允许您使用 GUID 对集合输入进行索引。我们一直在使用它,但它可能很棘手——主要是,您应该始终将集合项放在部分视图中。目前,您可能最好使用 Haacked 文章中概述的基于整数的索引。

It looks like you have a couple of problems here. One probable reason why the orders arg is null in your action method is because it doesn't look like you are rendering any input elements. You just have @Html.Encode(item.LOCNAME).

In order for the default model binder to construct an instance of OrdersVM and pass it to the action method, it needs to have input from the HTTP POST. You need something more like @Html.TextBoxFor(m => item.LOCNAME).

The second problem I think is that you have 2 arguments in the action method. Since the OrdersVM already has a FiltersVM property, you should just be able to have a single OrdersVM argument to the action method. During the HTTP POST, you can just access FiltersVM properties from OrdersVM.filterCriteria. This will lead to your 3rd challenge, though, since the meters property on OrdersVM is an IEnumerable collection.

To solve this, first have a couple reads of this article about model binding collections. It's old, but it still applies in MVC3. Read it and really wrap your head around it.

If you don't like using integers to index your collection fields, there is an HTML helper written by Steve Sanderson that allows you to index collection inputs using GUID's. We use this all the time, but it can be tricky -- mainly, you should always put the collection item in a partial view. For now, you might just be better off using integer-based indexing as outlined in the Haacked article.

末骤雨初歇 2025-01-01 03:20:16

听起来您来自 Webforms。要过渡到 MVC,您需要消除 PostBack 的想法。这个概念在网络上并不存在,但 Webforms 为我们伪造了它。

在 MVC 中,您通常从像 /edit/{someId} 这样的 GET 请求开始。从这里,您可以从数据库加载视图模型的数据并渲染视图。现在假设视图模型中的所有数据都是可编辑的,因此每个属性都有自己的输入字段。用户编辑一些数据并保存表单。这会向服务器发出 POST。

假设我们有这个 POST 方法,

[HttpPost]
public ActionResult Edit(MyViewModel model)

在这种情况下,您拥有模型绑定所需的所有数据,因为所有数据都存在于表单中。

您可以执行此操作并获得呈现的相同视图,因为所有数据都是数据绑定的。

[HttpPost]
public ActionResult Edit(MyViewModel model){
   return View(model);
}

现在假设您的表单中有一个下拉菜单。然后你的视图模型中就会有这两个属性。

public int CarId { get; set; }
public IEnumerable<SelectListItem> CarOptions {get; set; }

当您这次发布表单时,CarId 将填充在 ViewModel 中,但不会填充 CarOptions,因为它们不是表单数据的一部分。如果您想再次返回相同的视图,您要做的就是重新加载丢失的部分。

[HttpPost]
public ActionResult Edit(MyViewModel model){
   model.CarOptions = LoadCarOptions();
   return View(model);
}

如果您将其放在隐藏字段中,当然也可以对其进行模型绑定。但再次从服务器/数据库重新加载它更容易,也可能更有效。这是使用 MVC 时采取的常规方法。

It sounds like you are comming from Webforms. To transition to MVC you need to remove the thought of PostBack. This is concept that doesn't really exist on the web but Webforms faked it for us.

In MVC you usually start with a GET request like /edit/{someId}. From here you load the data for the viewmodel from the database and render the view. Now let's say that all data in the viewmodel is editable so each property have it's own input field. The user edits some data and saves the form. This issues a POST to the server.

Assume we have this POST method

[HttpPost]
public ActionResult Edit(MyViewModel model)

In this case you have all the data you need modelbinded because all data existed in the form.

You could do this and get the same view rendered because all data was databinded.

[HttpPost]
public ActionResult Edit(MyViewModel model){
   return View(model);
}

Now let's pretend you have a dropdown in your form. Then you would have these two properties in your viewmodel.

public int CarId { get; set; }
public IEnumerable<SelectListItem> CarOptions {get; set; }

When you post the form this time the CarId will be populated in the ViewModel but not CarOptions because they are not a part of the form data. What you do if you would want to return the same view again is to reload the missing parts.

[HttpPost]
public ActionResult Edit(MyViewModel model){
   model.CarOptions = LoadCarOptions();
   return View(model);
}

It's certainly possible to modelbind that too if you put it in a hidden field. But it's easier and probably more effective to reload it from server/database again. This is the normal approach taken when working with MVC.

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