Pokračování minulého příspěvku - využití "property" třídy v prvcích ASP.NET.
Následující kód je jednoduchá předělávka třídy Property<T> do prostředí ASP.NET, kde se stav objektu uchovává ve ViewState.
public class WebProperty<T> : IWebProperty {
#region Constants
const string CACHE_KEY = "WebProperty.InitWebProperties.Cache";
#endregion
#region Fields
private StateBag viewState;
private string propertyKey;
#endregion
#region Properties
public T Value {
get {
if ( this.viewState == null ){ throw new NullReferenceException("ViewState can not be null."); }
object ret = this.viewState[this.propertyKey];
if ( ret == null ) {
return default( T );
}
return (T)ret;
}
set { this.viewState[this.propertyKey] = value; }
}
object IWebProperty.Value {
get { return this.Value; }
set { this.Value = (T)value; }
}
public StateBag ViewState{
get{ return this.viewState; }
set{ this.viewState = value; }
}
#endregion
#region Constructors
public WebProperty(string propertyKey) : this(propertyKey, null) {
}
public WebProperty(string propertyKey, StateBag viewState){
if ( propertyKey == null ) { throw new ArgumentNullException( "propertyKey" ); }
if ( propertyKey.Length == 0 ) { throw new ArgumentException( "Parameter 'propertyKey' must be longer than 0.", "propertyKey" ); }
this.propertyKey = propertyKey;
this.viewState = viewState;
}
#endregion
#region Static methods
// ... potrebne staticke metody ukazu nize
#endregion
}
V UserControlu pak takovouto vlastnost muzeme nadefinovat takto:
public partial class WebUserControl : System.Web.UI.UserControl{
protected readonly WebProperty<string> NejakyText;
public WebUserControl() {
WebProperty<object>.InitWebProperties( this, this.ViewState, true ); // toto volani bude za chvili vysvetleno
}
}
Protoze se kazda instance tridy WebProperty<T> musí odvolávat do ViewState nějakým klíčem, a nikdo jistě nechce tyto klíče vypisovat ručně ( alespoň já ne :) ), tak třída WebProperty<T> obsahuje statickou metodu InitWebProperties(), která nainicializuje tyto proměnné/vlastnosti za nás.
Předává se jí instance, která proměnné obsahuje, instance třídy StateBag, která bude použita pro načítání/ukládání hodnot a nakonec přepínač, zda si informace pro inicializaci proměných tohoto typu třídy má uložit do cache.
Kód, pro statických metod třídy WebProperty<T>:
private static FieldInfo[] GetPropertyFields( Type componentType, bool useCache ) {
object obj = HttpContext.Current.Cache[CACHE_KEY];
Dictionary<Type, FieldInfo[]> cache;
if ( obj is Dictionary<Type, FieldInfo[]> ) {
cache = (Dictionary<Type, FieldInfo[]>)obj;
}
else {
cache = new Dictionary<Type, FieldInfo[]>();
}
FieldInfo[] fields;
if ( useCache == false || cache.ContainsKey( componentType ) ) {
fields = (FieldInfo[])cache[componentType];
}
else {
Type basePropertyType = typeof( IWebProperty );
string strBasePropertyType = basePropertyType.FullName;
FieldInfo[] tmpFields = componentType.GetFields( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic );
List<FieldInfo> lst = new List<FieldInfo>();
foreach ( FieldInfo field in tmpFields ) {
Type fieldType = field.FieldType;
Type tmpType = fieldType.GetInterface( strBasePropertyType, false );
if ( tmpType == basePropertyType ) {
lst.Add( field );
}
}
fields = lst.ToArray();
}
if ( useCache ) {
cache[componentType] = fields;
HttpContext.Current.Cache[CACHE_KEY] = cache;
}
return fields;
}
public static void InitWebProperties( object instance, StateBag viewState ) {
InitWebProperties( instance, viewState, false );
}
public static void InitWebProperties( object instance, StateBag viewState, bool useCache ) {
if ( viewState == null ) { throw new ArgumentNullException( "viewState" ); }
Type mainType = instance.GetType();
FieldInfo[] fields = GetPropertyFields( mainType, useCache );
foreach ( FieldInfo field in fields ) {
string strID = "WebProperty_{0}" + field.Name;
IWebProperty property;
try {
property = (IWebProperty)Activator.CreateInstance( field.FieldType, strID );
}
catch ( Exception exc ) {
string msg = string.Format("Type '{0}' can not be created.", strID);
throw new TypeLoadException( msg, exc );
}
property.ViewState = viewState;
field.SetValue( instance, property );
}
}
Poslední ( třetí ) část bude o použití "property" třídy ve WinForms + automatická podpora práce s PropertiesWindow ( to se pravděpodobně bude týkat i asp.net ).