3

我了解如何使用部分视图,并且了解 Ajax.ActionLink 和 Ajax.BeginForm 如何在视图中设置它们。我假设每个局部视图都有自己的控制器。我在这里考虑有界上下文,因为在每个局部视图中都可以通过自己的控制器与自己的有界上下文对话

我想我缺少的部分是:

  1. 如何将部分视图包含在“主视图”(或持有视图)中,并让这些部分视图中的每一个独立发布到单独的控制器操作,然后返回以刷新部分视图而不加载“主视图”或持有视图.
  2. “主”视图或持有视图仍然需要有自己的控制器,我想阻止主控制器重新加载其视图,并让主控制器的操作方法生成的视图持有对这两个部分的引用意见。

我似乎可以采取两种方法,一种是使用“Ajax”。MVC3 的功能,另一个是直接使用 jQuery 并从客户端手动处理所有这些交互。

我正在尝试做的事情是两种方式,还是一种方式“更适合”这种类型的复合 ui 构造?

到目前为止,我所看到的只是复合 ui 构造的简单示例,例如通过 Ajax.ActionLink 刷新页面上的单个链接的链接,或者编写为 Ajax.BeginForm 的表单,该表单使用来自部分观点。

4

1 回答 1

4

好的,所以我终于有了一些我认为正确的工作代码。这是我一起去的。我有两个简单的“实体”;客户和计费客户。它们实际上是在单独的“有界上下文”中,并且出于演示目的,这些类非常简单。

public class Customer
{ 
    public Guid CustomerId { get; set; }
    public string Name { get; set; }
}

public class BillingCustomer
{
    public Guid CustomerId { get; set; }
    public bool IsOverdueForPayment { get; set; }
}

请注意,这两个类都引用了 CustomerId,为了这个演示,它是一个 GUID。

我从一个简单的 HomeController 开始,它构建了一个 ViewModel 将被 Index.cshtml 文件使用:

public ActionResult Index()
{
    var customer = new Customer {
        CustomerId = Guid.Empty, 
        Name = "Mike McCarthy" };

    var billingCustomer = new BillingCustomer { 
        CustomerId = Guid.Empty, 
        IsOverdueForPayment = true };

    var compositeViewModel = new CompositeViewModel {
        Customer = customer, 
        BillingCustomer = billingCustomer };

    return View(compositeViewModel);
}

CompositeViewModel 类只是一个愚蠢的 DTO,每个域实体都有一个属性,因为我将在我的 Index.cshtml 文件中调用的局部视图每个都需要将它们各自的域模型传递到局部视图中:

public class CompositeViewModel
{
    public BillingCustomer BillingCustomer { get; set; }
    public Customer Customer { get; set; }
}

这是我生成的 Index.cshtml 文件,它使用 HomeController 上的 Index 方法

@model CompositeViews.ViewModels.CompositeViewModel

<h2>Index - @DateTime.Now.ToString()</h2>

<div id="customerDiv">
    @{Html.RenderPartial("_Customer", Model.Customer);}
</div>

<p></p>

<div id="billingCustomerDiv">
    @Html.Partial("_BillingCustomer", Model.BillingCustomer)
</div>

这里有几点需要注意:

  1. 视图正在使用 CompositeViews.ViewModels.CompositeViewModel ViewModel
  2. Html.RenderPartial 用于渲染每个实体的局部视图,并传入适当的实体。小心 Html.Partial 调用的语法!

所以,这里是 _Customer 部分视图:

@model CompositeViews.Models.Customer

@using (Ajax.BeginForm("Edit", "Customer", new AjaxOptions { 
    HttpMethod = "POST", 
    InsertionMode = InsertionMode.Replace, 
    UpdateTargetId = "customerDiv" }))
{
    <fieldset>
        <legend>Customer</legend>

        @Html.HiddenFor(model => model.CustomerId)

        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

这里的重要部分是 Ajax.BeginForm 调用。请注意,它显式调用了 CustomerController 的 Edit ActionMethod。另请注意,UpdateTargetId 设置为“customerDiv”。这个 div 不在局部视图中,而是在“父”视图 Index.cshtml 中。

下面是 _BillingCustomer 视图

@model CompositeViews.Models.BillingCustomer

@using (Ajax.BeginForm("Edit", "BillingCustomer", new AjaxOptions { 
    HttpMethod = "POST", 
    InsertionMode = InsertionMode.Replace, 
    UpdateTargetId = "billingCustomerDiv" }))
{
<fieldset>
    <legend>BillingCustomer</legend>

    @Html.HiddenFor(model => model.CustomerId)

    <div class="editor-label">
        @Html.LabelFor(model => model.IsOverdueForPayment)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.IsOverdueForPayment)
        @Html.ValidationMessageFor(model => model.IsOverdueForPayment)
    </div>

    <p>
        <input type="submit" value="Save" />
    </p>
</fieldset>
}

再次注意,UpdateTargetId 设置为 billingCustomerDiv。此 div 位于 Index.cshtml 文件中,而不是此部分视图文件中。

所以,我们唯一还没有看到的是 CustomerController 和 BillingCustomerController 上的 Edit ActionResult。这是客户控制器

public class CustomerController : Controller
{
    [HttpGet]
    public PartialViewResult Edit(Guid customerId)
    {
        var model = new Customer {
            CustomerId = Guid.Empty, 
            Name = "Mike McCarthy"};

        return PartialView("_Customer", model);
    }

    [HttpPost]
    public ActionResult Edit(Customer customer)
    {
        return PartialView("_Customer", customer);
    }
}

在这个控制器中没有什么真正“发生”,因为帖子直接涉及构建复合 UI。请注意我们如何通过“PartialView”返回并指定要使用的局部视图的名称,以及视图需要呈现的所需模型。

这是 BillingCustomerController

public class BillingCustomerController : Controller
{
    [HttpGet]
    public PartialViewResult Edit(Guid customerId)
    {
        var model = new BillingCustomer {
            CustomerId = Guid.Empty, 
            IsOverdueForPayment = true };

        return PartialView("_BillingCustomer", model);
    }

    [HttpPost]
    public PartialViewResult Edit(BillingCustomer billingCustomer)
    {
        return PartialView("_BillingCustomer", billingCustomer);
    }
}

同样,与 CustomerController 相同,只是这个控制器正在处理 BillingCustomer 实体。

现在,当我加载 HomeController 的 Index ActionResult 时,我得到一个如下所示的屏幕:

复合界面

每个保存按钮都会对控制器进行异步回发,部分视图需要更新并与之对话以获取数据,所有这些都不会导致整个页面的定期回发。点击任一保存按钮时,您可以看到 DateTime 戳不会改变。

所以,这就是我如何使用局部视图构建我的第一个复合视图。由于我对 MVC3 还是很陌生,我仍然可能会搞砸一些事情,或者做一些比它需要的更难的事情,但这就是我让它工作的方式。

于 2012-10-01T16:32:24.850 回答