467,879 Members | 1,349 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 467,879 developers. It's quick & easy.

C# windows: DataGridView sorting event troubles

Plater
Expert 4TB
I am having trouble determining when my DataGridView object is sorting (based on a column header click).

The idea is, in a large table, sorting the columns takes time, so I show a splash screen. When it is done sorting I want the splash screen dissapear.

What I had been doing was using the CellClick and Sorted events:
Expand|Select|Wrap|Line Numbers
  1. private void myDGV_CellClick(object sender, DataGridViewCellEventArgs e)
  2. {
  3.    if (e.RowIndex == -1)
  4.    {//sorting
  5.       ShowSplash2(myDGV, "Sorting...");
  6.    }
  7. }
  8.  
  9. private void myDGV_Sorted(object sender, EventArgs e)
  10. {
  11.    HideSplash2(myDGV);
  12. }
  13.  
This works really well, except for one problem. On checkbox columns that all have the same value (or possibly columns that are "unsortable"?) The CellClick event is triggered, but the Sorted event is not triggered. No sorting operation happens, so the event never triggers?

Does anyone know of a better way to determine if the gridview is starting to sort? I looked at the SortCompare event, but it never seemed to be fired at all. (I think it only gets fired when you call the .Sort() function)

Problem 2)
When you click the top of a column to sort the data, all the cellstyles disapear. anyone know how to keep the cellstyling the same between row sorting?
Edit: Using the CellFormatting event and state data kept inside a hidden row, i can keep changing the row style based on it.
Oct 8 '08 #1
  • viewed: 18815
Share:
7 Replies
Expert 100+
I've worked much with both sorting and the DataGridView, but that is a tricky question if you are not creating a subclassed DataGridView or BindingList, since most of the sorting related items are protected.
That said, let me throw out some ideas.

- First, easiest way to narrow down the cell-click problem would be to start the splash screen in the ColumnHeaderMouseClick event, since normal behavior is to only sort on ColumnHeader clicks.

- Second, is your DataSource a DataSet/DataTable or something else that implements IBindingList? If something else, is it your own extension of BindingList (most custom classes would need to extend BindingList in order to get sorting)? In which case, you could check for sorting from your BindingList/DataSource instead of the GridView...

- But assuming you are binding to a DataView (the underlying IBindingList of the DataSet) then what happens is on the left-click of the column header cell, if sorting is enabled, the Grid calls (IBindingList)DefaultView.ApplySort(PropertyDescri ptor[which is the column name], SortDirection [the sort glyph]);
Only once inside that method can you really be guaranteed the Grid is actually sorting. Unfortunately, as mentioned, it is a protected method, so you would have to have an entire BindingList implementation to get into that method and possibly raise a custom event or such.

I believe the SortCompare event is fired only when there is no underlying BindingList, and so the Grid literally compares each cell's text value, which would explain why it is not fired if you have any underlying binding source.

As far as the CellStyle changing goes...I find that odd. By default it should not change just because you have sorted. That said, there may be an obvious cause of it changing...but try to hunt down why...maybe even throw some debug lines into the CellStyleChanged event to see when and how. Although you found a workaround, at a high level it seems to me such a workaround should not be needed...unless you customized the CellFormatting event on the initial load, but somehow the same CellFormatting event is not getting called when you sort.

The CellFormatting event should really only be used as a last resort for customizations that cannot be cached in a DefaultCellStyle (and there are several...Grid, Row, Column, AlternatingRow) or its Format string.
Oct 10 '08 #2
Expert 100+
One more thought...the DataGridViewColumn has a SortMode property...which can be set to NotSortable for the columns such as all check boxes or whatnot...(assuming you truly do not want them sorted).

I guess the ColumnHeaderMouseClick would still be raised, but by setting that SortMode there would be no glyph there asking to be clicked.

Of course, this then begs the obvious and perhaps simplest solution...why not just check which column was clicked before firing off the splash screen...and not fire it for the columns which you have determined that ultimately do not fire a Grid.Sorted event...?
Oct 10 '08 #3
Plater
Expert 4TB
It was so much that I *didn't* want them sorted, as they just didn't sort. It doesn't matter to me if they do or do not, I jsut don't want them triggering the splash screen to come up, and then never having it go away. I just thought maybe I could watch the DataBindingComplete event, but that also is not fired for those columns.

Yes, I set the DataSource to a DataTable, you're saying there is something in there I can watch for the sorting?

