using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web.UI; using System.Web.UI.WebControls; using System.Collections; using System.Reflection; using System.Runtime.Serialization; using System.ComponentModel; namespace jqGrid { // container for all the items stored in the view state internal class StateManagerViewState { public StateManagerViewState() { } public StateManagerViewState(StateBag viewState) { _viewState = viewState; } private StateBag _viewState = null; private Dictionary _objectStorage = new Dictionary(); private bool _isTrackingViewState = false; private StateBag ViewState { get { if (_viewState == null) { _viewState = new StateBag(false); if (_isTrackingViewState) ((IStateManager)_viewState).TrackViewState(); } return _viewState; } } public int GetPropertyCount() { if (typeof(IStateManager).IsAssignableFrom(typeof(T))) return _objectStorage.Count; else return _viewState.Count; } /// /// Providing this enumerable allows us to use this class as a state managed dictionary, similar to /// how we have a state managed collection, above. We just will store the dictionary items right in the /// viewstate bag. Since we only deal with string property names, the dictionary must be limited to a key type of string /// /// public IEnumerator> GetProperties() { if (typeof(IStateManager).IsAssignableFrom(typeof(T))) foreach (KeyValuePair item in _objectStorage) yield return new KeyValuePair(item.Key, (T)item.Value); else { if (_viewState != null) foreach (DictionaryEntry item in _viewState) yield return new KeyValuePair((string)item.Key, (T)((StateItem)item.Value).Value); } } public bool IsPropSet(string propertyName) { return (_viewState != null && _viewState[propertyName] != null) || (_objectStorage.ContainsKey(propertyName) && _objectStorage[propertyName] != null); } public T GetProp(T defaultValue, string propertyName) { if (ViewState[propertyName] == null) { if (defaultValue != null) { ViewState[propertyName] = defaultValue; if (_isTrackingViewState) ViewState.SetItemDirty(propertyName, true); } else return defaultValue; } return (T)ViewState[propertyName]; } public void SetProp(T value, string propertyName) { ViewState[propertyName] = value; if (_isTrackingViewState) ViewState.SetItemDirty(propertyName, true); } public T GetNestedProp(string propertyName) where T : class, IStateManager, new() { T returnVal = null; if (_objectStorage.ContainsKey(propertyName) == false) { _objectStorage[propertyName] = returnVal = new T(); if (_isTrackingViewState) returnVal.TrackViewState(); } else returnVal = _objectStorage[propertyName] as T; return returnVal; } public void SetNestedProp(T value, string propertyName) where T : class, IStateManager { _objectStorage[propertyName] = value; } public bool IsTrackingViewState { get { return _isTrackingViewState; } } public object SaveViewState() { List objs = new List(); // always provide an object for this state in the 0th element, even if there is no view state object firstObject = null; if (_viewState != null) firstObject = ((IStateManager)_viewState).SaveViewState(); objs.Add(firstObject); // store named pairs, the First being the Propery to use to construct the object, and the second being the saved viewstate foreach (KeyValuePair kvp in _objectStorage) { if (kvp.Value != null) objs.Add(new Pair(kvp.Key, kvp.Value.SaveViewState())); else { // objects that have been set to null can't obviously save state, so set // the Second to null. It will not be an object[] (SaveViewState() returns an object[]), and we can pick it back // up on the Load as a null. There we can actually just set the Object property to null // directly, instead of loading view state objs.Add(new Pair(kvp.Key, null)); } } return objs.ToArray(); } public void LoadViewState(object savedState, object stateManagedObject) { object[] objs = savedState as object[]; if (objs != null) { // this objects state is always in the 0th element if (objs.Length > 0 && objs[0] != null) ((IStateManager)ViewState).LoadViewState(objs[0]); // all the rest come in as pairs, with the name of the property to construct in the First property, and the viewstate in the Second for (int ix = 1; ix < objs.Length; ix++) if (objs[ix] is Pair) { // construct the property by name PropertyInfo pi = stateManagedObject.GetType().GetProperty((string)((Pair)objs[ix]).First); if (pi != null) { object second = ((Pair)objs[ix]).Second; if (second == null) { // this was an object property that was set to null (since the Second is not an object[], but // rather null). Just call the Set on it with null as its value. pi.SetValue(stateManagedObject, null, null); } else { // this will get the property's current object, or instanciate a new one if not set. Then we can tell it to load its view state // with the stuff we just got in the second parameter IStateManager prop = pi.GetValue(stateManagedObject, null) as IStateManager; if (prop != null) prop.LoadViewState(second); } } } } } public void TrackViewState() { ((IStateManager)ViewState).TrackViewState(); foreach (KeyValuePair kvp in _objectStorage) if (kvp.Value != null) kvp.Value.TrackViewState(); _isTrackingViewState = true; } public void SetDirty() { ViewState.SetDirty(true); } public void SetItemDirty(string propertyName) { ViewState.SetItemDirty(propertyName, true); } } public abstract class StateManager : IStateManager { internal StateManagerViewState _viewStateContainer = new StateManagerViewState(); public bool IsPropSet(string propertyName) { return _viewStateContainer.IsPropSet(propertyName); } protected T GetProp(T defaultValue, string PropName) { return _viewStateContainer.GetProp(defaultValue, PropName); } public T GetProp(string propertyName) { return _viewStateContainer.GetProp(default(T), propertyName); } protected void SetProp(T value, string PropName) { _viewStateContainer.SetProp(value, PropName); } protected T GetNestedProp(string propertyName) where T : class, IStateManager, new() { return _viewStateContainer.GetNestedProp(propertyName); } protected void SetNestedProp(T value, string PropName) where T : class, IStateManager { _viewStateContainer.SetNestedProp(value, PropName); } bool IStateManager.IsTrackingViewState { get { return _viewStateContainer.IsTrackingViewState; } } object IStateManager.SaveViewState() { return _viewStateContainer.SaveViewState(); } void IStateManager.LoadViewState(object savedState) { _viewStateContainer.LoadViewState(savedState, this); } void IStateManager.TrackViewState() { _viewStateContainer.TrackViewState(); } public void SetDirty() { _viewStateContainer.SetDirty(); } } public class StateManagerWebControl : WebControl { private StateManagerViewState _viewStateContainer; public StateManagerWebControl() : base() { _viewStateContainer = new StateManagerViewState(ViewState); } public StateManagerWebControl(HtmlTextWriterTag tag) : base(tag) { _viewStateContainer = new StateManagerViewState(ViewState); } public bool IsPropSet(string propertyName) { return _viewStateContainer.IsPropSet(propertyName); } protected T GetProp(T defaultValue, string PropName) { return _viewStateContainer.GetProp(defaultValue, PropName); } public T GetProp(string propertyName) { return _viewStateContainer.GetProp(default(T), propertyName); } protected void SetProp(T value, string PropName) { _viewStateContainer.SetProp(value, PropName); } protected T GetNestedProp(string propertyName) where T : class, IStateManager, new() { return _viewStateContainer.GetNestedProp(propertyName); } protected void SetNestedProp(T value, string PropName) where T : class, IStateManager { _viewStateContainer.SetNestedProp(value, PropName); } protected override object SaveViewState() { return _viewStateContainer.SaveViewState(); } protected override void LoadViewState(object savedState) { _viewStateContainer.LoadViewState(savedState, this); } protected override void TrackViewState() { base.TrackViewState(); _viewStateContainer.TrackViewState(); } } public class StateManagerCollection : StateManagedCollection, IEnumerable where T : StateManager, new() { protected override Type[] GetKnownTypes() { return new Type[] { typeof(T) }; } protected override object CreateKnownType(int index) { switch (index) { case 0: return new T(); default: throw new ArgumentOutOfRangeException("Unknown Type"); } } protected override void SetDirtyObject(object o) { ((T)o).SetDirty(); } #region IList Members public int IndexOf(T item) { return ((IList)this).IndexOf(item); } public void Insert(int index, T item) { ((IList)this).Insert(index, item); if (((IStateManager)this).IsTrackingViewState) this.SetDirty(); } public void RemoveAt(int index) { ((IList)this).RemoveAt(index); if (((IStateManager)this).IsTrackingViewState) this.SetDirty(); } public T this[int index] { get { return (T)((IList)this)[index]; } set { ((IList)this)[index] = value; } } #endregion #region ICollection Members public void Add(T item) { ((IList)this).Add(item); if (((IStateManager)this).IsTrackingViewState) this.SetDirty(); } public bool Contains(T item) { return ((IList)this).Contains(item); } public void CopyTo(T[] array, int arrayIndex) { ((IList)this).CopyTo(array, arrayIndex); } public bool IsReadOnly { get { return false; } } public bool Remove(T item) { if (((IList)this).Contains(item)) { ((IList)this).Remove(item); if (((IStateManager)this).IsTrackingViewState) this.SetDirty(); return true; } return false; } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { foreach (T item in this) yield return item; } #endregion #region IEnumerable Members IEnumerator IEnumerable.GetEnumerator() { foreach (T item in this) yield return item; } #endregion } public class StateManagedDictionary : StateManager, IEnumerable> { // StateManager can be used as a Dictionary with IStateManager functionality, since the ViewState is just a collection of name/value pairs // just add a count and get to return all the items in the viewstate collection protected int Count { get { return _viewStateContainer.GetPropertyCount(); } } protected T GetProp(T defaultValue, string propertyName) { return base.GetProp(defaultValue, propertyName); } protected void SetProp(T value, string propertyName) { base.SetProp(value, propertyName); } public IEnumerator> GetEnumerator() { return _viewStateContainer.GetProperties(); } IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); } } }