Friday, July 24, 2009

C# DataGrid custom paging

In .NET 1.1 (I don't know the later version at this time), datagrid paging navigation is troublesome since it does not include link to the first and last page, and does not show the total number of pages. The pager row can contain no other information, which is also inconvenient when you want to put something there, e.g., a checkbox says "select all" for all checkboxes on the rows in the datagrid.

This is a way of imitating the paging manually, and allows the freedom of specifying "First, Prev, Next, Last" links, as well as total pages and other information on the pager row.

The "Prev, ..., 11, 12, ..., Next" part can be done with the following function. Then you can add "First" and "Last" as link buttons. You can then provide the page count as a Label. Alternatively, the following example also adds the page count as a simulation of the link button "Last".

In .aspx.cs page put:

/// <summary>
/// This function writes a customized navigation bar for datagrid.
///
/// Note that lblNext and lblPrev can be replaced with image icons.
///
/// Example of Calling this function:
/// writeDataGridNavBar(
/// this.DataGrid1.PageCount,
/// this.DataGrid1.CurrentPageIndex,
/// this.DataGrid1.PagerStyle.PageButtonCount,
/// 1
/// );
///
/// The last parameter "1" here is obtained this way:
/// Check the aspx page with default paging, look at the links to "1, 2, ...",
/// javascript:__doPostBack('DataGrid1$_ctl1$_ctl4','')
/// ^
/// Pass this number as the last parameter.
///
/// The optional ctrl_LastPage in the code below is similarly obtained from the
/// "Last" link button.
///
/// </summary>
/// <param name="totalPage">DataGrid.PageCount</param>
/// <param name="currentPage">DataGrid.CurrentPageIndex</param>
/// <param name="pageButtonCount">DataGrid.PagerStyle.PageButtonCount</param>
/// <param name="ctl_val"></param>
/// <returns></returns>
///
/// @Author: HomeTom
/// @Date: 7/24/2009
///
public string writeDataGridNavBar(
int PageCount, int CurrentPageIndex, int PageButtonCount, int ctl_val)
{
string lblNext = "Next";
string lblPrev = "Prev";
string ctrl = "javascript:__doPostBack('DataGrid1$_ctl" + ctl_val + "$_ctl";
// Optional. Use this only when use the "Last" link button.
string ctrl_LastPage = "javascript:__doPostBack('btnLastPage','')";
string s = "";
int i, j, tmp;

int startPage =
((int) (Math.Floor((CurrentPageIndex * 1.0)/PageButtonCount)) * PageButtonCount);

tmp = PageCount - PageButtonCount;
if (tmp > 0 && tmp < startPage) { startPage = tmp; }

if (CurrentPageIndex == 0) { s += lblPrev + " "; }
else
{
j = CurrentPageIndex - startPage;
if (startPage == 0) j -= 1;
s += "<a href=\"" + ctrl + j + "', '')\">" + lblPrev + "</a> ";
}

if (startPage > 0) { s += "<a href=\"" + ctrl + "0','')\">...</a> "; }

for (i = 0; i < PageButtonCount && (i + startPage) < PageCount; i ++)
{
tmp = startPage + i + 1;
j = (startPage == 0) ? i : (i + 1);
if (tmp == CurrentPageIndex + 1) { s += tmp + " "; }
else { s += "<a href=\"" + ctrl + j + "','')\">" + tmp + "</a> "; }
}
if (startPage + PageButtonCount < PageCount - 1) {
j = (startPage == 0) ? PageButtonCount : (PageButtonCount + 1);
s += "<a href=\"" + ctrl + j + "','')\">...</a> ";
}
if (startPage + PageButtonCount < PageCount)
{
s += "<a href=\"" + ctrl_LastPage + "\">" + PageCount + "</a> ";
}

if (CurrentPageIndex >= PageCount - 1) { s += lblNext; }
else
{
j = CurrentPageIndex - startPage + 1;
if (startPage > 0) j += 1;
s += "<a href=\"" + ctrl + j + "','')\">" + lblNext + "</a>";
}

return s;
}

Note that if don't want to use the page count link at the end then replace the red region with the following code:

if (startPage + PageButtonCount < PageCount) {
j = (startPage == 0) ? PageButtonCount : (PageButtonCount + 1);
s += "<a href=\"" + ctrl + j + "','')\">...</a> ";
}

In .aspx page put:

<asp:linkbutton id="btnFirstPage" onclick="DataGrid1_CustomPaging_First" Runat="server">First</asp:linkbutton>
<asp:label id="lblPageNavBar" Runat="server"></asp:label>
<asp:linkbutton id="btnLastPage" onclick="DataGrid1_CustomPaging_Last" Runat="server">Last</asp:linkbutton>


Now set DataGrid1.PagerStyle.visible to False.
Leave DataGrid1.AllowPaging as True, and DataGrid1.AllowCustomPaging as False.

That's it! You are simulating datagrid's default paging with the freedom of customizing the style!

--Appendix on 8/20/2009

Now it's clear that this does not work in later versions of .NET. First the links' format is not DataGrid1$_ctl1$_ctl4, but like DataGrid1$ctl01$ctl04. More importantly, if set the visible property of the link buttons and datagrid pager to false, then __doPostBack won't work for these controls, as they are cleaned from the output. Therefore the above scheme works only for .NET 1.1 :(

In later versions of .NET there is a pager template that can be used to format paging. Hope that's flexible enough.

Another thought is that, the use of datagrid and dataview in later versions of .NET, are mostly for the ease of paging and sorting. Think carefully, I don't see anything else that datagrid and dataview can do special. If these can be handled from scratch, then there is no need to use these cumbersome controls. Actually I would prefer such a build-from-scratch approach, it avoids the burden of version incompatibility and allows the largest flexibility. Once the template is done, it can be used all the time without any more learning curve.

Types of parameters in C#

There are 4 types of parameter passing in C#:
1) Value: pass by value.
2) Out: like pointer in C/C++, allow return value. Don't have to be initialized first.
3) Ref: like reference in C++, allow return value. Must be initialized first.
4) Params: for variable length parameter list.

