/* ****************************************************************************
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
* This software is subject to the Microsoft Public License (Ms-PL).
* A copy of the license can be found in the license.htm file included
* in this distribution.
*
* You must not remove this notice, or any other, from this software.
*
* ***************************************************************************/
namespace System.Web.Mvc{
using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Web.Mvc.Resources;
using System.Web.UI;
[FileLevelControlBuilder(typeof(ViewUserControlControlBuilder))]
public class ViewUserControl : UserControl, IViewDataContainer {
private AjaxHelper<object> _ajaxHelper;
private HtmlHelper<object> _htmlHelper;
private ViewContext _viewContext;
private ViewDataDictionary _viewData;
private string _viewDataKey;
public AjaxHelper<object> Ajax {
get {
if (_ajaxHelper == null) {
_ajaxHelper = new AjaxHelper<object>(ViewContext, this);
}
return _ajaxHelper;
}
}
public HtmlHelper<object> Html {
get {
if (_htmlHelper == null) {
_htmlHelper = new HtmlHelper<object>(ViewContext, this);
}
return _htmlHelper;
}
}
public object Model {
get {
return ViewData.Model;
}
}
public TempDataDictionary TempData {
get {
return ViewPage.TempData;
}
}
public UrlHelper Url {
get {
return ViewPage.Url;
}
}
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public ViewContext ViewContext {
get {
return _viewContext ?? ViewPage.ViewContext;
}
set {
_viewContext = value;
}
}
[SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly",
Justification = "This is the mechanism by which the ViewUserControl gets its ViewDataDictionary object.")]
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public ViewDataDictionary ViewData {
get {
EnsureViewData();
return _viewData;
}
set {
SetViewData(value);
}
}
[DefaultValue("")]
public string ViewDataKey {
get {
return _viewDataKey ?? String.Empty;
}
set {
_viewDataKey = value;
}
}
internal ViewPage ViewPage {
get {
ViewPage viewPage = Page as ViewPage;
if (viewPage == null) {
throw new InvalidOperationException(MvcResources.ViewUserControl_RequiresViewPage);
}
return viewPage;
}
}
public HtmlTextWriter Writer {
get {
return ViewPage.Writer;
}
}
protected virtual void SetViewData(ViewDataDictionary viewData) {
_viewData = viewData;
}
protected void EnsureViewData() {
if (_viewData != null) {
return;
}
// Get the ViewData for this ViewUserControl, optionally using the specified ViewDataKey
IViewDataContainer vdc = GetViewDataContainer(this);
if (vdc == null) {
throw new InvalidOperationException(
String.Format(
CultureInfo.CurrentUICulture,
MvcResources.ViewUserControl_RequiresViewDataProvider,
AppRelativeVirtualPath));
}
ViewDataDictionary myViewData = vdc.ViewData;
// If we have a ViewDataKey, try to extract the ViewData from the dictionary, otherwise
// return the container's ViewData.
if (!String.IsNullOrEmpty(ViewDataKey)) {
object target = myViewData.Eval(ViewDataKey);
myViewData = target as ViewDataDictionary ?? new ViewDataDictionary(myViewData) { Model = target };
}
SetViewData(myViewData);
}
private static IViewDataContainer GetViewDataContainer(Control control) {
// Walk up the control hierarchy until we find someone that implements IViewDataContainer
while (control != null) {
control = control.Parent;
IViewDataContainer vdc = control as IViewDataContainer;
if (vdc != null) {
return vdc;
}
}
return null;
}
public virtual void RenderView(ViewContext viewContext) {
ViewUserControlContainerPage containerPage = new ViewUserControlContainerPage(this);
RenderViewAndRestoreContentType(containerPage, viewContext);
}
internal static void RenderViewAndRestoreContentType(ViewPage containerPage, ViewContext viewContext) {
// We need to restore the Content-Type since Page.SetIntrinsics() will reset it. It's not possible
// to work around the call to SetIntrinsics() since the control's render method requires the
// containing page's Response property to be non-null, and SetIntrinsics() is the only way to set
// this.
string savedContentType = viewContext.HttpContext.Response.ContentType;
containerPage.RenderView(viewContext);
viewContext.HttpContext.Response.ContentType = savedContentType;
}
[SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "textWriter",
Justification = "This method existed in MVC 1.0 and has been deprecated.")]
[SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic",
Justification = "This method existed in MVC 1.0 and has been deprecated.")]
[Obsolete("The TextWriter is now provided by the ViewContext object passed to the RenderView method.", true /* error */)]
public void SetTextWriter(TextWriter textWriter) {
// this is now a no-op
}
private sealed class ViewUserControlContainerPage : ViewPage {
private readonly ViewUserControl _userControl;
public ViewUserControlContainerPage(ViewUserControl userControl) {
_userControl = userControl;
}
public override void ProcessRequest(HttpContext context) {
_userControl.ID = ViewPage.NextId();
Controls.Add(_userControl);
base.ProcessRequest(context);
}
}
}
}
|