Index: ASP.NET/Common/Admin/Entity.aspx.cs.cst =================================================================== --- ASP.NET/Common/Admin/Entity.aspx.cs.cst (revision 505) +++ ASP.NET/Common/Admin/Entity.aspx.cs.cst (working copy) @@ -77,6 +77,16 @@ public partial class <%=entityName%> : System.Web.UI.Page { + /// + /// Handles the Init event of the Page. + /// + /// The source of the event. + /// The instance containing the event data. + protected void Page_Init(object sender, EventArgs e) + { + FormUtil.HandleGridViewSearchPanelState( GridViewSearchPanel1 ); + } + protected void Page_Load(object sender, EventArgs e) { FormUtil.RedirectAfterUpdate(GridView1, "<%=entityName%>.aspx?page={0}"); Index: Entities/EntityHelper.cst =================================================================== --- Entities/EntityHelper.cst (revision 505) +++ Entities/EntityHelper.cst (working copy) @@ -10,8 +10,8 @@ using System.Xml.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.ComponentModel; +using System.Text.RegularExpressions; - namespace <%=NameSpace%> { /// @@ -468,6 +468,25 @@ #endregion GetAttribute + #region Pascal to spaced helper + /// + /// Get the Pascal spaced version of a name. + /// + /// Name to be changed + /// PascalSpaced version of the name + public static string GetPascalSpacedName(string name) + { + if (string.IsNullOrEmpty(name)) + { + return string.Empty; + } + + Regex regex = new Regex("(?<=[a-z])(?[A-Z])|(?<=.)(?[A-Z])(?=[a-z])"); + return regex.Replace(name, " ${x}"); + + } + #endregion + <% if (false) { @@ -757,5 +776,5 @@ public T NewValue { get { return newValue; } } } #endregion - + } Index: NetTiers.cst =================================================================== --- NetTiers.cst (revision 505) +++ NetTiers.cst (working copy) @@ -2095,6 +2095,10 @@ this.GetTemplate("GridViewSearchPanel.cs.cst").SetProperty("RootNameSpace", RootNameSpace); this.GetTemplate("GridViewSearchPanel.cs.cst").SetProperty("BusinessLogicLayerNameSpace", BusinessLogicLayerNameSpace); this.RenderToFile("GridViewSearchPanel.cs.cst", rootPathWebLib + "\\UI\\GridViewSearchPanel.cs", true); + + AddFileNode(commonNode, "GridViewSearchPanelState.cs"); + this.GetTemplate("GridViewSearchPanelState.cs.cst").SetProperty("RootNameSpace", RootNameSpace); + this.RenderToFile("GridViewSearchPanelState.cs.cst", rootPathWebLib + "\\UI\\GridViewSearchPanelState.cs", true); // Generated strongly typed repeater if ( GenerateDataAccessLayer ) Index: TemplateLib/CreateTemplates.cs =================================================================== --- TemplateLib/CreateTemplates.cs (revision 505) +++ TemplateLib/CreateTemplates.cs (working copy) @@ -191,6 +191,7 @@ CodeTemplates.Add("BoundEntityDropDownField.cs.cst", base.CreateTemplate()); this.PerformStep(); CodeTemplates.Add("BoundRadioButtonField.cs.cst", base.CreateTemplate()); this.PerformStep(); CodeTemplates.Add("GridViewSearchPanel.cs.cst", base.CreateTemplate()); this.PerformStep(); + CodeTemplates.Add("GridViewSearchPanelState.cs.cst", base.CreateTemplate()); this.PerformStep(); CodeTemplates.Add("TableRepeater.cst", base.CreateTemplate()); this.PerformStep(); CodeTemplates.Add("ViewRepeater.cst", base.CreateTemplate()); this.PerformStep(); Index: TemplateLib/FrameworkTemplates.cst =================================================================== --- TemplateLib/FrameworkTemplates.cst (revision 505) +++ TemplateLib/FrameworkTemplates.cst (working copy) @@ -189,7 +189,8 @@ <%@ Register Name="BoundEntityDropDownField" Template="../WebLibrary/UI/BoundEntityDropDownField.cs.cst" MergeProperties="False" ExcludeProperties="" %> <%@ Register Name="BoundRadioButtonField" Template="../WebLibrary/UI/BoundRadioButtonField.cs.cst" MergeProperties="False" ExcludeProperties="" %> <%@ Register Name="GridViewSearchPanel" Template="../WebLibrary/UI/GridViewSearchPanel.cs.cst" MergeProperties="False" ExcludeProperties="" %> - +<%@ Register Name="GridViewSearchPanelState" Template="../WebLibrary/UI/GridViewSearchPanelState.cs.cst" MergeProperties="False" ExcludeProperties="" %> + <%@ Register Name="TableRepeater" Template="../WebLibrary/UI/TableRepeater.cst" MergeProperties="False" ExcludeProperties="" %> <%@ Register Name="ViewRepeater" Template="../WebLibrary/UI/ViewRepeater.cst" MergeProperties="False" ExcludeProperties="" %> Index: VisualStudio/vsnet2005.project.cst =================================================================== --- VisualStudio/vsnet2005.project.cst (revision 505) +++ VisualStudio/vsnet2005.project.cst (working copy) @@ -1046,7 +1046,11 @@ Code - + + + Code + + <% } %> <% if (IncludeWinLibrary) { %> Index: WebLibrary/UI/FormUtilBase.cst =================================================================== --- WebLibrary/UI/FormUtilBase.cst (revision 505) +++ WebLibrary/UI/FormUtilBase.cst (working copy) @@ -25,6 +25,9 @@ using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; +using System.IO; +using System.Text; +using System.Xml.Serialization; using <%= BLLNameSpace %>; using <%= WebNameSpace %>.Data; #endregion @@ -38,7 +41,7 @@ public partial class FormUtilBase { private static readonly String ControlCacheKey = "ControlCache"; - + #region Request Methods #endregion @@ -1408,5 +1411,240 @@ } #endregion + + #region Handles the GridViewSearchPanel State + /// + /// Handles the state of the GridViewSearchPanel + /// + /// The search panel. + public static void HandleGridViewSearchPanelState( GridViewSearchPanel searchPanel ) + { + HandleGridViewSearchPanelState( searchPanel, PersistenceMethod.Session ); + } + + /// + /// Handles the state of the GridViewSearchPanel + /// + /// The search panel. + /// The date and time the persistent cookie expires. + public static void HandleGridViewSearchPanelState( GridViewSearchPanel searchPanel, DateTime persistentCookieExpiryDateTime ) + { + HandleGridViewSearchPanelState( searchPanel, null, PersistenceMethod.PersistentCookie, persistentCookieExpiryDateTime ); + } + + /// + /// Handles the state of the GridViewSearchPanel + /// + /// The search panel. + /// The persistence method. + public static void HandleGridViewSearchPanelState( GridViewSearchPanel searchPanel, PersistenceMethod persistenceMethod ) + { + HandleGridViewSearchPanelState( searchPanel, null, persistenceMethod, null ); + } + + /// + /// Handles the state of the GridViewSearchPanel + /// + /// The search panel. + /// The grid view. + /// The persistence method + /// The expiry datetime of a persistent cookie + public static void HandleGridViewSearchPanelState( GridViewSearchPanel searchPanel, GridView gridView, + PersistenceMethod persistenceMethod, DateTime? persistentCookieExpiryDateTime ) + { + if ( gridView == null ) + { + // try and find the GridView control if it hasn't been explicitly supplied + gridView = FindControl( searchPanel.NamingContainer, searchPanel.GridViewControlID ) as GridView; + } + + if ( gridView != null ) + { + // restore any previously saved state + gridView.Page.Load += new EventHandler( + delegate( object sender, EventArgs e ) + { + if ( !gridView.Page.IsPostBack ) + { + GridViewSearchPanelState controlState = GetGridViewSearchPanelState( GetUniqueGridViewName( gridView ), persistenceMethod ); + if ( controlState != null ) + { + controlState.RestoreState( ref gridView, ref searchPanel ); + } + } + } + ); + + // save state when page index changes + gridView.PageIndexChanged += new EventHandler( + delegate( object sender, EventArgs e ) + { + GridViewSearchPanelState controlState = new GridViewSearchPanelState( gridView, searchPanel ); + SaveGridViewSearchPanelState( controlState, GetUniqueGridViewName( gridView ), + persistenceMethod, persistentCookieExpiryDateTime ); + } + ); + + // save state when grid is sorted + gridView.Sorted += new EventHandler( + delegate( object sender, EventArgs e ) + { + GridViewSearchPanelState controlState = new GridViewSearchPanelState( gridView, searchPanel ); + SaveGridViewSearchPanelState( controlState, GetUniqueGridViewName( gridView ), + persistenceMethod, persistentCookieExpiryDateTime ); + } + ); + + // save state when search id done + searchPanel.SearchButtonClicked += new EventHandler( + delegate( object sender, EventArgs e ) + { + GridViewSearchPanelState controlState = new GridViewSearchPanelState( gridView, searchPanel ); + SaveGridViewSearchPanelState( controlState, GetUniqueGridViewName( gridView ), + persistenceMethod, persistentCookieExpiryDateTime ); + } + ); + + // save state when reset is done + searchPanel.ResetButtonClicked += new EventHandler( + delegate( object sender, EventArgs e ) + { + GridViewSearchPanelState controlState = new GridViewSearchPanelState( gridView, searchPanel ); + SaveGridViewSearchPanelState( controlState, GetUniqueGridViewName( gridView ), + persistenceMethod, persistentCookieExpiryDateTime ); + } + ); + } + } + + /// + /// Gets the unique name of the grid view. + /// + /// The grid view. + /// + private static string GetUniqueGridViewName( GridView gridView ) + { + return gridView.Page.Request.Url.AbsoluteUri + gridView.UniqueID; + } + + /// + /// Saves the GridViewSearchPanel State. + /// + /// State of the control. + /// Name of the control state. + public static void SaveGridViewSearchPanelState( GridViewSearchPanelState controlState, string controlStateName, + PersistenceMethod persistenceMethod, DateTime? persistentCookieExpiryDateTime ) + { + switch ( persistenceMethod ) + { + case PersistenceMethod.Session : + #region Uses Session state + HttpContext.Current.Session[ controlStateName ] = controlState; + #endregion + break; + case PersistenceMethod.Cookie : + case PersistenceMethod.PersistentCookie : + #region Uses a client cookie + string serializedString = SerializeGridViewSearchPanelState( controlState ); + HttpCookie cookie = new HttpCookie( controlStateName, HttpContext.Current.Server.UrlEncode( serializedString ) ); + // Determine if this should be persisted longer than just the current session + if ( persistentCookieExpiryDateTime != null ) + { + cookie.Expires = persistentCookieExpiryDateTime.Value; + } + HttpContext.Current.Response.Cookies.Add( cookie ); + + #endregion + break; + } + } + + /// + /// Gets the GridViewSearchPanel State from the cookie + /// + /// Name of the control state. + /// + public static GridViewSearchPanelState GetGridViewSearchPanelState( string controlStateName, PersistenceMethod persistenceMethod ) + { + GridViewSearchPanelState controlState = null; + + switch ( persistenceMethod ) + { + case PersistenceMethod.Session : + #region Uses Session state + if ( HttpContext.Current.Session[ controlStateName ] != null ) + { + controlState = HttpContext.Current.Session[ controlStateName ] as GridViewSearchPanelState; + } + #endregion + break; + + case PersistenceMethod.Cookie : + case PersistenceMethod.PersistentCookie : + #region Uses a client session cookie + HttpCookie cookie = HttpContext.Current.Request.Cookies[ controlStateName ]; + + if ( cookie != null ) + { + controlState = DeserializeGridViewSearchPanelState( HttpContext.Current.Server.UrlDecode( cookie.Value ) ); + } + #endregion + + break; + } + + return controlState; + } + + /// + /// Serializes the grid view search panel state. + /// + /// The control state. + /// + private static string SerializeGridViewSearchPanelState( GridViewSearchPanelState controlState) + { + string serializedString = string.Empty; + + using ( StringWriter stringWriter = new StringWriter() ) + { + XmlSerializer serializer = new XmlSerializer( typeof( GridViewSearchPanelState ) ); + serializer.Serialize( stringWriter, controlState ); + serializedString = stringWriter.ToString(); + } + + return serializedString; + } + + /// + /// Deserializes the grid view search panel state. + /// + /// The serialized string. + /// + private static GridViewSearchPanelState DeserializeGridViewSearchPanelState( string serializedString ) + { + GridViewSearchPanelState controlState = null; + XmlSerializer serializer = new XmlSerializer( typeof( GridViewSearchPanelState ) ); + controlState = (GridViewSearchPanelState)serializer.Deserialize( new StringReader( serializedString ) ); + + return controlState; + } + + #endregion + } + + #region Enums + /// + /// used to determine the persistence method + /// + public enum PersistenceMethod + { + /// session state will be used + Session = 0, + /// client cookie will be used + Cookie = 1, + /// a persistent client cookie will be used + PersistentCookie = 2, + } + #endregion } Index: WebLibrary/UI/GridViewSearchPanel.cs.cst =================================================================== --- WebLibrary/UI/GridViewSearchPanel.cs.cst (revision 505) +++ WebLibrary/UI/GridViewSearchPanel.cs.cst (working copy) @@ -11,6 +11,7 @@ using System.Web.UI; using System.IO; using System.Web.UI.WebControls; +using System.Reflection; using <%=RootNameSpace%>; using <%=RootNameSpace%>.Web.Data; using <%=RootNameSpace%>.<%=BusinessLogicLayerNameSpace%>; @@ -30,11 +31,17 @@ ] public class GridViewSearchPanel : CompositeControl { + #region Fields private string _gridViewControlID = string.Empty; private string _businessEntityType = string.Empty; private GridView GridView1; private DataSourceControl TypedDataSource; + private DropDownList cboFieldName; + private DropDownList cboOperator; + private TextBox txtKeyword; + #endregion + /// /// SearchButtonClicked event raised whenever the Search Button Clicked /// @@ -121,9 +128,110 @@ ViewState["_filter"] = value; } } + + /// + /// Gets or sets the name of the search field name. + /// + /// The name of the search field name. + [ + Browsable( true ), + Description( "Set / Gets the Search Field Name" ), + Category( "Misc" ), + DefaultValue( "" ), + ] + public string SearchFieldName + { + get + { + EnsureChildControls(); + return cboFieldName.SelectedValue; + } + set + { + EnsureChildControls(); + ListItem fieldItem = cboFieldName.Items.FindByValue( value ); + if ( fieldItem != null ) + { + cboFieldName.SelectedItem.Selected = false; // deselect any currently selected item + fieldItem.Selected = true; + } + } + } + + /// + /// Gets or sets the search operator. + /// + /// The search operator. + [ + Browsable( true ), + Description( "Set / Gets the Search Operator" ), + Category( "Misc" ), + DefaultValue( "Contains" ), + ] + public SearchOperator SearchOperator + { + get + { + EnsureChildControls(); + return (SearchOperator)Convert.ToInt32( cboOperator.SelectedValue ); + } + set + { + EnsureChildControls(); + ListItem opItem = cboOperator.Items.FindByValue( ( (int)value ).ToString() ); + if ( opItem != null ) + { + cboOperator.SelectedItem.Selected = false; // deselect any currently selected item + opItem.Selected = true; + } + } + } + + /// + /// Gets or sets the search keyword. + /// + /// The search keyword. + [ + Browsable( true ), + Description( "Set / Gets the Search keyword" ), + Category( "Misc" ), + DefaultValue( "" ), + ] + public string SearchKeyword + { + get + { + EnsureChildControls(); + return txtKeyword.Text; + } + set + { + EnsureChildControls(); + txtKeyword.Text = value; + } + } #endregion /// + /// Raises the event. + /// + /// The object that contains the event data. + protected override void OnLoad( EventArgs e ) + { + base.OnLoad( e ); + base.EnsureChildControls(); + if ( !Page.IsPostBack ) + { + // if we have a search value then build the search + if ( !string.IsNullOrEmpty( txtKeyword.Text ) && + !string.IsNullOrEmpty( cboFieldName.SelectedValue ) ) + { + BuildSearch(); + } + } + } + + /// /// Make sure that CreateChildControls has been called /// before the control is rendered /// @@ -144,7 +252,7 @@ // Start with a clean form base.Controls.Clear(); - DropDownList cboFieldName = new DropDownList(); + cboFieldName = new DropDownList(); cboFieldName.ID = "cboFieldName"; cboFieldName.SkinID = "cboFieldName"; @@ -158,26 +266,50 @@ Type[] typeArguments = TypedDataSource.GetType().BaseType.GetGenericArguments(); _businessEntityType = typeArguments[0].FullName; - Type t = EntityUtil.GetType(_businessEntityType); - System.Reflection.PropertyInfo[] pinfo = t.GetProperties(); - - foreach (System.Reflection.PropertyInfo p in pinfo) + #region Set up the fields drop down list using the list of table columns + Type enumType = EntityUtil.GetType( _businessEntityType + "Column" ); + string[] columnNames = Enum.GetNames( enumType ); + Array c = Enum.GetValues( enumType ); + for ( int i = 0; i < c.Length; i++ ) { - if (p.PropertyType.ToString() == "System.String") + ColumnEnumAttribute cea = EntityHelper.GetAttribute( (Enum)c.GetValue( i ) ); + // only show fields that we can realistically search against + switch ( cea.DbType ) { - for (int i = 0; i < GridView1.Columns.Count; i++) - { - // -- check if property is the same what specified in the sortexpression of the column - if (p.Name.ToLower() == GetCleanName(GridView1.Columns[i].SortExpression)) - { - ListItem li = new ListItem(); - li.Text = GridView1.Columns[i].HeaderText; - li.Value = GridView1.Columns[i].SortExpression; - cboFieldName.Items.Add(li); - } - } + case System.Data.DbType.AnsiString: + case System.Data.DbType.AnsiStringFixedLength: + case System.Data.DbType.Boolean: + case System.Data.DbType.Byte: + case System.Data.DbType.Currency: + case System.Data.DbType.Date: + case System.Data.DbType.DateTime: + case System.Data.DbType.Decimal: + case System.Data.DbType.Double: + case System.Data.DbType.Int16: + case System.Data.DbType.Int32: + case System.Data.DbType.Int64: + case System.Data.DbType.SByte: + case System.Data.DbType.Single: + case System.Data.DbType.String: + case System.Data.DbType.StringFixedLength: + case System.Data.DbType.Time: + case System.Data.DbType.UInt16: + case System.Data.DbType.UInt32: + case System.Data.DbType.UInt64: + case System.Data.DbType.VarNumeric: + case System.Data.DbType.Xml: + #region + ListItem li = new ListItem(); + li.Text = EntityHelper.GetPascalSpacedName(cea.Name); + li.Value = cea.Name; + cboFieldName.Items.Add( li ); + #endregion + break; + default: + break; } } + #endregion } else { @@ -185,14 +317,15 @@ } #region UI implementation - DropDownList cboOperator = new DropDownList(); + cboOperator = new DropDownList(); cboOperator.ID = "cboOperator"; cboOperator.SkinID = "cboOperator"; cboOperator.Items.Add(new ListItem("contains", "0")); cboOperator.Items.Add(new ListItem("starts with", "1")); cboOperator.Items.Add(new ListItem("equals", "2")); + cboOperator.Items.Add(new ListItem("ends with", "3")); - TextBox txtKeyword = new TextBox(); + txtKeyword = new TextBox(); txtKeyword.ID = "txtKeyword"; txtKeyword.SkinID = "txtKeyword"; @@ -266,10 +399,6 @@ /// void cmdReset_Click(object sender, EventArgs e) { - DropDownList cboFieldName = (DropDownList)this.FindControl("cboFieldName"); - DropDownList cboOperator = (DropDownList)this.FindControl("cboOperator"); - TextBox txtKeyword = (TextBox)this.FindControl("txtKeyword"); - cboFieldName.SelectedIndex = 0; cboOperator.SelectedIndex = 0; txtKeyword.Text = string.Empty; @@ -288,13 +417,21 @@ /// void cmdSearch_Click(object sender, EventArgs e) { - DropDownList cboFieldName = (DropDownList)this.FindControl("cboFieldName"); - DropDownList cboOperator = (DropDownList)this.FindControl("cboOperator"); - TextBox txtKeyword = (TextBox)this.FindControl("txtKeyword"); + BuildSearch(); + GridView1.PageIndex = 0; // default to first page + GridView1.DataBind(); - switch (cboOperator.SelectedValue) + if (SearchButtonClicked != null) SearchButtonClicked(sender, e); + } + + /// + /// Builds the search. + /// + private void BuildSearch() + { + switch ( cboOperator.SelectedValue ) { - case "0": + case "0": whereClause = string.Format("[{0}] LIKE '%{1}%'", cboFieldName.SelectedValue, txtKeyword.Text); break; @@ -305,12 +442,13 @@ case "2": whereClause = string.Format("[{0}] = '{1}'", cboFieldName.SelectedValue, txtKeyword.Text); break; + + case "3": + whereClause = string.Format( "[{0}] LIKE '%{1}'", cboFieldName.SelectedValue, txtKeyword.Text ); + break; } - SetWhereClause(whereClause); - GridView1.DataBind(); - - if (SearchButtonClicked != null) SearchButtonClicked(sender, e); + SetWhereClause( whereClause ); } #endregion @@ -379,6 +517,21 @@ } #endregion } + + /// + /// Enum for the search panel search operator + /// + public enum SearchOperator + { + /// does a contains search - '%{0}%' + Contains = 0, + /// does a starts with search - '{0}%' + StartsWith = 1, + /// does a equals search - '{0}' + Equals = 2, + /// does an ends with search - '%{0}' + EndsWith = 3 + } }