// $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];
}
}
}