C# windows: DataGridView sorting event troubles

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Plater
    Recognized Expert Expert
    • Apr 2007
    • 7872

    C# windows: DataGridView sorting event troubles

    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:
    [code=c#]
    private void myDGV_CellClick (object sender, DataGridViewCel lEventArgs e)
    {
    if (e.RowIndex == -1)
    {//sorting
    ShowSplash2(myD GV, "Sorting... ");
    }
    }

    private void myDGV_Sorted(ob ject sender, EventArgs e)
    {
    HideSplash2(myD GV);
    }
    [/code]

    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.
  • mldisibio
    Recognized Expert New Member
    • Sep 2008
    • 191

    #2
    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 ColumnHeaderMou seClick 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)D efaultView.Appl ySort(PropertyD escriptor[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 CellStyleChange d 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 DefaultCellStyl e (and there are several...Grid, Row, Column, AlternatingRow) or its Format string.
    Last edited by mldisibio; Oct 10 '08, 04:41 AM. Reason: Removed unnecessary chatter about post-sorting events...using the Sorted event is obviously the most reliable...

    Comment

    • mldisibio
      Recognized Expert New Member
      • Sep 2008
      • 191

      #3
      One more thought...the DataGridViewCol umn has a SortMode property...whic h can be set to NotSortable for the columns such as all check boxes or whatnot...(assu ming you truly do not want them sorted).

      I guess the ColumnHeaderMou seClick 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...?

      Comment

      • Plater
        Recognized Expert Expert
        • Apr 2007
        • 7872

        #4
        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 DataBindingComp lete 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 ColumnHeaderMou seClick 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

        Comment

        • mldisibio
          Recognized Expert New Member
          • Sep 2008
          • 191

          #5
          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 ColumnHeaderMou seClick irrelevant...so rry.

          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.

          Comment

          • Plater
            Recognized Expert Expert
            • Apr 2007
            • 7872

            #6
            Well after your recent suggestions I think I have a good enough solutions for it:
            [code=c#]
            private void dgvResults_Cell Click(object sender, DataGridViewCel lEventArgs e)
            {
            if ((e.RowIndex == -1)&&(e.ColumnIn dex!=-1))//if both -1, it is the "select all" corner
            {
            if (dgvResults.Col umns[e.ColumnIndex].CellType == typeof(DataGrid ViewTextBoxCell ))
            {//sorting
            ShowSplash2(dgv Results, "Sorting... ");
            }
            }
            }
            [/code]

            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 DefaultCellStyl e proeprty of the row that I was setting, that was getting reset durring a column sort

            Comment

            • divyavk21
              New Member
              • Sep 2008
              • 6

              #7
              Sample code :
              [code=c#]
              string Connstring = @"Server=IN4410 9369\SQLExpress ; Database=MATool ;Trusted_Connec tion=Yes";
              conn = new SqlConnection(C onnstring);
              string SQLcnn = "SELECT Id,Analyst,Vend orType,Site,Leg al,QAD_Code,Pha se_II_Audit,QAD _Status,Code_St atus,Pop_Form_T AT,Rec_Form_TAT ,TAT_AP,EDI_TAT ,VMTAT,Audited_ By,VM_FTT,TOE,V M_Error_Desc,Ca tegory,Fatal,No n_Fatal,PhaseII _AuditStatus,Au dit_Status,Audi t_Compl_Date,Au dit_Compl_Time, Audit_TAT FROM [dbo].[tblQAD] where [Audited_By]= @PAnalyst and [PhaseII_AuditSt atus] = @PStatus";
              cmd = new SqlCommand(SQLc nn, conn);
              cmd.Parameters. Add(new SqlParameter("@ PAnalyst", System.Data.Sql DbType.NChar, 10, "Audited_By "));
              cmd.Parameters. Add(new SqlParameter("@ PStatus", System.Data.Sql DbType.NChar, 10, "PhaseII_AuditS tatus"));
              cmd.Parameters["@PAnalyst"].Value = lblUser.Text;
              cmd.Parameters["@PStatus"].Value = lblPendingStatu s.Text;
              SqlDataAdapter sdr = new SqlDataAdapter( cmd);
              DataTable dt = new DataTable("tblQ AD");
              sdr.Fill(dt);
              int dataTableRowCou nt = dt.Rows.Count;
              if (dataTableRowCo unt > 0)
              {
              GridView1.Visib le = true;
              GridView1.DataS ource = dt;
              GridView1.DataB ind();
              }
              else
              {
              GridView1.Visib le = false;
              }

              private string GetSortDirectio n()
              {
              switch (GridViewSortDi rection)
              {
              case "ASC":
              GridViewSortDir ection = "DESC";
              break;

              case "DESC":
              GridViewSortDir ection = "ASC";
              break;
              }

              return GridViewSortDir ection;
              }
              private string GridViewSortDir ection
              {
              get { return ViewState["SortDirect ion"] as string ?? "ASC"; }
              set { ViewState["SortDirect ion"] = value; }
              }
              private string GridViewSortExp ression
              {
              get { return ViewState["SortExpression "] as string ?? string.Empty; }
              set { ViewState["SortExpression "] = value; }
              }

              private string ConvertSortDire ctionToSql(Sort Direction sortDirection)
              {
              string newSortDirectio n = String.Empty;

              switch (sortDirection)
              {
              case SortDirection.A scending:
              newSortDirectio n = "ASC";
              break;

              case SortDirection.D escending:
              newSortDirectio n = "DESC";
              break;
              }

              return newSortDirectio n;
              }


              protected void GridView1_PageI ndexChanging(ob ject sender, GridViewPageEve ntArgs e)
              {
              GridView1.EditI ndex = -1;
              GridView1.PageI ndex = e.NewPageIndex;
              GridView1.DataS ource = SortDataTable(G ridView1.DataSo urce as DataTable, true);
              GridView1.DataB ind();
              }

              protected void GridView1_Sorti ng(object sender, GridViewSortEve ntArgs e)
              {
              GridViewSortExp ression = e.SortExpressio n;
              int pageIndex = GridView1.PageI ndex;
              GridView1.DataS ource = SortDataTable(G ridView1.DataSo urce as DataTable, false);
              GridView1.DataB ind();
              GridView1.PageI ndex = pageIndex;
              }
              protected DataView SortDataTable(D ataTable dataTable, bool isPageIndexChan ging)
              {
              if (dataTable != null)
              {
              DataView dataView = new DataView(dataTa ble);
              if (GridViewSortEx pression != string.Empty)
              {
              if (isPageIndexCha nging)
              {
              dataView.Sort = string.Format(" {0} {1}", GridViewSortExp ression, GridViewSortDir ection);
              }
              else
              {
              dataView.Sort = string.Format(" {0} {1}", GridViewSortExp ression, GetSortDirectio n());
              }
              }
              return dataView;
              }
              else
              {
              return new DataView();
              }
              }
              public override void VerifyRendering InServerForm(Co ntrol control)
              {
              // Confirms that an HtmlForm control is rendered for the specified ASP.NET server control at run time.
              }
              [/code]
              Originally posted by Plater
              Well after your recent suggestions I think I have a good enough solutions for it:
              [code=c#]
              private void dgvResults_Cell Click(object sender, DataGridViewCel lEventArgs e)
              {
              if ((e.RowIndex == -1)&&(e.ColumnIn dex!=-1))//if both -1, it is the "select all" corner
              {
              if (dgvResults.Col umns[e.ColumnIndex].CellType == typeof(DataGrid ViewTextBoxCell ))
              {//sorting
              ShowSplash2(dgv Results, "Sorting... ");
              }
              }
              }
              [/code]

              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 DefaultCellStyl e proeprty of the row that I was setting, that was getting reset durring a column sort

              Comment

              • Plater
                Recognized Expert Expert
                • Apr 2007
                • 7872

                #8
                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

                Comment

                Working...