Razor / MVC - PartialView (分部视图)

创建时间:
2014-07-06 01:29
最近更新:
2018-09-17 14:48

Resource - MSDN

  1. @Html.Partial() - PartialExtensions 类
  2. @{Html.RenderPartial();} - RenderPartialExtensions 类
  3. System.Web.Mvc.PartialViewResult - 详见本站专文

Resource - PartialViewResult

  1. 分部视图 的 各种用法
  2. $.ajax() 加载 PartialViewResult 并传递参数
  3. PartialViewResult 不鸟 _ViewStart.cshtml - 在ASP.NET MVC中,对于Action中得到的ActionResult如果是一个ViewResult对象,那么在进行View呈现时,则会先执行_ViewStart.cshtml,然后再去执行被请求的视图页,但是如果在控制器的Action中得到的ActionResult是一个PartialViewResult对象,那么在进行View呈现时,则不会执行_ViewStart.cshtml。 上图中,我们可以看出在创建RazorView对象时,ViewResult和PartialViewResult的区别在于参数:runViewStartPages,正式由于它,决定了在之后执行进行视图页处理时,也就是执行RazorView对象的Render(viewContext, output)方法时,是否执行“_ViewStar.cshtml”。

Resource

  1. MVC Razor 中 Partial, Action, RenderPartial, RenderAction 的使用选择
  2. ASP.NET MVC 中 Partial, Action, RenderPartial, RenderAction 区别和用法
  3. ASP.NET MVC3 Helpers Partial, Action, RenderPartial, RenderAction
  4. 在 ASP.NET MVC 中 PartialView 与 EditorFor 和 DisplayFor 的区别

PartialView Rule

  • 如果 控制器 返回 PartialViewResult,则 ASP.NET MVC 框架 将 跳过 _ViewStart.cshtml 文件,而该文件的内容默认为 @{ Layout = ""; },最终表现为 "分部视图 不加载 布局页/母版页"。
  • ASP.NET MVC 框架对 PartialView 的文件名、内容以及其它一切没有任何约束,它可以和普通的 View 文件没有任何区别。在 PartialView 中可访问外层 View 的全部数据,例如 Model、ViewData、TempData 等。
  • Tony's Convention: 公用的 PartialView 放在 /Views/Shared 目录下 且 以 _ 开头。即与 _Layout.cshtml 保持一致。
  • PartialView 中不应该存在 html、head、body 等页面级 HTML-tag,因为 PartialView 的输出总是嵌套在另一个完整的 HTML 页面中。
  • 避免在 PartialView 中引用 CSS 与 JavaScript 文件,应该尽量在包含 PartialView 的 View 中引用,因为 PartialView 与 View 不在同一目录下时可能会导致引用路径错误。
  • @Html.Action()@{Html.RenderAction();} 会进行完整的 "请求-响应",如非必须,应使用 @Html.Partial()@{Html.RenderPartial();} 减少消耗。
  • 尽量使用 Model 向视图传递数据。如果一个分部视图需要两组数据,建议考虑是否应重构成两个分部视图。

ASP.NET MVC 框架 查找 分部视图 的顺序

Controller/Actionreturn PartialView(partialViewName); 时,默认会在以下目录下依次查找 partialViewName 对应的视图文件:

  • ~/Views/Shared/
  • ~/Views/ControllerName/

@Html.Partial() versus @{Html.RenderPartial();}

  • 前者 定义在 System.Web.Mvc.Html.PartialExtensions 类中。
  • 后者 定义在 System.Web.Mvc.Html.RenderPartialExtensions 类中。
  • 二者 都 总共有4个重载 且 这些重载的签名完全相同。
  • 二者 都 可以传入主视图的 ModelViewData
  • 前者返回 MvcHtmlString 类的实例。
  • 后者返回 void 类的实例。
  • 二者 的 全参重载 签名 如下:
public static MvcHtmlString       Partial(this HtmlHelper htmlHelper, string partialViewName, object model, ViewDataDictionary viewData)
public static void          RenderPartial(this HtmlHelper htmlHelper, string partialViewName, object model, ViewDataDictionary viewData)

摘要对比:
前者: 以 HTML 编码字符串的形式呈现指定的分部视图。
后者: 呈现指定的分部视图,使用指定的 System.Web.Mvc.ViewDataDictionary 对象替换分部视图的 ViewData 属性,并将视图数据的 Model 属性设置为指定的模型。

