MVC - 多个局部视图中提交按钮无法正常工作

7
我是新手MVC开发者,请手下留情。我接手了一个已经开始开发的MVC项目,被要求增加一些功能。在遇到需要来自两个不同模型的数据时,我陷入了困境。现在我无法继续开发,而我的老板希望这件事情昨天就完成。如果您能帮助我,那就太好了。
我有一个包含两个部分视图和一个提交按钮的视图。每个部分视图都使用不同的模型。这些视图显示屏幕上的信息,用户可以更改。然后点击提交按钮。在控制器中,我想访问来自两个模型的数据(用户在屏幕上输入的值)。现在,我甚至不能让提交按钮调用控制器。这就是我需要立即解决的问题,但我最终还需要知道如何从控制器访问两个模型的数据。
这是我想做的基本思路:
这是我的视图:CreateContract.cshtml
<div class="container-fluid">
@using (Html.BeginForm("CreateContract", "CreateContract", FormMethod.Post, new { @class = "form-horizontal " }))
{
                <div id="PartialDiv">
            @{
        Html.RenderPartial("ApplicationPartialView", new CarmelFinancialWeb.Models.ModelApplication());
        Html.RenderPartial("ContractPartialView");
            }
        </div>
            <input id="btnCreateContract" type="submit" class="btn btn-primary" value="Save" name="CreateContract" />
}
    </div>

这是控制器CreateContractController.cs的一部分。当视图打开并且正常工作时,将调用此方法。

        [AuthorizeAdmin]
    public ActionResult CreateContract(string ID)
    {
        ModelContract obj_Contract = new ModelContract();

        obj_Contract.BuyerName = "MOCS";

        return View(@"~/Views/CreateContract/CreateContract.cshtml", obj_Contract);
    }

这是控制器CreateContractController.cs的一部分。当单击提交按钮时,此方法未被调用。我尝试包括来自其他方法的字符串ID变量以及ModelContract和ModelApplication(以及各种组合),但我无法使该方法被调用。

        [AuthorizeAdmin]
    [HttpPost]
    public ActionResult CreateContract()
    {
         ModelApplication obj_App = new ModelApplication();
         return View(@"~/Views/CreateContract/CreateContract.cshtml", obj_App);

    }

这些是控制器中用于局部视图的方法。这些方法也没有被调用。

        public PartialViewResult ApplicationPartialView(string ID)
    {
        ModelApplication obj_App = new ModelApplication();

        if (ID != null && ID != "0" && ID != null && ID != "")
        {
            obj_App = objBllApplication.GetApplicationByID(int.Parse(ID));
        }

        return PartialView("CreateContractApplicationPartialView");
    }

    public PartialViewResult ContractContractPartialView()
    {
        ModelContract obj_Contract = new ModelContract();

        obj_Contract.DealerID = "MOCS";

        return PartialView("CreateContractContractPartialView");
    }

创建合同的Post版本之前能用吗?我猜答案是否定的。它可能需要一个ModelContract实例,以便可以从表单中获取详细信息。 - Daniel Hollinrake
我会改变的第一件事是您的提交控件。我会将其更改为按钮而不是输入框。尝试一下,看看它是否开始调用您的控制器操作。 - Pheonyx
当我将它更改为按钮时,出现了以下错误:“传递到字典中的模型项的类型为'CarmelFinancialWeb.Models.ModelContract',但是该字典需要一个类型为'CarmelFinancialWeb.Models.ModelApplication'的模型项。” - boilers222
Daniel Hollinrake:在我没有使用部分视图的时候,这个发布版本是可以工作的。我尝试添加ModelContract作为变量,但它没有起作用:[HttpPost]public ActionResult CreateContract(ModelContract con){} - boilers222
1
这些Partial视图里面有什么?如果将它们移除,POST请求是否正常工作? - Mrchief
1个回答

12
这里有很多隐藏的内容,对于你来说了解这些内容是有益的,特别是因为你是新手。首先,一个视图只能有一个模型。高层次的原因是它实际上是通过一个通用类呈现的,所选的模型填充它的类型。你可以稍微作弊,就像你在这里一样,使用部分视图,但你仍然需要将一个模型实例放入其中。看起来你试图通过在控制器中创建操作来表示那些部分视图,但这些操作实际上是无用的。它们从未被调用过。Html.Partial或者Html.RenderPartial只会呈现指定的视图,如果没有指定模型,则默认使用与调用视图相同的模型,或者使用传递给这些方法的对象作为模型(第二个参数)。它不会返回到控制器。
在MVC中,有一种叫做“子操作”的东西,它的工作方式就像你想要部分视图的方式一样。通过使用Html.ActionHtml.RenderAction,你可以在控制器上调用这些操作,返回部分视图。不过有两件事情需要注意:
1. 如果你要返回部分视图(而不是完整的视图),那么你应该使用[ChildActionOnly]装饰该操作。否则,这些操作将暴露给浏览器直接访问的URL,这将呈现部分视图而没有任何布局。 2. 子操作只能用于GET类型的请求。你不能向子操作POST。
对于像这样的事情,最好只使用子操作来呈现表单的不同区域,如果表单的各个单独区域将被发布到不同的位置。例如,假设你有一个组合页面,其中包含登录或注册概念。你可以使用子操作来呈现每个单独的字段组,但是登录部分应该POST到一个登录操作,而注册部分应该POST到一个注册操作。你不会将两个表单中的所有内容都POST到同一个操作中。
在你特定的场景中,部分视图实际上是正确的方法,但你只需要调整主视图的模型,使其成为一个包含两个子模型的视图模型即可。例如:
public class MyAwesomeViewModel // name doesn't matter
{
    public ModelApplication Application { get; set; }
    public ModelContract Contract { get; set; }
}

然后,在你的主视图中:
@model Namespace.To.MyAwesomeViewModel

...

@Html.Partial("ApplicationPartialView", Model.Application)
@Html.Partial("ContractPartialView", Model.Contract)

最后,您的 POST 操作将以此视图模型作为参数:
[HttpPost]
public ActionResult CreateContract(MyAwesomeViewModel model)
{
    ...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接