// $Id: DataBindExtender.cs 14039 2010-07-08 18:48:53Z vladimirn $ using System; using System.ComponentModel; using System.Collections.Generic; using System.Web; using System.Web.UI; using System.Web.UI.Design; using AjaxControlToolkit; [assembly: TagPrefix("Bphx.Cool.Web", "bphx")] namespace Bphx.Cool.Web { /// /// A delegate to validate values. /// /// An extender instance. /// A value to validate. /// true for valid value, and false otherwise. public delegate bool ValueValidator(DataBindExtender extender, object value); /// /// A data bind extender control. /// [Designer(typeof(ExtenderControlDesigner))] [TargetControlType(typeof(Control))] public class DataBindExtender: ExtenderControlBase, IValidator { /// /// Creates a DataBindExtender instance. /// public DataBindExtender() { IsValid = true; } /// /// A data source. /// [Category("Data")] [Description("A data source that provides data.")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Bindable(true)] [ExtenderControlProperty(false)] public virtual object DataSource { get; set; } /// /// A data source member. /// [Category("Data")] [Description("A data member in the DataSource.")] [Bindable(true)] [ExtenderControlProperty(false)] public virtual string DataMember { get; set; } /// /// An optional data member validator. /// [Category("Data")] [Description("An optional data member validator.")] [Bindable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [ExtenderControlProperty(false)] public virtual ValueValidator Validator { get; set; } /// /// A read only data member indicator. /// [Category("Data")] [Description("Indicates whether the data member is read only.")] [DefaultValue(false)] [Bindable(true)] [ExtenderControlProperty(false)] public virtual bool ReadOnly { get; set; } /// /// A html escape indicator for the data member. /// [Category("Data")] [Description("Indicates whether to html escape the data member.")] [DefaultValue(false)] [Bindable(true)] [ExtenderControlProperty(false)] public virtual bool Escape { get; set; } /// /// A control property. /// [Category("Data")] [Description("A control property to bind to.")] [ExtenderControlProperty(false)] public virtual string ControlProperty { get; set; } /// /// Optional type converter. /// [Category("Data")] [Description("A type converter for the data member.")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Bindable(true)] [ExtenderControlProperty(false)] public virtual TypeConverter Converter { get; set; } /// /// Optional tag associated with extender. /// [Category("Data")] [Description("Optional tag associated with extender.")] [Bindable(true)] [ExtenderControlProperty(false)] public virtual string Tag { get { return GetPropertyValue("Tag", null as string); } set { SetPropertyValue("Tag", value); } } /// /// Gets or sets the client script that executes on component /// initialization time. /// [Category("Data")] [Description( "The client script that runs on component initialization time. " + "When javascript is invoked this refers to dom element that " + "corresponds to a target control.")] [Bindable(true)] [ExtenderControlProperty(false)] public virtual string OnClientInit { get { return GetPropertyValue("OnClientInit", ""); } set { SetPropertyValue("OnClientInit", value); } } #region IValidator Members /// /// Gets or sets the error message text generated when the condition /// being validated fails. /// [Category("Data")] [Description("A validation message")] [Bindable(true)] [ExtenderControlProperty(false)] public string ErrorMessage { get { return GetPropertyValue("ErrorMessage", null as string) ?? (Exception != null ? Exception.Message : ""); } set { SetPropertyValue("ErrorMessage", value); } } /// /// Gets or sets a value indicating whether the user-entered content in /// the specified control passes validation. /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Browsable(false)] public bool IsValid { get; set; } /// /// Gets or sets a validation exception. /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [Browsable(false)] public Exception Exception { get; set; } /// /// Gets a target control. /// [Browsable(false)] public new Control TargetControl { get { return base.TargetControl; } } /// /// Evaluates the condition it checks and updates IsValid property. /// public void Validate() { IsValid = true; Exception = null; try { Bind(false); } catch(Exception e) { IsValid = false; Exception = e; } } #endregion /// /// Binds data member to the control property, or vise versa. /// /// /// true to put data member into a control property, and /// false to get control property and update data member. /// public virtual void Bind(bool toControl) { if (ControlProperty == null) { // There is no binding. return; } var dataSource = DataSource; if (dataSource == null) { DataBind(); dataSource = DataSource; } if (Visible && Enabled && (toControl || !ReadOnly)) { if (dataSource != null) { var control = TargetControl; if (control != null) { var dataMember = DataMember; var pos = dataMember.LastIndexOf('.'); if (pos != -1) { dataMember = dataMember.Substring(pos + 1); dataSource = DataBinder.Eval(dataSource, dataMember.Substring(0, pos)); } var dataProperty = TypeDescriptor.GetProperties(dataSource)[dataMember]; if (dataProperty == null) { throw new InvalidOperationException("DataMember"); } var name = ControlProperty; object instance = control; pos = name.LastIndexOf('.'); if (pos != -1) { name = name.Substring(pos + 1); instance = DataBinder.Eval( instance, name.Substring(0, pos)); } var controlProperty = TypeDescriptor.GetProperties(instance)[name]; if (controlProperty == null) { throw new ArithmeticException("ControlProperty"); } if (toControl || !dataProperty.IsReadOnly) { var converter = Converter ?? dataProperty.Converter; if (toControl) { var value = dataProperty.GetValue(dataSource); if (converter != null) { if (converter.CanConvertTo(controlProperty.PropertyType)) { value = converter.ConvertTo(value, controlProperty.PropertyType); } } if (Escape) { string text = value as string; if (text != null) { value = HttpUtility.HtmlEncode(text); } } controlProperty.SetValue(control, value); } else { var value = controlProperty.GetValue(instance); if (Escape) { string text = value as string; if (text != null) { value = HttpUtility.HtmlEncode(text); } } if (converter != null) { if (converter.CanConvertFrom(controlProperty.PropertyType)) { value = converter.ConvertFrom(value); } } if ((value != null) && !dataProperty.PropertyType.IsAssignableFrom(value.GetType())) { if ((dataProperty.Converter != null) && dataProperty.Converter.CanConvertFrom(value.GetType())) { value = dataProperty.Converter.ConvertFrom(value); } else { value = Convert.ChangeType(value, dataProperty.PropertyType); } } var validator = Validator; if ((validator != null) && !validator(this, value)) { throw new ArgumentException(DataMember); } dataProperty.SetValue(dataSource, value); } } } } } } /// /// Adds this data binder to the page collection of Validators. /// /// An event arguments. protected override void OnInit(EventArgs e) { base.OnInit(e); if (Page != null) { Page.Validators.Add(this); } } /// /// Removes this control from the page collection of validators. /// /// An event handler. protected override void OnUnload(EventArgs e) { if (Page != null) { Page.Validators.Remove(this); } base.OnUnload(e); } /// /// Updates data binding. /// /// An event handler. protected override void OnPreRender(EventArgs e) { base.OnPreRender(e); if (Page != null) { // Do not bind control if entered value is not valid. if (!Page.IsPostBack || IsValid) { Bind(true); } if (!string.IsNullOrEmpty(OnClientInit) && Visible && Enabled && TargetControl.Visible) { // (function() { script }).apply($get(id)); Page.ClientScript.RegisterStartupScript( GetType(), ClientID, @"(function(){" + OnClientInit + @"}).apply($get(""" + TargetControl.ClientID + @"""));", true); } } } /// /// No scripts are used. /// protected override IEnumerable GetScriptDescriptors( Control targetControl) { return new ScriptDescriptor[0]; } /// /// No resources are used. /// protected override IEnumerable GetScriptReferences() { return new ScriptReference[0]; } } }