CSTrüter HomeArticlesDownloadsAbout meContact me
a quick look at how to create a windows service using C# 2010-02-28 21:48:06
How to call server-side code from client-side code, using PageMethods in ASP.net 2010-02-21 12:31:27
How to pass a set of data to an xml type in SQL 2005/8 2010-02-12 19:04:23
Some funky behaviour regarding overload Resolution of dynamic/object types 2010-02-09 17:16:52
Object orientated programming within JavaScript 2010-01-28 07:25:45
How to sort data using ASP.net (C#) and SQL 2005/8 2010-01-18 15:23:14
Quick look at some of the new features added to C# 4.0 2010-01-12 21:52:13
SQL 2008 introduced a nifty feature called Table-Valued Parameters (TVP) into its codebase 2010-01-06 22:58:25
How to page data using ASP.net (C#) and SQL 2005/8 2009-10-19 15:01:45
a post about sql joins 2009-09-20 15:50:57
Creating a WYSIWYG textbox for your website is actually quite simple. 2007-02-01 12:00:00
Move items between two listboxes in ASP.net(C#, VB.NET) and PHP 2008-06-12 17:07:43
Firefox word wrapping issues 2008-06-09 09:51:21
2007-02-22 12:00:00
Blog about passing parameters by reference to functions using func_get_arg(s) 2008-07-27 12:38:24
Source code for the following post can be downloaded here. The following post is a bit of a follow up post on the post I did a while ago about paging. Equally to paging, sorting is also one of those common tasks when working with data. Similarly to the paging post we create a table, except we're adding a datetime field in this example, which tells us when an user was added to our "system". CREATE TABLE [dbo].[friends]( [id] [int] IDENTITY(1,1) NOT NULL, [firstname] [varchar](50) NOT NULL, [lastname] [varchar](50) NOT NULL, [created] [datetime] NOT NULL, CONSTRAINT [PK_friends] PRIMARY KEY CLUSTERED ( [id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] The default value for the create date: ALTER TABLE [dbo].[friends] ADD CONSTRAINT [DF_friends_created] DEFAULT (getdate()) FOR [created] You'll also need to create some indexes for the fields you're planning to do sorting on, to avoid table scans: CREATE NONCLUSTERED INDEX [ix_friends] ON [dbo].[friends] ( [firstname] ASC, [lastname] ASC, [created] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] Add some data: INSERT INTO friends(firstname, lastname, created) VALUES ('Julie', 'Truter', getdate() - 10) INSERT INTO friends(firstname, lastname, created) VALUES ('Eugene', 'Stander', getdate() - 50) INSERT INTO friends(firstname, lastname, created) VALUES ('Pam', 'Nizar', getdate() - 120) INSERT INTO friends(firstname, lastname, created) VALUES ('Alexander', 'Mehlhorn', getdate() - 4) INSERT INTO friends(firstname, lastname, created) VALUES ('Roland', 'Cooper', getdate() - 10) INSERT INTO friends(firstname, lastname, created) VALUES ('Loren', 'Stevens', getdate() -2) INSERT INTO friends(firstname, lastname, created) VALUES ('Edward', 'Anderson', getdate() - 5) INSERT INTO friends(firstname, lastname, created) VALUES ('Wayne', 'Kleynhans', getdate() - 13) The stored procedure we're going to use to assist us in sorting, will look something like this: CREATE PROCEDURE [dbo].[sortFriends] @sort AS VARCHAR(20) AS BEGIN SELECT id, firstname, lastname, created FROM friends ORDER BY CASE @sort WHEN 'firstname' THEN firstname WHEN 'lastname' THEN lastname ELSE NULL END ASC, CASE @sort WHEN 'created' THEN created ELSE NULL END ASC, CASE @sort WHEN 'firstname DESC' THEN firstname WHEN 'lastname DESC' THEN lastname ELSE NULL END DESC, CASE @sort WHEN 'created DESC' THEN created ELSE NULL END DESC END Notice the case statements in the order by clause, I seperated the created field from the other (firstname, lastname) fields - if we process these fields in the same case statement, we'll need to convert the datetime field to a varchar - which I am avoiding for performance reasons. Also notice the "ELSE NULL", SQL will ignore these order conditions, if our case condition isn't met. Moving on to the ASP.net side of things.. In the following snippet we create a gridview control, notice the sortexpression attributes, those are the expressions we're going to send to our stored procedure. Note: the control will automatically concatenate our descending command if needed, eg firstname DESC. <asp:GridView ID="gvFriends" runat="server" DataSourceID="obsFriends" AllowSorting="true" AutoGenerateColumns="false" OnRowCreated="gvFriends_RowCreated"> <Columns> <asp:BoundField DataField="firstname" HeaderText="Firstname" SortExpression="firstname" /> <asp:BoundField DataField="lastname" HeaderText="Lastname" SortExpression="lastname" /> <asp:BoundField DataField="created" HeaderText="Created" SortExpression="created" DataFormatString="{0:d}" /> </Columns> </asp:GridView> <asp:ObjectDataSource ID="obsFriends" runat="server" SelectMethod="sortFriends" TypeName="friends" SortParameterName="sort"></asp:ObjectDataSource> This is what our select method is going to look like: [DataObject()] public class friends { [DataObjectMethod(DataObjectMethodType.Select)] public static DataTable sortFriends(String sort) { using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Default"].ConnectionString)) { using (SqlCommand command = new SqlCommand("sortFriends", connection)) { command.CommandType = CommandType.StoredProcedure; command.Parameters.AddWithValue("@sort", sort); using (SqlDataAdapter adapter = new SqlDataAdapter(command)) { DataTable dt = new DataTable(); adapter.Fill(dt); return dt; } } } } } When an user clicks on a field in the header of the gridview, it will send the appropriate command to the stored procedure and sort our results. Unfortunately M$ didn't provide functionality which displays which field and which direction (descending/ascending) are currently being sorted. Luckily this is functionality we can add ourselves, we attach the following code to the rowcreated event of the gridview. if (e.Row.RowType == DataControlRowType.Header) { List<LinkButton> linkButtons = (from headerCells in e.Row.Cells.OfType<DataControlFieldHeaderCell>() let linkButton = (headerCells.HasControls()) ? headerCells.Controls[0] as LinkButton : null where linkButton != null && ((GridView)sender).SortExpression == linkButton.CommandArgument select linkButton).ToList<LinkButton>(); foreach (LinkButton linkButton in linkButtons) { Image image = new Image(); image.ImageUrl = String.Concat("~/images/", (((GridView)sender).SortDirection == SortDirection.Ascending ? "asc" : "desc"), ".gif"); linkButton.Controls.Add(new LiteralControl(String.Concat(linkButton.Text, " "))); linkButton.Controls.Add(image); } } You will notice I wrote a LINQ query to retrieve the linkbutton(s) currently "responsible" for sorting - alternatively one can simply retrieve them using a foreach statement, but I felt lucky ;) Once we find them, we add the proper picture to these controls, which gives us a visible representation of which columns are currently being sorted.
CREATE TABLE [dbo].[friends]( [id] [int] IDENTITY(1,1) NOT NULL, [firstname] [varchar](50) NOT NULL, [lastname] [varchar](50) NOT NULL, [created] [datetime] NOT NULL, CONSTRAINT [PK_friends] PRIMARY KEY CLUSTERED ( [id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]
ALTER TABLE [dbo].[friends] ADD CONSTRAINT [DF_friends_created] DEFAULT (getdate()) FOR [created]
CREATE NONCLUSTERED INDEX [ix_friends] ON [dbo].[friends] ( [firstname] ASC, [lastname] ASC, [created] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
INSERT INTO friends(firstname, lastname, created) VALUES ('Julie', 'Truter', getdate() - 10) INSERT INTO friends(firstname, lastname, created) VALUES ('Eugene', 'Stander', getdate() - 50) INSERT INTO friends(firstname, lastname, created) VALUES ('Pam', 'Nizar', getdate() - 120) INSERT INTO friends(firstname, lastname, created) VALUES ('Alexander', 'Mehlhorn', getdate() - 4) INSERT INTO friends(firstname, lastname, created) VALUES ('Roland', 'Cooper', getdate() - 10) INSERT INTO friends(firstname, lastname, created) VALUES ('Loren', 'Stevens', getdate() -2) INSERT INTO friends(firstname, lastname, created) VALUES ('Edward', 'Anderson', getdate() - 5) INSERT INTO friends(firstname, lastname, created) VALUES ('Wayne', 'Kleynhans', getdate() - 13)
CREATE PROCEDURE [dbo].[sortFriends] @sort AS VARCHAR(20) AS BEGIN SELECT id, firstname, lastname, created FROM friends ORDER BY CASE @sort WHEN 'firstname' THEN firstname WHEN 'lastname' THEN lastname ELSE NULL END ASC, CASE @sort WHEN 'created' THEN created ELSE NULL END ASC, CASE @sort WHEN 'firstname DESC' THEN firstname WHEN 'lastname DESC' THEN lastname ELSE NULL END DESC, CASE @sort WHEN 'created DESC' THEN created ELSE NULL END DESC END
<asp:GridView ID="gvFriends" runat="server" DataSourceID="obsFriends" AllowSorting="true" AutoGenerateColumns="false" OnRowCreated="gvFriends_RowCreated"> <Columns> <asp:BoundField DataField="firstname" HeaderText="Firstname" SortExpression="firstname" /> <asp:BoundField DataField="lastname" HeaderText="Lastname" SortExpression="lastname" /> <asp:BoundField DataField="created" HeaderText="Created" SortExpression="created" DataFormatString="{0:d}" /> </Columns> </asp:GridView> <asp:ObjectDataSource ID="obsFriends" runat="server" SelectMethod="sortFriends" TypeName="friends" SortParameterName="sort"></asp:ObjectDataSource>
[DataObject()] public class friends { [DataObjectMethod(DataObjectMethodType.Select)] public static DataTable sortFriends(String sort) { using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["Default"].ConnectionString)) { using (SqlCommand command = new SqlCommand("sortFriends", connection)) { command.CommandType = CommandType.StoredProcedure; command.Parameters.AddWithValue("@sort", sort); using (SqlDataAdapter adapter = new SqlDataAdapter(command)) { DataTable dt = new DataTable(); adapter.Fill(dt); return dt; } } } } }
if (e.Row.RowType == DataControlRowType.Header) { List<LinkButton> linkButtons = (from headerCells in e.Row.Cells.OfType<DataControlFieldHeaderCell>() let linkButton = (headerCells.HasControls()) ? headerCells.Controls[0] as LinkButton : null where linkButton != null && ((GridView)sender).SortExpression == linkButton.CommandArgument select linkButton).ToList<LinkButton>(); foreach (LinkButton linkButton in linkButtons) { Image image = new Image(); image.ImageUrl = String.Concat("~/images/", (((GridView)sender).SortDirection == SortDirection.Ascending ? "asc" : "desc"), ".gif"); linkButton.Controls.Add(new LiteralControl(String.Concat(linkButton.Text, " "))); linkButton.Controls.Add(image); } }
Codebooth my semi-community site etc (work in progress)
The company I'am currently working for as software developer.
a Parallel reference of programming languages 2009-09-10 12:48:23
a tutorial explaining how to develop a simple login using PHP and MySQL 2009-09-05 18:26:47
An article looking at adding some kind of event driven model to PHP 5 2008-07-28 12:48:09
It is very simple creating your own rss reader, the following article looks at a few methods of doing this. 2008-06-23 13:18:25
A quick reference about working with dropdown boxes (select element) in javascript. 2007-02-17 16:36:41
Collection of funny programming articles 2006-10-08 14:23:43