Fix bugs in sizing TableLayoutPanel (Xamarin bug 18638)
[mono.git] / mcs / class / System.Web.Mvc / System.Web.Mvc / ViewUserControl.cs
1 /* ****************************************************************************\r
2  *\r
3  * Copyright (c) Microsoft Corporation. All rights reserved.\r
4  *\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
8  *\r
9  * You must not remove this notice, or any other, from this software.\r
10  *\r
11  * ***************************************************************************/\r
12 \r
13 namespace System.Web.Mvc {\r
14     using System;\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
20 \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
28 \r
29         public AjaxHelper Ajax {\r
30             get {\r
31                 if (_ajaxHelper == null) {\r
32                     _ajaxHelper = new AjaxHelper(ViewContext, this);\r
33                 }\r
34                 return _ajaxHelper;\r
35             }\r
36         }\r
37 \r
38         public HtmlHelper Html {\r
39             get {\r
40                 if (_htmlHelper == null) {\r
41                     _htmlHelper = new HtmlHelper(ViewContext, this);\r
42                 }\r
43                 return _htmlHelper;\r
44             }\r
45         }\r
46 \r
47         public object Model {\r
48             get {\r
49                 return ViewData.Model;\r
50             }\r
51         }\r
52 \r
53         public TempDataDictionary TempData {\r
54             get {\r
55                 return ViewPage.TempData;\r
56             }\r
57         }\r
58 \r
59         public UrlHelper Url {\r
60             get {\r
61                 return ViewPage.Url;\r
62             }\r
63         }\r
64 \r
65         [Browsable(false)]\r
66         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\r
67         public ViewContext ViewContext {\r
68             get {\r
69                 return _viewContext ?? ViewPage.ViewContext;\r
70             }\r
71             set {\r
72                 _viewContext = value;\r
73             }\r
74         }\r
75 \r
76         [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly",\r
77             Justification = "This is the mechanism by which the ViewUserControl gets its ViewDataDictionary object.")]\r
78         [Browsable(false)]\r
79         [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]\r
80         public ViewDataDictionary ViewData {\r
81             get {\r
82                 EnsureViewData();\r
83                 return _viewData;\r
84             }\r
85             set {\r
86                 SetViewData(value);\r
87             }\r
88         }\r
89 \r
90         [DefaultValue("")]\r
91         public string ViewDataKey {\r
92             get {\r
93                 return _viewDataKey ?? String.Empty;\r
94             }\r
95             set {\r
96                 _viewDataKey = value;\r
97             }\r
98         }\r
99 \r
100         internal ViewPage ViewPage {\r
101             get {\r
102                 ViewPage viewPage = Page as ViewPage;\r
103                 if (viewPage == null) {\r
104                     throw new InvalidOperationException(MvcResources.ViewUserControl_RequiresViewPage);\r
105                 }\r
106                 return viewPage;\r
107             }\r
108         }\r
109 \r
110         public HtmlTextWriter Writer {\r
111             get {\r
112                 return ViewPage.Writer;\r
113             }\r
114         }\r
115 \r
116         protected virtual void SetViewData(ViewDataDictionary viewData) {\r
117             _viewData = viewData;\r
118         }\r
119 \r
120         protected void EnsureViewData() {\r
121             if (_viewData != null) {\r
122                 return;\r
123             }\r
124 \r
125             // Get the ViewData for this ViewUserControl, optionally using the specified ViewDataKey\r
126             IViewDataContainer vdc = GetViewDataContainer(this);\r
127             if (vdc == null) {\r
128                 throw new InvalidOperationException(\r
129                     String.Format(\r
130                         CultureInfo.CurrentUICulture,\r
131                         MvcResources.ViewUserControl_RequiresViewDataProvider,\r
132                         AppRelativeVirtualPath));\r
133             }\r
134 \r
135             ViewDataDictionary myViewData = vdc.ViewData;\r
136 \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
142             }\r
143 \r
144             SetViewData(myViewData);\r
145         }\r
146 \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
152                 if (vdc != null) {\r
153                     return vdc;\r
154                 }\r
155             }\r
156             return null;\r
157         }\r
158 \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
165 \r
166             RenderViewAndRestoreContentType(containerPage, viewContext);\r
167         }\r
168 \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
173             // this.\r
174             string savedContentType = viewContext.HttpContext.Response.ContentType;\r
175             containerPage.RenderView(viewContext);\r
176             viewContext.HttpContext.Response.ContentType = savedContentType;\r
177         }\r
178 \r
179         private sealed class ViewUserControlContainerPage : ViewPage {\r
180             public ViewUserControlContainerPage(ViewUserControl userControl) {\r
181                 Controls.Add(userControl);\r
182             }\r
183         }\r
184     }\r
185 }\r