返回对比:
前者: 以 HTML 编码字符串形式呈现的分部视图。
后者: void,故不能 @Html.RenderPartial(),需要写为 @{Html.RenderPartial();}

每个 _Layout.cshtml 中可使用 0 或 无数次。

TonyRemark:

  1. @{Html.RenderPartial();} 性能优于 @Html.Partial(),因为后者需创建 TextWriter 来缓存数据并转而输出至 MvcString 对象中。@{Html.RenderPartial();} same as Html.Partial(), except that it writes its output directly to the response stream. This is more efficient, because the view content is not buffered in memory. However, because the method does not return any output, @Html.RenderPartial("MyView") won't work. You have to wrap the call in a code block instead: @{Html.RenderPartial("MyView");}.
  2. 这 2 个 Partial() 均 follows the standard rules for view lookup (i.e. check current directory, then check the Shared directory).

Partial versus Action

  • @Html.Partial()@Html.Action() 的返回类型均为 MvcHtmlString
  • @{Html.RenderPartial();}@{Html.RenderAction();} 的返回类型均为 void,均将内容直接写入响应流中,因此二者在 .cshtml 文件中的语法必须像这样放在代码块中。
  • 如果某个 Action 被设置为仅被 @Html.Action()@{Html.RenderAction()} 调用,那么应该为该 Action 添加 [ChildActionOnly] 特性,来限制只能在其它 Action 中访问该 "子 Action",当用户直接请求该 "子 Action" 时将抛出异常 "操作“xxx”只能由子请求访问"。
  • Action() 重新执行一个请求,并且使用新请求中得到的数据,至少需要经历 Route、Controller、Action、View。本质上,它是对逻辑的复用。
  • Partial() 使用当前 Action 中的数据进行处理,不经历 Route、Controller、Action,本质上,它是对 View 的复用。
  • 结论: 除非当前 Action 提供的数据不适用,否则尽量使用 Partial(),而非 Action()

Partial versus RenderPage

二者 传递数据的方式 不同:

  • @Html.Partial()@{Html.RenderPartial();} 都 可以传入主视图的 ModelViewData。PartialView 中可使用强类型,例如 @model List<string>
  • RenderPage 的签名为 public override HelperResult System.Web.WebPages.WebPageBase.RenderPage(string path, params object[] data);。该方法没有重载。在被呈现页中 不能使用主视图的 ModelViewData、只能使用 该方法的 data 实参 (可选) 传递给 被呈现页 的数据数组。在被呈现页中,可以使用 System.Web.WebPages.WebPageBase.PageData 属性来访问这些参数。

网友意见:

  • 单纯从上述区别看的话 RenderPage 有点多余,觉得微软这样的设定会引起一些不规范的做法。
  • 我更喜欢 @RenderPage("_LayoutHeader.cshtml") 超过 @{Html.RenderPartial("_LayoutHeader");},只是因为 语法更简单、可读性更强。除了这似乎没有任何差异功能明智。

Tony Remark:
截至 2013-08-21,综合上述,Tony 认为,如无需传递数据,统一使用 @RenderPage()

加载分部视图的途径

在视图里有多种方法可以加载分部视图,包括:
@RenderPage()
@Html.Action()
@Html.Partial()
@{Html.RenderAction();}
@{Html.RenderPartial();}
-- ASP.NET MVC4 分部视图

调用 PartialView 的几种方式

在视图中:

@Html.Partial("ViewName", ModelData)
@Html.Partial("PartialViewName", ModelData, viewDataDictionary)
@Html.Partial("~/Views/Shared/_Product.cshtml", ModelData);

@{Html.RenderPartial("PartialViewName", Model);}

@Html.Action("ActionName", "ControllerName")
@Html.RenderAction()

在控制器中:

//本 Action 对应的视图代码通常为 ``@Html.Action()``。
//注意: 如果不需要经历控制器来提供上下文数据,那么改用 ``@Html.Partial("",data)`` 消耗会小得多。
public ActionResult PartialViewResult_Test()
{
    return PartialView("PartialViewName", model);
}

[ChildActionOnly]
public ActionResult ChildAction()
{
    return PartialView(...);
}

使用 $("#Div0").load("/Controller/PartialViewName/Id"); 来调用 PartialView,非常优雅。