I didn't use the ColumnHeaderMouseClick because the event appeared to fire AFTER the sorting was done, as opposed to the regular cellclick which appeared to happen before the sorting.

As for not picking specific columns, I may have to do that. I had hoped to keep this genereic and as free from preprocessing as possible
Oct 10 '08 #4
Expert 100+
I did not notice you were checking the RowIndex during the cell click, so you are already filtering on the ColumnHeader row, making my suggestion about ColumnHeaderMouseClick irrelevant...sorry.

I think you could do this with a minimum of 'extra' code. The suggestion of subclassing a BindingList would be way overkill if you want to keep it simple. [All I was suggesting about DataTable is that when it sorts, the Grid casts the DataSet to IBindingList and calls ApplySort on it...so IF you could override that method, you would be guaranteed to know sorting was happening...but you would have to implement your own BindingList to do so...]

You are already checking the row, so why not check the column on the CellClick event as well. I could see two possibilites:

1. Assume you only want TextBoxCell columns sorted (not Button, CheckBox, Image or Link). You could simple check the CellType or CellTemplate property of the column before firing the splash screen.

2. Set the SortMode of each column (it's a public property, so I would consider that minimal code interference) at initialization, and then at CellClick get the column and only fire the splash screen for columns that are not NotSortable.
Oct 10 '08 #5
Plater
Expert 4TB
Well after your recent suggestions I think I have a good enough solutions for it:
Expand|Select|Wrap|Line Numbers
  1. private void dgvResults_CellClick(object sender, DataGridViewCellEventArgs e)
  2. {
  3.    if ((e.RowIndex == -1)&&(e.ColumnIndex!=-1))//if both -1, it is the "select all" corner
  4.    {
  5.       if (dgvResults.Columns[e.ColumnIndex].CellType == typeof(DataGridViewTextBoxCell))
  6.       {//sorting
  7.          ShowSplash2(dgvResults, "Sorting...");
  8.       }
  9.    }
  10. }
  11.  
Thanks for the help on that.


As for the cellformating, I stopped looking into it when I found the cellformating event, lets me supply dynamic cell formating based on cell contents.

As a side note, it was the DefaultCellStyle proeprty of the row that I was setting, that was getting reset durring a column sort
Oct 10 '08 #6
Sample code :
Expand|Select|Wrap|Line Numbers
  1. string Connstring = @"Server=IN44109369\SQLExpress; Database=MATool;Trusted_Connection=Yes";
  2.         conn = new SqlConnection(Connstring);
  3.         string SQLcnn = "SELECT Id,Analyst,VendorType,Site,Legal,QAD_Code,Phase_II_Audit,QAD_Status,Code_Status,Pop_Form_TAT,Rec_Form_TAT,TAT_AP,EDI_TAT,VMTAT,Audited_By,VM_FTT,TOE,VM_Error_Desc,Category,Fatal,Non_Fatal,PhaseII_AuditStatus,Audit_Status,Audit_Compl_Date,Audit_Compl_Time,Audit_TAT FROM [dbo].[tblQAD] where [Audited_By]= @PAnalyst and [PhaseII_AuditStatus] = @PStatus";
  4.         cmd = new SqlCommand(SQLcnn, conn);
  5.         cmd.Parameters.Add(new SqlParameter("@PAnalyst", System.Data.SqlDbType.NChar, 10, "Audited_By"));
  6.         cmd.Parameters.Add(new SqlParameter("@PStatus", System.Data.SqlDbType.NChar, 10, "PhaseII_AuditStatus"));
  7.         cmd.Parameters["@PAnalyst"].Value = lblUser.Text;
  8.         cmd.Parameters["@PStatus"].Value = lblPendingStatus.Text;
  9.         SqlDataAdapter sdr = new SqlDataAdapter(cmd);
  10.         DataTable dt = new DataTable("tblQAD");
  11.         sdr.Fill(dt);
  12.         int dataTableRowCount = dt.Rows.Count;
  13.         if (dataTableRowCount > 0)
  14.         {
  15.             GridView1.Visible = true;
  16.             GridView1.DataSource = dt;
  17.             GridView1.DataBind();
  18.         }
  19.         else
  20.         {
  21.             GridView1.Visible = false;
  22.         }
  23.  
  24. private string GetSortDirection()
  25.     {
  26.         switch (GridViewSortDirection)
  27.         {
  28.             case "ASC":
  29.                 GridViewSortDirection = "DESC";
  30.                 break;
  31.  
  32.             case "DESC":
  33.                 GridViewSortDirection = "ASC";
  34.                 break;
  35.         }
  36.  
  37.         return GridViewSortDirection;
  38.     }
  39.     private string GridViewSortDirection
  40.     {
  41.         get { return ViewState["SortDirection"] as string ?? "ASC"; }
  42.         set { ViewState["SortDirection"] = value; }
  43.     }
  44.     private string GridViewSortExpression
  45.     {
  46.         get { return ViewState["SortExpression"] as string ?? string.Empty; }
  47.         set { ViewState["SortExpression"] = value; }
  48.     }
  49.  
  50.     private string ConvertSortDirectionToSql(SortDirection sortDirection)
  51.     {
  52.         string newSortDirection = String.Empty;
  53.  
  54.         switch (sortDirection)
  55.         {
  56.             case SortDirection.Ascending:
  57.                 newSortDirection = "ASC";
  58.                 break;
  59.  
  60.             case SortDirection.Descending:
  61.                 newSortDirection = "DESC";
  62.                 break;
  63.         }
  64.  
  65.         return newSortDirection;
  66.     }
  67.  
  68.  
  69.     protected void GridView1_PageIndexChanging(object sender, GridViewPageEventArgs e)
  70.     {
  71.         GridView1.EditIndex = -1;
  72.         GridView1.PageIndex = e.NewPageIndex;
  73.         GridView1.DataSource = SortDataTable(GridView1.DataSource as DataTable, true);
  74.         GridView1.DataBind();
  75.     }
  76.  
  77.     protected void GridView1_Sorting(object sender, GridViewSortEventArgs e)
  78.     {
  79.         GridViewSortExpression = e.SortExpression;
  80.         int pageIndex = GridView1.PageIndex;
  81.         GridView1.DataSource = SortDataTable(GridView1.DataSource as DataTable, false);
  82.         GridView1.DataBind();
  83.         GridView1.PageIndex = pageIndex;
  84.     }
  85.     protected DataView SortDataTable(DataTable dataTable, bool isPageIndexChanging)
  86.     {
  87.         if (dataTable != null)
  88.         {
  89.             DataView dataView = new DataView(dataTable);
  90.             if (GridViewSortExpression != string.Empty)
  91.             {
  92.                 if (isPageIndexChanging)
  93.                 {
  94.                     dataView.Sort = string.Format("{0} {1}", GridViewSortExpression, GridViewSortDirection);
  95.                 }
  96.                 else
  97.                 {
  98.                     dataView.Sort = string.Format("{0} {1}", GridViewSortExpression, GetSortDirection());
  99.                 }
  100.             }
  101.             return dataView;
  102.         }
  103.         else
  104.         {
  105.             return new DataView();
  106.         }
  107.     }
  108.     public override void VerifyRenderingInServerForm(Control control)
  109.     {
  110.         // Confirms that an HtmlForm control is rendered for the specified ASP.NET server control at run time.
  111.     }
  112.  
Well after your recent suggestions I think I have a good enough solutions for it:
Expand|Select|Wrap|Line Numbers
  1. private void dgvResults_CellClick(object sender, DataGridViewCellEventArgs e)
  2. {
  3.    if ((e.RowIndex == -1)&&(e.ColumnIndex!=-1))//if both -1, it is the "select all" corner
  4.    {
  5.       if (dgvResults.Columns[e.ColumnIndex].CellType == typeof(DataGridViewTextBoxCell))
  6.       {//sorting
  7.          ShowSplash2(dgvResults, "Sorting...");
  8.       }
  9.    }
  10. }
  11.  
Thanks for the help on that.


As for the cellformating, I stopped looking into it when I found the cellformating event, lets me supply dynamic cell formating based on cell contents.

As a side note, it was the DefaultCellStyle proeprty of the row that I was setting, that was getting reset durring a column sort
Oct 22 '08 #7
Plater
Expert 4TB
Hmm it would seem *I* am guilty of not following proper question titles, I should have stated clearly that I was using a windows application, not a web application.
I will edit the question title
Oct 23 '08 #8

Post your reply

Sign in to post your reply or Sign up for a free account.

Similar topics

reply views Thread by scotch.yard | last post: by
2 posts views Thread by Simon Harvey | last post: by
1 post views Thread by =?Utf-8?B?U2hhcm9u?= | last post: by
reply views Thread by jack112 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.