1 namespace System.Web.DynamicData {
2     using System.ComponentModel;
3     using System.Diagnostics.CodeAnalysis;
4     using System.Globalization;
5     using System.Web.Resources;
6     using System.Web.UI;
7     using System.Collections.Generic;
8     using System.Reflection;
9     using System.Web.UI.WebControls;
10     using System.Drawing;
11     using System.Diagnostics;
12 
13     /// <summary>
14     /// Control used to render Dynamic Data driven UI
15     /// </summary>
16     [ToolboxBitmap(typeof(DynamicControl), "DynamicControl.bmp")]
17     public class DynamicControl : Control, IAttributeAccessor, IFieldTemplateHost, IFieldFormattingOptions {
18 
19         private bool _customConvertEmptyStringToNullSet;
20         private bool _customApplyFormatInEditModeSet;
21         private MetaTable _table;
22         private IMetaTable _iMetaTable;
23         private IDictionary<string, string> _attributes;
24         private IMetaColumn _iMetaColumn;
25         private MetaColumn _column;
26 
27         /// <summary>
28         /// </summary>
DynamicControl()29         public DynamicControl() {
30         }
31 
DynamicControl(IMetaTable table)32         internal DynamicControl(IMetaTable table) {
33             _iMetaTable = table;
34         }
35 
DynamicControl(IMetaColumn column)36         internal DynamicControl(IMetaColumn column) {
37             _iMetaColumn = column;
38         }
39 
40         /// <param name="mode">The mode that the associated field template should be in (readonly, edit, insert)</param>
DynamicControl(DataBoundControlMode mode)41         public DynamicControl(DataBoundControlMode mode) {
42             Mode = mode;
43         }
44 
45         /// <summary>
46         /// The name of the column that this control handles
47         /// </summary>
48         [
49         Category("Data"),
50         DefaultValue(""),
51         ResourceDescription("DynamicControlFieldCommon_DataField")
52         ]
53         public string DataField {
54             get {
55                 object o = ViewState["DataField"];
56                 return ((o == null) ? String.Empty : (string)o);
57             }
58             set {
59                 if (!String.Equals(value, ViewState["DataField"])) {
60                     ViewState["DataField"] = value;
61                 }
62             }
63         }
64 
65         /// <summary>
66         /// The MetaColumn that this control is working with
67         /// </summary>
68         [Browsable(false)]
69         public MetaColumn Column {
70             get {
71                 return _column;
72             }
73             set {
74                 _column = value;
75                 _iMetaColumn = value;
76             }
77         }
78 
79         /// <summary>
80         /// The UIHint used by this control to locate the proper field template
81         /// </summary>
82         [
83         Category("Behavior"),
84         DefaultValue(""),
85         ResourceDescription("DynamicControlFieldCommon_UIHint")
86         ]
87         public virtual string UIHint {
88             get {
89                 object o = ViewState["UIHint"];
90                 return ((o == null) ? String.Empty : (string)o);
91             }
92             set {
93                 ViewState["UIHint"] = value;
94             }
95         }
96 
97         /// <summary>
98         /// Gets or sets the CSS class property of the DynamicControl
99         /// </summary>
100         [
101         Category("Appearance"),
102         DefaultValue(""),
103         CssClassProperty()
104         ]
105         public virtual string CssClass {
106             get {
107                 object o = ViewState["CssClass"];
108                 return ((o == null) ? String.Empty : (string)o);
109             }
110             set {
111                 ViewState["CssClass"] = value;
112             }
113         }
114 
115         /// <summary>
116         /// The MetaTable that this control is associated with
117         /// </summary>
118         [Browsable(false)]
119         public virtual MetaTable Table {
120             get {
121                 if (_table == null) {
122                     _table = this.FindMetaTable();
123 
124                     if (_table == null) {
125                         throw new Exception(String.Format(CultureInfo.CurrentCulture,
126                              DynamicDataResources.DynamicControl_ControlNeedsToExistInADataControlUsingDynamicDataSource));
127                     }
128                 }
129                 return _table;
130             }
131         }
132 
133         private IMetaTable IMetaTable {
134             get {
135                 return _iMetaTable ?? Table;
136             }
137         }
138 
139         private IMetaColumn IMetaColumn {
140             get {
141                 return _iMetaColumn;
142             }
143             set {
144                 _iMetaColumn = value;
145                 _column = value as MetaColumn;
146             }
147         }
148 
149         /// <summary>
150         /// The rendering mode: readonly, edit or insert
151         /// </summary>
152         [
153         DefaultValue(DataBoundControlMode.ReadOnly),
154         Category("Behavior"),
155         ResourceDescription("DynamicField_Mode")
156         ]
157         public DataBoundControlMode Mode {
158             get {
159                 object o = ViewState["Mode"];
160                 return ((o == null) ? DataBoundControlMode.ReadOnly : (DataBoundControlMode)o);
161             }
162             set {
163                 ViewState["Mode"] = value;
164             }
165         }
166 
167         /// <summary>
168         /// The validation group that the field template need to be in
169         /// </summary>
170         [
171         Category("Behavior"),
172         DefaultValue(""),
173         Themeable(false),
174         ResourceDescription("DynamicControlFieldCommon_ValidationGroup")
175         ]
176         public virtual string ValidationGroup {
177             get {
178                 object o = ViewState["ValidationGroup"];
179                 return ((o == null) ? String.Empty : (string)o);
180             }
181             set {
182                 ViewState["ValidationGroup"] = value;
183             }
184         }
185 
CreateControl()186         internal Control CreateControl() {
187             Debug.Assert(FieldTemplate == null);
188 
189             FieldTemplate = (Control)IMetaColumn.Model.FieldTemplateFactory.CreateFieldTemplate(Column, Mode, UIHint);
190             if (FieldTemplate != null) {
191                 ((IFieldTemplate)FieldTemplate).SetHost(this);
192 
193                 // If we got some extra attributes declared on the tag, assign them to the user control if it has matching properties
194                 if (_attributes != null) {
195                     var ucType = FieldTemplate.GetType();
196                     foreach (var entry in _attributes) {
197                         // Look for a public property by that name on th user control
198                         var propInfo = ucType.GetProperty(entry.Key, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
199                         if (propInfo != null) {
200                             // Convert the value to the type of the property and set it
201                             var value = PropertyConverter.ObjectFromString(propInfo.PropertyType, propInfo, entry.Value);
202                             propInfo.SetValue(FieldTemplate, value, null);
203                         }
204                     }
205                 }
206 
207                 // Give it the column name as its ID, unless there is already a control by that name
208                 string id = GetControlIDFromColumnName(IMetaColumn.Name);
209                 if (FindControl(id) == null)
210                     FieldTemplate.ID = id;
211             }
212             return FieldTemplate;
213         }
214 
215         /// <summary>
216         /// See base class documentation
217         /// </summary>
218         [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
OnInit(EventArgs e)219         protected override void OnInit(EventArgs e) {
220             base.OnInit(e);
221 
222             // Don't do anything in Design mode
223             if (DesignMode)
224                 return;
225 
226             ResolveColumn();
227             FieldTemplate = CreateControl();
228             // Add it to the tree
229             if (FieldTemplate != null) {
230                 Controls.Add(FieldTemplate);
231             }
232         }
233 
234         /// <summary>
235         /// Renders the underlying field template control. If this DynamicControl's CssClass tag is defined,
236         /// the underlying control's output will be wrapped in a span tag with that css class applied.
237         /// </summary>
238         /// <param name="writer"></param>
Render(HtmlTextWriter writer)239         protected override void Render(HtmlTextWriter writer) {
240 
241             // In Design mode, simply render the string Databound.  Ideally, we'd do something fancier
242             // that takes into account the type of the column.  But at lesat, rendering *something* makes
243             // the design layout look reasonable
244             if (DesignMode) {
245                 writer.Write(DynamicDataResources.DynamicControlDesignRender);
246                 return;
247             }
248 
249             // If there is a CSS class, output it in a span tag.  Otherwise, don't use any extra tag.
250             if (!String.IsNullOrEmpty(CssClass)) {
251                 writer.AddAttribute(HtmlTextWriterAttribute.Class, CssClass);
252                 writer.RenderBeginTag(HtmlTextWriterTag.Span);
253                 base.Render(writer);
254                 writer.RenderEndTag();
255             }
256             else {
257                 base.Render(writer);
258             }
259         }
260 
ResolveColumn()261         internal void ResolveColumn() {
262             if (IMetaColumn == null) {
263                 if (String.IsNullOrEmpty(DataField)) {
264                     throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,
265                         DynamicDataResources.DynamicControl_ControlMustHaveDateFieldAttribute, GetType().Name, ID));
266                 }
267 
268                 IMetaColumn = IMetaTable.GetColumn(DataField);
269 
270 
271                 // Try to get them various settings from the model, unless they were explicitely
272                 // specified on the control
273                 if (String.IsNullOrEmpty(UIHint)) {
274                     UIHint = IMetaColumn.UIHint;
275                 }
276                 if (String.IsNullOrEmpty(DataFormatString)) {
277                     DataFormatString = IMetaColumn.DataFormatString;
278                 }
279                 if (String.IsNullOrEmpty(NullDisplayText)) {
280                     NullDisplayText = IMetaColumn.NullDisplayText;
281                 }
282                 if (!_customConvertEmptyStringToNullSet) {
283                     ConvertEmptyStringToNull = IMetaColumn.ConvertEmptyStringToNull;
284                 }
285                 if (!_customApplyFormatInEditModeSet) {
286                     ApplyFormatInEditMode = IMetaColumn.ApplyFormatInEditMode;
287                 }
288                 if (ViewState["HtmlEncode"] == null) {
289                     HtmlEncode = IMetaColumn.HtmlEncode;
290                 }
291             }
292         }
293 
294         /// <summary>
295         /// The Field Template that was created for this control
296         /// </summary>
297         [Browsable(false)]
298         public Control FieldTemplate { get; private set; }
299 
GetControlIDFromColumnName(string columnName)300         internal static string GetControlIDFromColumnName(string columnName) {
301             return "__" + columnName;
302         }
303 
SetAttributes(IDictionary<string, string> attributes)304         internal void SetAttributes(IDictionary<string, string> attributes) {
305             _attributes = attributes;
306         }
307 
308         #region IAttributeAccessor Members
309 
310         /// <summary>
311         /// See IAttributeAccessor
312         /// </summary>
GetAttribute(string key)313         public string GetAttribute(string key) {
314             if (_attributes == null)
315                 return String.Empty;
316             return _attributes[key];
317         }
318 
319         /// <summary>
320         /// See IAttributeAccessor
321         /// </summary>
SetAttribute(string key, string value)322         public void SetAttribute(string key, string value) {
323             if (_attributes == null) {
324                 _attributes = new Dictionary<string, string>();
325             }
326             _attributes[key] = value;
327         }
328 
329         #endregion
330 
331         #region IFieldTemplateHost Members
332 
333         IFieldFormattingOptions IFieldTemplateHost.FormattingOptions {
334             get { return this; }
335         }
336 
337         #endregion
338 
339         #region IFieldFormattingOptions Members
340 
341         /// <summary>
342         /// See IFieldFormattingOptions
343         /// </summary>
344         [
345         Category("Behavior"),
346         DefaultValue(false),
347         ResourceDescription("DynamicControlFieldCommon_ConvertEmptyStringToNull")
348         ]
349         public bool ConvertEmptyStringToNull {
350             get {
351                 object o = ViewState["ConvertEmptyStringToNull"];
352                 return (o == null ? false : (bool)o);
353             }
354             set {
355                 _customConvertEmptyStringToNullSet = true;
356                 ViewState["ConvertEmptyStringToNull"] = value;
357             }
358         }
359 
360         /// <summary>
361         /// See IFieldFormattingOptions
362         /// </summary>
363         [
364         Category("Behavior"),
365         DefaultValue(false),
366         ResourceDescription("DynamicControlFieldCommon_ApplyFormatInEditMode")
367         ]
368         public bool ApplyFormatInEditMode {
369             get {
370                 object o = ViewState["ApplyFormatInEditMode"];
371                 return (o == null ? false : (bool)o);
372             }
373             set {
374                 _customApplyFormatInEditModeSet = true;
375                 ViewState["ApplyFormatInEditMode"] = value;
376             }
377         }
378 
379         /// <summary>
380         /// See IFieldFormattingOptions
381         /// </summary>
382         [
383         Category("Data"),
384         DefaultValue(""),
385         ResourceDescription("DynamicControlFieldCommon_DataFormatString")
386         ]
387         public string DataFormatString {
388             get {
389                 object o = ViewState["DataFormatString"];
390                 return (o == null ? String.Empty : (string)o);
391             }
392             set {
393                 ViewState["DataFormatString"] = value;
394             }
395         }
396 
397         /// <summary>
398         /// See IFieldFormattingOptions
399         /// </summary>
400         [
401         Category("Behavior"),
402         DefaultValue(true),
403         ResourceDescription("DynamicControlFieldCommon_HtmlEncode")
404         ]
405         public bool HtmlEncode {
406             get {
407                 object o = ViewState["HtmlEncode"];
408                 return (o == null ? true : (bool)o);
409             }
410             set {
411                 ViewState["HtmlEncode"] = value;
412             }
413         }
414 
415         /// <summary>
416         /// See IFieldFormattingOptions
417         /// </summary>
418         [
419         Category("Behavior"),
420         DefaultValue(""),
421         ResourceDescription("DynamicControlFieldCommon_NullDisplayText")
422         ]
423         public string NullDisplayText {
424             get {
425                 object o = ViewState["NullDisplayText"];
426                 return (o == null ? String.Empty : (string)o);
427             }
428             set {
429                 ViewState["NullDisplayText"] = value;
430             }
431         }
432 
433         #endregion
434     }
435 }
436