1 /* ****************************************************************************
\r
3 * Copyright (c) Microsoft Corporation. All rights reserved.
\r
5 * This software is subject to the Microsoft Public License (Ms-PL).
\r
6 * A copy of the license can be found in the license.htm file included
\r
7 * in this distribution.
\r
9 * You must not remove this notice, or any other, from this software.
\r
11 * ***************************************************************************/
\r
13 namespace System.Web.Mvc {
\r
15 using System.ComponentModel;
\r
16 using System.Diagnostics.CodeAnalysis;
\r
17 using System.Globalization;
\r
18 using System.Web.Mvc.Resources;
\r
19 using System.Web.UI;
\r
21 [FileLevelControlBuilder(typeof(ViewUserControlControlBuilder))]
\r
22 public class ViewUserControl : UserControl, IViewDataContainer {
\r
23 private AjaxHelper _ajaxHelper;
\r
24 private HtmlHelper _htmlHelper;
\r
25 private ViewContext _viewContext;
\r
26 private ViewDataDictionary _viewData;
\r
27 private string _viewDataKey;
\r
29 public AjaxHelper Ajax {
\r
31 if (_ajaxHelper == null) {
\r
32 _ajaxHelper = new AjaxHelper(ViewContext, this);
\r
38 public HtmlHelper Html {
\r
40 if (_htmlHelper == null) {
\r
41 _htmlHelper = new HtmlHelper(ViewContext, this);
\r
47 public object Model {
\r
49 return ViewData.Model;
\r
53 public TempDataDictionary TempData {
\r
55 return ViewPage.TempData;
\r
59 public UrlHelper Url {
\r
61 return ViewPage.Url;
\r
66 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
\r
67 public ViewContext ViewContext {
\r
69 return _viewContext ?? ViewPage.ViewContext;
\r
72 _viewContext = value;
\r
76 [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly",
\r
77 Justification = "This is the mechanism by which the ViewUserControl gets its ViewDataDictionary object.")]
\r
79 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
\r
80 public ViewDataDictionary ViewData {
\r
91 public string ViewDataKey {
\r
93 return _viewDataKey ?? String.Empty;
\r
96 _viewDataKey = value;
\r
100 internal ViewPage ViewPage {
\r
102 ViewPage viewPage = Page as ViewPage;
\r
103 if (viewPage == null) {
\r
104 throw new InvalidOperationException(MvcResources.ViewUserControl_RequiresViewPage);
\r
110 public HtmlTextWriter Writer {
\r
112 return ViewPage.Writer;
\r
116 protected virtual void SetViewData(ViewDataDictionary viewData) {
\r
117 _viewData = viewData;
\r
120 protected void EnsureViewData() {
\r
121 if (_viewData != null) {
\r
125 // Get the ViewData for this ViewUserControl, optionally using the specified ViewDataKey
\r
126 IViewDataContainer vdc = GetViewDataContainer(this);
\r
128 throw new InvalidOperationException(
\r
130 CultureInfo.CurrentUICulture,
\r
131 MvcResources.ViewUserControl_RequiresViewDataProvider,
\r
132 AppRelativeVirtualPath));
\r
135 ViewDataDictionary myViewData = vdc.ViewData;
\r
137 // If we have a ViewDataKey, try to extract the ViewData from the dictionary, otherwise
\r
138 // return the container's ViewData.
\r
139 if (!String.IsNullOrEmpty(ViewDataKey)) {
\r
140 object target = myViewData.Eval(ViewDataKey);
\r
141 myViewData = target as ViewDataDictionary ?? new ViewDataDictionary(myViewData) { Model = target };
\r
144 SetViewData(myViewData);
\r
147 private static IViewDataContainer GetViewDataContainer(Control control) {
\r
148 // Walk up the control hierarchy until we find someone that implements IViewDataContainer
\r
149 while (control != null) {
\r
150 control = control.Parent;
\r
151 IViewDataContainer vdc = control as IViewDataContainer;
\r
159 public virtual void RenderView(ViewContext viewContext) {
\r
160 // TODO: Remove this hack. Without it, the browser appears to always load cached output
\r
161 viewContext.HttpContext.Response.Cache.SetExpires(DateTime.Now);
\r
162 ViewUserControlContainerPage containerPage = new ViewUserControlContainerPage(this);
\r
163 // Tracing requires Page IDs to be unique.
\r
164 ID = Guid.NewGuid().ToString();
\r
166 RenderViewAndRestoreContentType(containerPage, viewContext);
\r
169 internal static void RenderViewAndRestoreContentType(ViewPage containerPage, ViewContext viewContext) {
\r
170 // We need to restore the Content-Type since Page.SetIntrinsics() will reset it. It's not possible
\r
171 // to work around the call to SetIntrinsics() since the control's render method requires the
\r
172 // containing page's Response property to be non-null, and SetIntrinsics() is the only way to set
\r
174 string savedContentType = viewContext.HttpContext.Response.ContentType;
\r
175 containerPage.RenderView(viewContext);
\r
176 viewContext.HttpContext.Response.ContentType = savedContentType;
\r
179 private sealed class ViewUserControlContainerPage : ViewPage {
\r
180 public ViewUserControlContainerPage(ViewUserControl userControl) {
\r
181 Controls.Add(userControl);
\r