Welcome to Tech-Review.Org Sign in | Join | Help

.net_2.0

My coding blog entries. Typically will either be more complex coding examples or overcoming product issues / troubleshooting resolutions.
Gridviews and adding empty rows for display purposes only.

On my Sites-Easy project, all of the Administrative features use Ajax, Gridviews, and ModalPopups to present a UI that is consistent.  This consistency is obtained by using abstract classes and delegates so that creating new Administrative Modules is almost as simple as dragging a control into the Designer View of Visual Studio.  However, since the number of records that the Gridview may display will vary - having a listing of only two records versus showing a result that pulls back whatever the page limit size is - makes the UI look incomplete.  Instead, I wanted to have the Gridview maintain the same size regardless of number of records - and if number of records to display is less than page size then insert dummy rows that just fill UI space.

 

How to do it however? Most of all the blog entries and forum posts address this for when returning a null set of data (which causes the header and footer to dissapear) - none addressed my particular issue. 

 

Here is my solution:

 

In this example the Gridview will be bound to a DataSet and I will assume you already know how to bind Gridviews to various data sources.

 

//BindGridView() event 

//ds = some dataset

//Compare the number of rows to configured PageSize if less than then stuff new rows in 

if (ds.Tables[0].Rows.Count < PageSize)
                {
                    //Set the number of inserts to do

                    int itemCount = (PageSize - ds.Tables[0].Rows.Count);

                   //Loop


                    for (int itemIndex = 0; itemIndex < itemCount; itemIndex++)
                    {

                       //Add empty row


                        ds.Tables[0].Rows.Add();
                       
                    }

                   // commit the changes to the Dataset


                    ds.AcceptChanges();
                   
                }

//Now bind to the Gridview 

grdData.DataSource = ds;
grdData.DataBind();

 

Now that we have Gridview populated now comes the real fun.  In this example I illustrate how to also implement security checks for your Gridview buttons. 

 

protected virtual void GridView_RowDataBound(Object s, GridViewRowEventArgs e)
        {
           
            if (e.Row.RowType == DataControlRowType.DataRow )
            {

//Set a Boolean to determine if our ID is not a integer.

                bool isValidRow = true;

//Find our buttons / checkboxes / etc that display something other than a text field.

                ImageButton btnDelete = (ImageButton)e.Row.FindControl("btnDelete");
                ImageButton btnEdit = (ImageButton)e.Row.FindControl("btnEdit");
                ImageButton btnClone = (ImageButton)e.Row.FindControl("btnClone");
                ImageButton btnView = (ImageButton)e.Row.FindControl("btnView");
                CheckBox chkSelect = (CheckBox)e.Row.FindControl("chkSelect");

               

 //Since the "id" is a integer we must first cast it to a string and compare to see if it is not a empty string. If actual string then we

//know we have real "id" and avoid specific casting. If string.empty then there was no "id" and row is null set isValid to false.

              if (DataBinder.Eval(e.Row.DataItem, "id").ToString() == string.Empty)
                {
                    isValidRow = false;
                }

               

//Process the id and set up desired behavior of buttons , etc...This code also checks for roles to disable any

//buttons that invoke a command argument if user does not match the roles.  The role handler here is custom. 

                if (isValidRow)
                {
                    int editID = (int)DataBinder.Eval(e.Row.DataItem, "id");

 


                    if (btnDelete != null)
                    {
                        btnDelete.ImageUrl = ResolveUrl("~/Communities/" + objSectionInfo.Skin + "/Images/Admin/delete.gif");
                        if (objUserInfo.MayDelete || Array.IndexOf(objSectionInfo.DeleteRoles, "Community-Authenticated") != -1)
                        {
                            btnDelete.CommandArgument = editID.ToString();
                        }
                        else
                        { btnDelete.Enabled = false; }
                    }

                    if (btnEdit != null)
                    {
                        btnEdit.ImageUrl = ResolveUrl("~/Communities/" + objSectionInfo.Skin + "/Images/Admin/edit.gif");
                        if (objUserInfo.MayEdit || Array.IndexOf(objSectionInfo.EditRoles, "Community-Authenticated") != -1)
                        {
                            btnEdit.CommandArgument = editID.ToString();
                        }
                        else
                        { btnEdit.Enabled = false; }
                    }

                    if (btnClone != null)
                    {
                        btnClone.ImageUrl = ResolveUrl("~/Communities/" + objSectionInfo.Skin + "/Images/Admin/clone.png");
                        if (objUserInfo.MayAdd|| Array.IndexOf(objSectionInfo.AddRoles, "Community-Authenticated") != -1)
                        {
                            btnClone.CommandArgument = editID.ToString();
                        }
                        else
                        { btnClone.Enabled = false; }
                    }
                    if (btnView != null)
                    {
                        btnView.ImageUrl = ResolveUrl("~/Communities/" + objSectionInfo.Skin + "/Images/Admin/view.png");
                        if (objUserInfo.MayView || Array.IndexOf(objSectionInfo.ViewRoles, "Community-Authenticated") != -1)
                        {
                            btnView.CommandArgument = editID.ToString();
                        }
                        else
                        { btnView.Enabled = false; }
                    }

                }

// Here we HIDE any button controls because these are the empty filler / dummy rows.  If you have other gridview templated items that display images or buttons - then you will need to add them here as well.  If you have text just being displayed such as in your aspx or ascx as such:

//<asp:BoundField DataField="Message_Name" DataFormatString="{0:d}" HeaderText="Question" />
      

//NO need to handle them as they accept null values.  The only exception may be a date field but not positive.

// Why not use the e.Row.Controls.Clear?

//If you do the Clear the row will be considered null and will not be displayed.               

   else
                {
                   
                    if (btnDelete != null)
                    { btnDelete.Visible = false; }
                   
                    if (btnEdit != null)
                    { btnEdit.Visible = false; }
                   
                    if (btnClone != null)
                    { btnClone.Visible = false; }

                    if (chkSelect != null)
                    { chkSelect.Visible = false; }

                    if (btnView != null)
                    { btnView.Visible = false; }

                }

            }

        }

 

