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