MVC如何从控制器渲染局部视图

时间:2016-11-30 10:14:15

标签: asp.net-mvc model-view-controller

我在视图@Html.Action("office_holders_Test")中有一个操作方法,在控制器类中我有以下方法,

我试图循环遍历每个办公室持有人的foreach循环中的项目并添加到办公室持有人视图,但在循环第一项后我的代码中此功能仅返回我在officeholder局部视图中的第一个办公室持有人

public ActionResult  office_holders_Test()
{
    int Application_id = Convert.ToInt32(TempData["Application_id"]);
    if (Application_id != 0)
    {
        var office_holders = Applicant_Service.GetOfficeHolderBy_Application_Id(Application_id);
        DisplayDropdownList();
        foreach (var OfficeHolder in office_holders)
        {
            return PartialView("../Applicant/OfficeHolderEntryEditor", OfficeHolder);
        }
        else
        {
            return PartialView("../Applicant/OfficeHolderEntryEditor", new tr_office_holders());
        }
        return PartialView("../Applicant/OfficeHolderEntryEditor")           
    }
}

3 个答案:

答案 0 :(得分:0)

我建议使用的最佳选择是使用EditorTempate

您应该在View\Shared中创建文件夹,并将其命名为EditorTemplates

在此文件夹中,创建与模型类同名的视图(例如tr_office_holders.cshtml)。

此视图应包含一个项目的html和starns:

@model YourApplicationModelNamespace.tr_office_holders

有一个问题 - 您无法调用EditorTemplate来收集Contoller ,这就是我建议您创建扩展方法的原因:

public static class ContollerExtensions
{
    /// <summary>
    /// Render partial method (Allows to render collections that implement IEnumerable interface)
    /// </summary>
    /// <param name="controller"></param>
    /// <param name="viewName"></param>
    /// <param name="model"></param>
    /// <returns></returns>
    public static string RenderPartial(this Controller controller, string viewName, object model)
    {
        var modelItems = model as IEnumerable<object>;
        if (modelItems == null)
            return controller.RenderPartialViewToString(viewName, model);
        else
        {
            var result = String.Empty;
            foreach (var modelItem in modelItems)
            {
                result += controller.RenderPartialViewToString(viewName, modelItem);
            }
            return result;
        }
    }

    /// <summary>
    /// Internal method that renders view and returning string
    /// </summary>
    /// <param name="controller"></param>
    /// <param name="viewName"></param>
    /// <param name="model"></param>
    /// <returns></returns>
    private static string RenderPartialViewToString(this Controller controller, string viewName, object model)
    {
        if (string.IsNullOrEmpty(viewName))
        {
            viewName = controller.ControllerContext.RouteData.GetRequiredString("action");
        }

        controller.ViewData.Model = model;

        using (var sw = new StringWriter())
        {
            var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
            var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
            viewResult.View.Render(viewContext, sw);

            return sw.GetStringBuilder().ToString();
        }
    }
}

你可以在你的控制器中调用这个:

public ActionResult  office_holders_Test()
{
    int Application_id = Convert.ToInt32(TempData["Application_id"]);
    if (Application_id != 0)
    {
        var office_holders = Applicant_Service.GetOfficeHolderBy_Application_Id(Application_id);
        DisplayDropdownList();
        this.RenderPartial("EditorTemplates/tr_office_holders", office_holders);      
    }
    else
    {
        return this.RenderPartial("EditorTemplates/tr_office_holders", new tr_office_holders());
    }
}

请注意,现在渲染一个元素或集合没有区别。

答案 1 :(得分:0)

所以听起来你想在视图中通过循环显示集合中的项目?你最好使用编辑器模板而不是部分视图。 MVC在显示和编辑器模板中有一些很好的功能,用于处理集合,您可以利用它们。我写了一篇关于using Display Templates的文章,你可能觉得它很有用。

我无法判断您的部分内容是否有任何表单输入,因此无法建议是使用编辑器还是显示模板。经验法则是,如果您显示只读标记,请使用“显示模板”。如果要为用户交互提供表单控件,请使用编辑器模板。你把你称为编辑,所以我们将继续这样做。

我将显示标记的业务与整理数据的业务分开。因此,您的控制器仅关注创建模型而不关注要呈现的模板。我们将把这个考虑留在视图中。为页面添加ViewModel,您将添加办公室持有者。我们称之为OfficeHoldersTestViewModel

public class OfficeHoldersTestViewModel
{
    public IEnumerable<OfficeHolder> OfficeHolders { get; set; }
}

您的控制器操作现在只需要创建其中一个并填充办公室持有人:

public ActionResult office_holders_Test()
{
    int Application_id = Convert.ToInt32(TempData["Application_id"]);
    var model = new OfficeHoldersTestViewModel { OfficeHolders = new List<OfficeHolder>() };
    if (Application_id != 0)
    {
        var office_holders = Applicant_Service.GetOfficeHolderBy_Application_Id(Application_id);
        model.OfficeHolders = office_holders;
    }

    return View(model);
}

接下来,在名为OfficeHolder.cshtml的Views/Shared/EditorTemplates中创建一个编辑模板,并将model属性设置为OfficeHolder类:

@model OfficeHolder
<!-- markup for an Office Holder goes here -->

最后,在您的主视图中,将model设置为OfficeHoldersTestViewModel,然后使用EditorFor扩展程序方式显示您的办公室持有人:

@model OfficeHoldersTestViewModel
<div class="row">
    <div class="col-xs-12">
        @Html.EditorFor(m => m.OfficeHolders)
    </div>
</div>

这个扩展方法的好处在于它适用于集合以及单个对象。在这种情况下,它将使用您为单个Office Holder创建的模板,并将其应用于集合中的每个项目,将它们呈现在另一个项目之下。

进一步阅读using Display Templates,您可能会觉得有用。

答案 2 :(得分:0)

你只看到第一个局部视图的原因是你的代码在foreach循环中有一个返回,它停止了代码的执行。

您必须只返回一个视图,您可以创建另一个局部视图并传递office_holders列表,并在视图内部进行for循环:

public ActionResult  office_holders_Test()
{
    int Application_id = Convert.ToInt32(TempData["Application_id"]);
    if (Application_id != 0)
    {
        var office_holders = Applicant_Service.GetOfficeHolderBy_Application_Id(Application_id);
        DisplayDropdownList();

            return PartialView("OfficeHolderEntryList", office_holders)        
     }

     return PartialView("OfficeHolderEntryList")
}

视图:OfficeHolderEntryList.cshtml

    @foreach (var officeHolder in Model)
    {
        Html.RenderPartial("OfficeHolderEntryEditor",officeHolder);
    }