ASP.NET MVC3 向View传递数据(转)
ASP.NET MVC3 向View传递数据
我们可以通过ViewResult 使Action传递数据到View.
一般来说我们使用3种方式通过Action向View传递数据:
1.ViewData
2.TempData
3.强类型Model
我们先来看看ViewContext,其有3个Virtual 属性:
public class ViewContext : ControllerContext
{
public virtual TempDataDictionary TempData { get; set; }
public virtual IView View { get; set; }
public virtual ViewDataDictionary ViewData { get; set; }
...
}
{
public virtual TempDataDictionary TempData { get; set; }
public virtual IView View { get; set; }
public virtual ViewDataDictionary ViewData { get; set; }
...
}
ViewData TempData传递过程:
Action中的赋值语句实际上操作的是Controller类的ViewData和TempData属性, 此时并没有任何的数据传递.Action返回ViewResult,
Controller的View方法会将Controller类的ViewData和TempData属性值传递给ViewResult,代码如下:
public abstract class Controller : ControllerBase, IActionFilter,IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter
{
...
protected internal virtual ViewResult View(IView view, object model)
{
if (model != null)
{
base.ViewData.Model = model;
}
return new ViewResult { View = view, ViewData = base.ViewData, TempData = base.TempData };
}
...
}
{
...
protected internal virtual ViewResult View(IView view, object model)
{
if (model != null)
{
base.ViewData.Model = model;
}
return new ViewResult { View = view, ViewData = base.ViewData, TempData = base.TempData };
}
...
}
ViewResult的ExecuteResult根据ViewData和TempData构建ViewContext对象:
public abstract class ViewResultBase : ActionResult
{
...
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (string.IsNullOrEmpty(this.ViewName))
{
this.ViewName = context.RouteData.GetRequiredString("action");
}
ViewEngineResult result = null;
if (this.View == null)
{
result = this.FindView(context);
this.View = result.View;
}
TextWriter writer = context.HttpContext.get_Response().get_Output();
ViewContext viewContext = new ViewContext(context, this.View, this.ViewData, this.TempData, writer);
this.View.Render(viewContext, writer);
if (result != null)
{
result.ViewEngine.ReleaseView(context, this.View);
}
}
...
}
{
...
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
if (string.IsNullOrEmpty(this.ViewName))
{
this.ViewName = context.RouteData.GetRequiredString("action");
}
ViewEngineResult result = null;
if (this.View == null)
{
result = this.FindView(context);
this.View = result.View;
}
TextWriter writer = context.HttpContext.get_Response().get_Output();
ViewContext viewContext = new ViewContext(context, this.View, this.ViewData, this.TempData, writer);
this.View.Render(viewContext, writer);
if (result != null)
{
result.ViewEngine.ReleaseView(context, this.View);
}
}
...
}
ViewContext对象最终会传递给ViewPage, 也就是说ViewData和TempData集合传递到了ViewPage. 实际上ViewData对象并不是通过ViewContext传递到ViewPage中的。
ViewPage上的ViewData是一个单独的属性,它继承自:IVeiwContainer
public interface IViewDataContainer
{
// Properties
ViewDataDictionary ViewData { get; set; }
}
{
// Properties
ViewDataDictionary ViewData { get; set; }
}
TempData在Controller的基类ControllerBase中定义
public abstract class ControllerBase : IController
{
...
public TempDataDictionary TempData
{
get
{
if ((this.ControllerContext != null) && this.ControllerContext.IsChildAction)
{
return this.ControllerContext.ParentActionViewContext.TempData;
}
if (this._tempDataDictionary == null)
{
this._tempDataDictionary = new TempDataDictionary();
}
return this._tempDataDictionary;
}
set
{
this._tempDataDictionary = value;
}
}
...
}
{
...
public TempDataDictionary TempData
{
get
{
if ((this.ControllerContext != null) && this.ControllerContext.IsChildAction)
{
return this.ControllerContext.ParentActionViewContext.TempData;
}
if (this._tempDataDictionary == null)
{
this._tempDataDictionary = new TempDataDictionary();
}
return this._tempDataDictionary;
}
set
{
this._tempDataDictionary = value;
}
}
...
}
TempData其实访问的是ViewContext.TempData
ViewPage Code如下:
[FileLevelControlBuilder(typeof(ViewPageControlBuilder))]
public class ViewPage : Page, IViewDataContainer
{
...
public ViewDataDictionary ViewData
{
get
{
if (this._viewData == null)
{
this.SetViewData(new ViewDataDictionary());
}
return this._viewData;
}
set
{
this.SetViewData(value);
}
}
public TempDataDictionary TempData
{
get
{
return this.ViewContext.TempData;
}
}
...
}
public class ViewPage : Page, IViewDataContainer
{
...
public ViewDataDictionary ViewData
{
get
{
if (this._viewData == null)
{
this.SetViewData(new ViewDataDictionary());
}
return this._viewData;
}
set
{
this.SetViewData(value);
}
}
public TempDataDictionary TempData
{
get
{
return this.ViewContext.TempData;
}
}
...
}
ViewData 和TempData传值如下:
public class HomeController : Controller
{
public ActionResult Index()
{
ViewData["ViewData"] = "ViewData";
TempData["TempData"] = "TempData";
return View();
}
}
{
public ActionResult Index()
{
ViewData["ViewData"] = "ViewData";
TempData["TempData"] = "TempData";
return View();
}
}
在View中我们如下使用:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
ViewData传值:<%=ViewData["ViewData"]%><br />
TempData传值:<%=TempData["TempData"]%>
</asp:Content>
ViewData传值:<%=ViewData["ViewData"]%><br />
TempData传值:<%=TempData["TempData"]%>
</asp:Content>
ViewData只能在当前Action中有效
TempData可以类似于Session一样到其它页面仍然存在,但仅仅局限于这两个前后相连的页面(只能经过一次Controller传递)
TempData可以类似于Session一样到其它页面仍然存在,但仅仅局限于这两个前后相连的页面(只能经过一次Controller传递)
TempData一般用于临时的缓存内容或抛出错误页面时传递错误信息
强类型Model传值如下:
1. 我们需要Create一个Model类:
public class Movie
{
public int Id { get; set; }
public string Title { get; set; }
public string Director { get; set; }
}
{
public int Id { get; set; }
public string Title { get; set; }
public string Director { get; set; }
}
2. Create一个View:
ViewName:Index
Check:Cerate aStrongly-typed view
选择刚Create的Movie Model
Scaffold template:选择List
点击ADD创建View
VS自动生成如下Code:
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Jeriffe.Web.MVC.MovieApp.Movie>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Details
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Details</h2>
<fieldset>
<legend>Movie</legend>
<div class="display-label">Title</div>
<div class="display-field">
<%: Html.DisplayFor(model => model.Title) %>
</div>
<div class="display-label">Director</div>
<div class="display-field">
<%: Html.DisplayFor(model => model.Director) %>
</div>
</fieldset>
<p>
<%: Html.ActionLink("Edit", "Edit", new { id=Model.Id }) %> |
<%: Html.ActionLink("Back to List", "Index") %>
</p>
</asp:Content>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Details
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Details</h2>
<fieldset>
<legend>Movie</legend>
<div class="display-label">Title</div>
<div class="display-field">
<%: Html.DisplayFor(model => model.Title) %>
</div>
<div class="display-label">Director</div>
<div class="display-field">
<%: Html.DisplayFor(model => model.Director) %>
</div>
</fieldset>
<p>
<%: Html.ActionLink("Edit", "Edit", new { id=Model.Id }) %> |
<%: Html.ActionLink("Back to List", "Index") %>
</p>
</asp:Content>
ViewPage的Model属性就是一个强类型对象, 在这里就是Movie.page页面指令可以看出, 这里的页面继承自ViewPage<Model>类, 而不是ViewPage.
ViewPage<TModel> Code如下:
public class ViewPage<TModel> : ViewPage
{
// Fields
private ViewDataDictionary<TModel> _viewData;
// Methods
public ViewPage();
public override void InitHelpers();
protected override void SetViewData(ViewDataDictionary viewData);
// Properties
public AjaxHelper<TModel> Ajax { get; set; }
public HtmlHelper<TModel> Html { get; set; }
public TModel Model { get; }
public ViewDataDictionary<TModel> ViewData { get; set; }
}
{
// Fields
private ViewDataDictionary<TModel> _viewData;
// Methods
public ViewPage();
public override void InitHelpers();
protected override void SetViewData(ViewDataDictionary viewData);
// Properties
public AjaxHelper<TModel> Ajax { get; set; }
public HtmlHelper<TModel> Html { get; set; }
public TModel Model { get; }
public ViewDataDictionary<TModel> ViewData { get; set; }
}