More detailed explanation and examples:
http://www.csharphelp.com/archives/archive225.html

Friday, July 3, 2009

Statistics and Analysis of IT technique usage in different area

Statistics and Analysis of IT technique usage in different area (in Chinese)

Summary:
C/C++ is strong in system level software.
.NET is strong in enterprise applications.
Java is strong on web server side. Php is good too.
Ajax/JavaScript is strong for RIA (Rich Interface Application). Flex is 1/10, and Silverlight is 1/100.

Wednesday, July 1, 2009

Use ADODB.RecordSet in C#

Usually one can use System.Data.SqlClient to deal with operations on MSSQL server. The corresponding objects are SqlConnection, SqlCommand, SqlDataReader etc.

There is one scenario like this: the user needs to read something from each row in a table, and use the obtained information to update that row. One needs to cycle through all the records, and then use "UPDATE" query for the purpose. If SqlDataReader is used, the efficiency will be slow. SqlDataReader is read only, and uses the current connection exclusively as well. The user needs to open a second connection, and use the second connection to do the update based on a key.

In ADODB.RecordSet, one can use RecordSet.Update() function to directly update the current row and write back to database. No second connection is needed, and no key-based query is needed. This is much more efficient. A similar mechanism in SqlClient may exist, but I don't know yet at this time.

The following is an example using ADODB.RecordSet in C#. Note one needs to add ADODB to the references list of the current C# project first.

Parameters used by RecordSet can be found at http://www.w3schools.com/ADO/met_rs_open.asp.
private void updateTbl_ADODB() {
    ADODB.Connection conn = new ADODB.ConnectionClass();
    ADODB.Recordset rs = new ADODB.RecordsetClass();

    try {
        string strConn = 
            "Provider=SQLOLEDB;Initial Catalog=[database];Data Source=[server];";
        conn.Open(strConn, [user], [pwd], 0);

        string sql = "SELECT * FROM tbl";
        rs.Open(sql, conn, ADODB.CursorTypeEnum.adOpenForwardOnly, 
                ADODB.LockTypeEnum.adLockOptimistic, -1);

        while (rs.EOF == false)  {
            rs.Update("field_name", [new_value]);
            rs.MoveNext();
        }

    } catch (Exception e) {
        MessageBox.Show(this, "Error" + e.Message);
    } finally {
        conn.Close();
    }
}

Blog Archive

Followers