【问题标题】:MVC how to render partial view from controllerMVC如何从控制器渲染部分视图
【发布时间】:2017-04-14 14:45:21
【问题描述】:

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

我正在尝试遍历 foreach 中的项目循环每个办公室持有人并添加到办公室持有人视图,但在我的代码中循环第一个项目后,此函数仅返回我在办公室持有人部分视图中的第一个办公室人员

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")           
    }
}

【问题讨论】:

  • 循环返回没有意义吧?
  • 你一使用return PartialView(...);就退出函数你的方法只能返回1个视图-你需要将集合传递给视图并在视图中使用foreach循环来生成html每个项目
  • 我建议创建另一个局部视图,它应该接受整个模型(即“OfficeHolder”类型的集合)。在该局部视图中,遍历集合的每个项目,并调用您的“OfficeHolderEntryEditor”局部视图。控制器动作应该调用新创建的局部视图,并且应该简单地传递“office_holders”集合。

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


【解决方案1】:

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

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

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

此视图应包含一个项目的 html 并带有:

@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());
    }
}

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

【讨论】:

  • 如果您在视图中使用EditorFor 扩展方法,则不需要此扩展方法 - EditorFor 已经处理显示集合
  • @levelnis 是的,但你不能从控制器这样称呼它
  • true - 将显示逻辑移动到视图中,而不是让它成为控制器的责任不是更好吗?
  • @levelnis 实际上是品味的标准。但是我的解决方案将在没有许多额外的 ViewModels 和 Views 的情况下工作。所以我想它更干净一些。
【解决方案2】:

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

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

我会将显示标记的业务与整理数据的业务分开。所以你的控制器只关心创建模型而不是渲染哪个模板。我们将把这个考虑留给视图。为页面添加一个 ViewModel,您将在其中添加您的办公室人员。我们就叫它OfficeHoldersTestViewModel:

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

您的 Controller 操作现在只需要创建其中一个并使用 office holder 填充它:

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);
}

接下来,在 Views/Shared/EditorTemplates 中创建一个名为 OfficeHolder.cshtml 的编辑器模板,并将 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>

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

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

【讨论】:

    【解决方案3】:

    您只看到第一个部分视图的原因是您的代码在 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);
        }
    

    【讨论】:

      猜你喜欢
      • 2015-06-05
      • 2015-08-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 2015-04-04
      • 2013-08-18
      相关资源
      最近更新 更多