here is the multigrouping.cs
/********
* @version : 0.8.2 - Professional Edition (Coolite Professional License)
* @author : Coolite Inc. http://www.ext.net/
* @date : 2009-08-05
* @copyright : Copyright (c) 2006-2009, Coolite Inc. (http://www.ext.net/). All rights reserved.
* @license : See license.txt and http://www.ext.net/license/.
********/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Web.UI;
using System.Collections;
using System.Xml;
using System.Collections.Specialized;
using System.Web;
using System.Web.UI.WebControls;
using Ext.Net.Utilities;
using Newtonsoft.Json;
using System.IO;
namespace Ext.Net
{
[Designer(typeof(EmptyDesigner))]
public class MultiGroupingStore : Store, IPostBackEventHandler, ICustomConfigSerialization
{
protected override List<ResourceItem> Resources
{
get
{
List<ResourceItem> baseList = base.Resources;
baseList.Capacity += 1;
baseList.Add(new ClientScriptItem(typeof(MultiGroupingStore), "Ext.Net.Build.Resources.Ext.Net.ux.extensions.multigrouping.multigrouping.js", "/ux/extensions/multigrouping/multigrouping.js"));
return baseList;
}
}
public override string XType
{
get
{
return "multigroupstore";
}
}
[Category("0. About")]
public override string InstanceOf
{
get
{
return "Ext.ux.MultiGroupingStore";
}
}
/// <summary>
/// The field name by which to sort the store's data (defaults to '').
/// </summary>
[ConfigOption("groupField", typeof(StringArrayJsonConverter))]
[TypeConverter(typeof(StringArrayConverter))]
[Category("Config Options")]
[DefaultValue(null)]
[Description("The field name by which to sort the store's data (defaults to '').")]
public virtual string[] GroupFieldArray
{
get
{
object obj = this.ViewState["GroupFieldArray"];
string[] groupfields = (obj == null) ? null : (string[])obj;
return groupfields;
}
set
{
this.ViewState["GroupFieldArray"] = value;
}
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (!this.DesignMode && !this.IsLazy)
{
this.Page.LoadComplete += Page_LoadComplete;
}
}
protected internal override bool IsIdRequired
{
get
{
return true;
}
}
void Page_LoadComplete(object sender, EventArgs e)
{
if (this.ParentComponent == null || (RequestManager.IsMicrosoftAjaxRequest && !this.IsInUpdatePanelRefresh))
{
return;
}
Component parent = this.ParentComponent;
if (parent != null)
{
parent = this.ParentComponent;
while (parent != null && (parent.IsLazy || parent.IsLayout))
{
parent = parent.ParentComponent;
}
}
if (parent != null)
{
parent.BeforeClientInit += Parent_BeforeClientInit;
}
}
void Parent_BeforeClientInit(Observable sender)
{
this.ForcePreRender();
}
internal override void ForcePreRender()
{
if (!RequestManager.IsAjaxRequest)
{
this.EnsureDataBound();
base.ForcePreRender();
}
}
private bool MemoryDataPresent
{
get { return this.Reader != null && this.Reader.Reader != null && (this.Data != null || this.JsonData.IsNotEmpty()); }
}
private string BuildParams(ParameterCollection parameters)
{
StringBuilder sb = new StringBuilder("function(store,options){if (!options.params){options.params = {};};");
sb.AppendFormat("Ext.apply(options.params,{0});", parameters.ToJson(2));
sb.AppendFormat("Ext.applyIf(options.params,{0});", parameters.ToJson(1));
sb.Append("}");
return sb.ToString();
}
private IDictionary keys;
private IDictionary values;
private IDictionary oldValues;
private bool needRetrieve;
private ConfirmationRecord confirmation;
private XmlNode record;
void IPostBackEventHandler.RaisePostBackEvent(string eventArgument)
{
if (RequestManager.IsAjaxRequest)
{
if (eventArgument.IsEmpty())
{
return;
}
this.RaiseAjaxPostBackEvent(eventArgument);
return;
}
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (RequestManager.IsAjaxRequest && this.ParentForm == null)
{
this.Page.LoadComplete += new EventHandler(Store_LoadComplete);
}
}
private void Store_LoadComplete(object sender, EventArgs e)
{
if (this.IsDynamic)
{
return;
}
if (this.Page == null)
{
return;
}
string _ea = this.Page.Request["__EVENTARGUMENT"];
if (_ea.IsNotEmpty())
{
string _et = this.Page.Request["__EVENTTARGET"];
if (_et == this.UniqueID)
{
RaiseAjaxPostBackEvent(_ea);
}
return;
}
if (this.SubmitConfig == null)
{
return;
}
XmlNode eventArgumentNode = this.SubmitConfig.SelectSingleNode("config/__EVENTARGUMENT");
if (eventArgumentNode == null)
{
throw new InvalidOperationException(
"Incorrect submit config - the '__EVENTARGUMENT' parameter is absent");
}
XmlNode eventTargetNode = this.SubmitConfig.SelectSingleNode("config/__EVENTTARGET");
if (eventTargetNode == null)
{
throw new InvalidOperationException(
"Incorrect submit config - the '__EVENTTARGET' parameter is absent");
}
if (eventTargetNode.InnerText == this.UniqueID)
{
RaiseAjaxPostBackEvent(eventArgumentNode.InnerText);
}
}
private BeforeStoreChangedEventArgs changingEventArgs;
private void DoSaving(string jsonData, XmlNode callbackParameters)
{
changingEventArgs = new BeforeStoreChangedEventArgs(jsonData, null, callbackParameters);
ConfirmationList confirmationList = null;
if (this.UseIdConfirmation && this.Reader.Reader != null)
{
confirmationList = changingEventArgs.DataHandler.BuildConfirmationList(GetIdColumnName());
}
changingEventArgs.ConfirmationList = confirmationList;
this.OnBeforeStoreChanged(changingEventArgs);
Exception ex = null;
try
{
if (!changingEventArgs.Cancel)
{
this.MakeChanges();
}
}
catch (Exception e)
{
ex = e;
}
AfterStoreChangedEventArgs eStoreChanged = new AfterStoreChangedEventArgs(true, ex, confirmationList);
this.OnAfterStoreChanged(eStoreChanged);
if (eStoreChanged.Exception != null && !eStoreChanged.ExceptionHandled)
{
throw new Exception(ex.Message, ex);
}
}
private void MakeChanges()
{
bool noDs = this.DataSourceID.IsEmpty();
IDataSource ds = null;
if (!noDs)
{
ds = this.GetDataSource();
}
if (ds == null && !noDs)
{
throw new HttpException("Can't find DataSource");
}
if (this.Reader.Reader == null)
{
throw new InvalidOperationException("The Store does not contain a Reader.");
}
XmlDocument xml = changingEventArgs.DataHandler.XmlData;
if (noDs || ds.GetView("").CanUpdate)
{
this.MakeUpdates(ds, xml);
}
if (noDs || ds.GetView("").CanDelete)
{
this.MakeDeletes(ds, xml);
}
if (noDs || ds.GetView("").CanInsert)
{
this.MakeInsertes(ds, xml);
}
}
private string GetIdColumnName()
{
string id = "";
if (this.Reader.Reader != null)
{
id = this.Reader.Reader.IDField;
}
return id;
}
private void MakeUpdates(IDataSource ds, XmlDocument xml)
{
XmlNodeList updatingRecords = xml.SelectNodes("records/Updated/record");
string id = GetIdColumnName();
foreach (XmlNode node in updatingRecords)
{
record = node;
values = new SortedList(this.Reader.Reader.Fields.Count);
keys = new SortedList();
oldValues = new SortedList();
foreach (RecordField field in this.Reader.Reader.Fields)
{
XmlNode keyNode = node.SelectSingleNode(field.Name);
values[field.Name] = keyNode != null ? keyNode.InnerText : null;
}
confirmation = null;
if (id.IsNotEmpty())
{
XmlNode keyNode = node.SelectSingleNode(id);
string idStr = keyNode != null ? keyNode.InnerText : null;
int idInt;
if (int.TryParse(idStr, out idInt))
{
keys[id] = idInt;
}
else
{
keys[id] = idStr;
}
if (this.UseIdConfirmation && keys[id] != null)
{
confirmation = changingEventArgs.ConfirmationList[keys[id].ToString()];
}
}
BeforeRecordUpdatedEventArgs eBeforeRecordUpdated = new BeforeRecordUpdatedEventArgs(record, keys, values, oldValues, confirmation);
this.OnBeforeRecordUpdated(eBeforeRecordUpdated);
if (eBeforeRecordUpdated.CancelAll)
{
break;
}
if (eBeforeRecordUpdated.Cancel)
{
continue;
}
if (ds != null)
{
ds.GetView("").Update(keys, values, oldValues, this.UpdateCallback);
}
else
{
this.UpdateCallback(0, null);
}
}
}
private void MakeDeletes(IDataSource ds, XmlDocument xml)
{
XmlNodeList deletingRecords = xml.SelectNodes("records/Deleted/record");
string id = GetIdColumnName();
foreach (XmlNode node in deletingRecords)
{
record = node;
values = new SortedList(0);
keys = new SortedList();
oldValues = new SortedList(0);
confirmation = null;
if (id.IsNotEmpty())
{
XmlNode keyNode = node.SelectSingleNode(id);
string idStr = keyNode != null ? keyNode.InnerText : null;
int idInt;
if (int.TryParse(idStr, out idInt))
{
keys[id] = idInt;
}
else
{
keys[id] = idStr;
}
if (this.UseIdConfirmation && keys[id] != null)
{
confirmation = changingEventArgs.ConfirmationList[keys[id].ToString()];
}
}
BeforeRecordDeletedEventArgs eBeforeRecordDeleted = new BeforeRecordDeletedEventArgs(record, keys, confirmation);
this.OnBeforeRecordDeleted(eBeforeRecordDeleted);
if (eBeforeRecordDeleted.CancelAll)
{
break;
}
if (eBeforeRecordDeleted.Cancel)
{
continue;
}
if (ds != null)
{
ds.GetView("").Delete(keys, oldValues, DeleteCallback);
}
else
{
this.DeleteCallback(0, null);
}
}
if (deletingRecords.Count > 0)
{
needRetrieve = true;
}
}
private void MakeInsertes(IDataSource ds, XmlDocument xml)
{
XmlNodeList insertingRecords = xml.SelectNodes("records/Created/record");
string id = GetIdColumnName();
foreach (XmlNode node in insertingRecords)
{
record = node;
values = new SortedList(this.Reader.Reader.Fields.Count);
keys = new SortedList();
oldValues = new SortedList();
foreach (RecordField field in this.Reader.Reader.Fields)
{
XmlNode keyNode = node.SelectSingleNode(field.Name);
values[field.Name] = keyNode != null ? keyNode.InnerText : null;
}
confirmation = null;
if (id.IsNotEmpty())
{
XmlNode keyNode = node.SelectSingleNode(id);
if (this.UseIdConfirmation && keyNode != null && keyNode.InnerText.IsNotEmpty())
{
confirmation = changingEventArgs.ConfirmationList[keyNode.InnerText];
}
}
BeforeRecordInsertedEventArgs eBeforeRecordInserted = new BeforeRecordInsertedEventArgs(record, keys, values, confirmation);
this.OnBeforeRecordInserted(eBeforeRecordInserted);
if (eBeforeRecordInserted.CancelAll)
{
break;
}
if (eBeforeRecordInserted.Cancel)
{
continue;
}
if (ds != null)
{
ds.GetView("").Insert(values, InsertCallback);
}
else
{
this.InsertCallback(0, null);
}
}
if (insertingRecords.Count > 0)
{
needRetrieve = true;
}
}
bool UpdateCallback(int recordsAffected, Exception exception)
{
if (confirmation != null && recordsAffected > 0)
{
confirmation.ConfirmRecord();
}
AfterRecordUpdatedEventArgs eAfterRecordUpdated = new AfterRecordUpdatedEventArgs(record, recordsAffected, exception, keys, values, oldValues, confirmation);
this.OnAfterRecordUpdated(eAfterRecordUpdated);
return eAfterRecordUpdated.ExceptionHandled;
}
bool DeleteCallback(int recordsAffected, Exception exception)
{
if (confirmation != null && recordsAffected > 0)
{
confirmation.ConfirmRecord();
}
AfterRecordDeletedEventArgs eAfterRecordDeleted = new AfterRecordDeletedEventArgs(record, recordsAffected, exception, keys, confirmation);
this.OnAfterRecordDeleted(eAfterRecordDeleted);
return eAfterRecordDeleted.ExceptionHandled;
}
bool InsertCallback(int recordsAffected, Exception exception)
{
if (confirmation != null && recordsAffected > 0)
{
confirmation.ConfirmRecord();
}
AfterRecordInsertedEventArgs eAfterRecordInserted = new AfterRecordInsertedEventArgs(record, recordsAffected, exception, keys, values, confirmation);
this.OnAfterRecordInserted(eAfterRecordInserted);
return eAfterRecordInserted.ExceptionHandled;
}
/* ------------------------------------------------------------------------------------------*/
private bool success = true;
private string msg;
private void RaiseAjaxPostBackEvent(string eventArgument)
{
bool needConfirmation = false;
try
{
if (eventArgument.IsEmpty())
{
throw new ArgumentNullException("eventArgument");
}
XmlNode xmlData = this.SubmitConfig;
string data = null;
XmlNode parametersNode = null;
if (xmlData != null)
{
parametersNode = xmlData.SelectSingleNode("config/extraParams");
XmlNode serviceNode = xmlData.SelectSingleNode("config/serviceParams");
if (serviceNode != null)
{
data = serviceNode.InnerText;
}
}
string action = eventArgument;
BeforeDirectEventArgs e = new BeforeDirectEventArgs(action, data, parametersNode);
this.OnAjaxPostBack(e);
PageProxy dsp = this.Proxy.Proxy as PageProxy;
if (this.AutoDecode && data.IsNotEmpty())
{
data = HttpUtility.HtmlDecode(data);
}
switch (action)
{
case "update":
if (data == null)
{
throw new InvalidOperationException("No data in request");
}
needConfirmation = this.UseIdConfirmation;
this.DoSaving(data, parametersNode);
if (this.RefreshAfterSaving == RefreshAfterSavingMode.None || dsp != null)
{
needRetrieve = false;
}
break;
case "refresh":
needRetrieve = true;
StoreRefreshDataEventArgs refreshArgs = new StoreRefreshDataEventArgs(parametersNode);
this.OnRefreshData(refreshArgs);
if (dsp != null)
{
if (refreshArgs.Total > -1)
{
dsp.Total = refreshArgs.Total;
}
}
break;
case "submit":
needRetrieve = false;
if (data == null)
{
throw new InvalidOperationException("No data in request");
}
StoreSubmitDataEventArgs args = new StoreSubmitDataEventArgs(data, parametersNode);
this.OnSubmitData(args);
break;
}
}
catch (Exception ex)
{
success = false;
msg = this.IsDebugging ? ex.ToString() : ex.Message;
if (this.ResourceManager.RethrowAjaxExceptions)
{
throw;
}
}
AfterDirectEventArgs eAjaxPostBackResult = new AfterDirectEventArgs(new Response(success, msg));
this.OnAjaxPostBackResult(eAjaxPostBackResult);
StoreResponseData response = new StoreResponseData();
if (needRetrieve && eAjaxPostBackResult.Response.Success)
{
if (this.RequiresDataBinding)
{
this.DataBind();
}
response.Data = this.Data != null ? JSON.Serialize(this.Data) : this.JsonData;
PageProxy dsp = this.Proxy.Proxy as PageProxy;
response.Total = dsp != null ? dsp.Total : 0;
}
if (needConfirmation)
{
response.Confirmation = changingEventArgs.ConfirmationList;
}
eAjaxPostBackResult.Response.Data = response.ToString();
ResourceManager.ServiceResponse = eAjaxPostBackResult.Response;
}
public string ToScript(Control owner)
{
return "new Ext.ux.MultiGroupingStore(".ConcatWith(new ClientConfig().Serialize(this, true), ")");
}
}
[Designer(typeof(EmptyDesigner))]
public class MultiGroupingView : GroupingView
{
protected override List<ResourceItem> Resources
{
get
{
List<ResourceItem> baseList = base.Resources;
baseList.Capacity += 1;
baseList.Add(new ClientScriptItem(typeof(MultiGroupingView), "Ext.Net.Build.Resources.Ext.Net.ux.extensions.multigrouping.multigrouping.js", "/ux/extensions/multigrouping/multigrouping.js"));
return baseList;
}
}
public override string XType
{
get
{
return "multigroupview";
}
}
public override string InstanceOf
{
get
{
return "Ext.ux.MultiGroupingView";
}
}
}
[Designer(typeof(EmptyDesigner))]
public class MultiGroupingPanel : GridPanel
{
protected override List<ResourceItem> Resources
{
get
{
List<ResourceItem> baseList = base.Resources;
baseList.Capacity += 1;
baseList.Add(new ClientScriptItem(typeof(MultiGroupingPanel), "Ext.Net.Build.Resources.Ext.Net.ux.extensions.multigrouping.multigrouping.js", "/ux/extensions/multigrouping/multigrouping.js"));
return baseList;
}
}
public override string XType
{
get
{
return "multigroupgridpanel";
}
}
public override string InstanceOf
{
get
{
return "Ext.ux.MultiGroupingPanel";
}
}
protected override void OnBeforeClientInit(Observable sender)
{
base.OnBeforeClientInit(sender);
this.CheckColumns();
if (this.SelectionMemoryProxy && this.MemoryIDField.IsEmpty() && this.StoreID.IsNotEmpty())
{
Store store = ControlUtils.FindControl(this, this.StoreID) as Store;
if (store != null && store.Reader.Count > 0)
{
string id = store.Reader.Reader.IDField;
if (id.IsNotEmpty())
{
this.MemoryIDField = id;
}
}
}
}
//public void RegisterColumnPlugins()
//{
// Ext.EnsureAjaxEvent();
// this.AddScript("{0}.initColumnPlugins({1}, true);", this.ClientID, this.GetColumnPlugins());
//}
private void CheckColumns()
{
string plugins = this.GetColumnPlugins();
if (plugins.Length > 2)
{
this.CustomConfig.Add(new ConfigItem("columnPlugins", plugins, ParameterMode.Raw));
}
}
private string GetColumnPlugins()
{
StringBuilder sb = new StringBuilder("[");
for (int i = 0; i < this.ColumnModel.Columns.Count; i++)
{
CommandColumn cmdCol = this.ColumnModel.Columns[i] as CommandColumn;
ImageCommandColumn imgCmdCol = this.ColumnModel.Columns[i] as ImageCommandColumn;
Column column = this.ColumnModel.Columns[i] as Column;
if (column != null && column.Commands.Count > 0 && imgCmdCol == null)
{
this.ResourceManager.RegisterClientStyleInclude("Ext.Net.Build.Resources.Ext.Net.ux.plugins.commandcolumn.commandcolumn.css");
continue;
}
if (cmdCol != null || imgCmdCol != null)
{
sb.Append(i + ",");
this.ResourceManager.RegisterClientStyleInclude("Ext.Net.Build.Resources.Ext.Net.ux.plugins.commandcolumn.commandcolumn.css");
continue;
}
CheckColumn cc = this.ColumnModel.Columns[i] as CheckColumn;
if (cc != null && cc.Editable)
{
sb.Append(i + ",");
continue;
}
}
if (sb[sb.Length - 1] == ',')
{
sb.Remove(sb.Length - 1, 1);
}
sb.Append("]");
return sb.ToString();
}
protected override void OnAfterClientInit(Observable sender)
{
base.OnAfterClientInit(sender);
this.CheckAutoExpand();
}
protected virtual void CheckAutoExpand()
{
if (this.AutoExpandColumn.IsNotEmpty())
{
if (this.AutoExpandColumn.Test("^\\d+$"))
{
return;
}
bool found = false;
foreach (ColumnBase column in this.ColumnModel.Columns)
{
if (column.ColumnID == this.AutoExpandColumn)
{
found = true;
break;
}
}
if (!found)
{
throw new ArgumentException("The auto expand Column with ID='".ConcatWith(this.AutoExpandColumn, "' is not found!"));
}
}
}
//private GridPanelListeners listeners;
/// <summary>
/// Client-side JavaScript EventHandlers
/// </summary>
//[ClientConfig("listeners", JsonMode.Object)]
//[Category("Events")]
//[Themeable(false)]
//[NotifyParentProperty(true)]
//[PersistenceMode(PersistenceMode.InnerProperty)]
//[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
//[Description("Client-side JavaScript EventHandlers")]
//[ViewStateMember]
//public GridPanelListeners Listeners
//{
// get
// {
// if (this.listeners == null)
// {
// this.listeners = new GridPanelListeners();
// this.listeners.InitOwners(this);
// }
// return this.listeners;
// }
//}
//private GridPanelAjaxEvents ajaxEvents;
/// <summary>
/// Server-side Ajax EventHandlers
/// </summary>
//[Category("Events")]
//[Themeable(false)]
//[NotifyParentProperty(true)]
//[PersistenceMode(PersistenceMode.InnerProperty)]
//[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
//[Description("Server-side Ajax EventHandlers")]
//[ViewStateMember]
//public GridPanelAjaxEvents AjaxEvents
//{
// get
// {
// if (this.ajaxEvents == null)
// {
// this.ajaxEvents = new GridPanelAjaxEvents();
// this.ajaxEvents.InitOwners(this);
// if (this.IsTrackingViewState)
// {
// ((IStateManager)this.ajaxEvents).TrackViewState();
// }
// }
// return this.ajaxEvents;
// }
//}
protected override void PageLoadComplete(object sender, EventArgs e)
{
base.PageLoadComplete(sender, e);
//Here is we must add view templates because LazyObservable incorrect hosts inner controls
if (this.View.View != null)
{
this.Controls.Add(this.View.View.Templates.Header);
this.LazyItems.Add(this.View.View.Templates.Header);
}
}
protected override bool LoadPostData(string postDataKey, NameValueCollection postCollection)
{
bool result = base.LoadPostData(postDataKey, postCollection);
string val = postCollection[this.ClientID.ConcatWith("_SM")];
if (val != null && this.SelectionModel.Primary != null)
{
JsonSerializer serializer = new JsonSerializer();
serializer.MissingMemberHandling = MissingMemberHandling.Ignore;
StringReader sr = new StringReader(val);
if (this.SelectionModel.Primary is RowSelectionModel)
{
SelectedRowCollection ids = (SelectedRowCollection)serializer.Deserialize(sr, typeof(SelectedRowCollection));
(this.SelectionModel.Primary as RowSelectionModel).SetSelection(ids);
}
else if (this.SelectionModel.Primary is CellSelectionModel)
{
SelectedCellSerializable cell = (SelectedCellSerializable)serializer.Deserialize(sr, typeof(SelectedCellSerializable));
if (cell != null)
{
CellSelectionModel sm = this.SelectionModel.Primary as CellSelectionModel;
sm.SelectedCell.RowIndex = cell.RowIndex;
sm.SelectedCell.ColIndex = cell.ColIndex;
sm.SelectedCell.RecordID = cell.RecordID;
sm.SelectedCell.Name = cell.Name;
sm.SelectedCell.Value = cell.Value;
}
}
}
return result;
}
}
}