This is an example screenshot of end result:

Before:

Before Example

After And End Result:

After SnapShot - Note Filler Rows

Hopefully, this is a concrete example on how to insert dummy rows and additionally - using the control.Enable along with checking for user roles for activities presented.

Posted: Sunday, February 04, 2007 5:51 AM by Jody
Filed under: ,

Comments

John Morris said:

The first code you have (....if (ds.Tables[0].Rows.Count < PageSize)....) what part of the code/when do you use this? You didn't mention where this code is used... and I would love to try it out in my code (and not just add to the end, but even add in the middle of the page.

Any comments would be greatly appreciated.

# March 1, 2007 5:04 PM

Jody said:

John,

Every dataset actually consists of a Table(s).  

ds represents the dataset returned from some method in my DAL.  

the ds.Tables[0] ...  is required to determine the count from the default Table that is created when a dataset is populated.  In other words by default a dataset will always have a Table with a index of 0 which is what the ds.Tables[0] references to.  

So, I call that right after I fill a dataset with some data...but before I databind() it.  If you databind before then it makes it a much more complex project to add subsequent rows...

Hope that explains...

# March 1, 2007 6:04 PM

Srini said:

Jody ,

Your first if code "if (ds.Tables[0].Rows.Count < PageSize" is incomplete I think.

What if you have Rows.Count more than a page size but does not fill second page fully?

For ex: If your page size is 10 and number of rows in dataset is 15. First page is full, no doubt, but second page is going to collapse to only 5 lines.

I feel, the check for row count of ds should be consider this scenario.

# March 30, 2007 9:17 AM

Jody said:

Srini...

Well, in the example - because of the fact I am doing explicit paging when calling a SQL stored procedure, I am always assured that the number of entries is within the page size.  The article assumes that you have some kind of paging mechanism already in place and that whatever page is called the number of records will be less than the page size for it to add the additional blank rows.  

So, if paging is properly constructed there should be no such scenario - after all, how could you have a page greater than the allowed page - and even if that was the case - no additional rows would be created because the number of rows in the associated dataset would be grater than...

# April 2, 2007 7:43 PM

HalfHuman said:

actually you could use a grid view with "empty data" template completed and also have a details view in "edit mode" by default.

# March 3, 2008 10:44 AM
New Comments to this post are disabled