This is a migrated thread and some comments may be shown as answers.

Show Hourglass Pointer on lengthy operations

17 Answers 250 Views
GridView
This is a migrated thread and some comments may be shown as answers.
erwin
Top achievements
Rank 1
Veteran
erwin asked on 16 Sep 2010, 12:53 PM
With large grids (>100'000 rows) sorting columns can take a lot of time, would be nice if the Grid would show the HourGlass Pointer during such internal operations.
Is there a way I can enable this?

Regards
Erwin

17 Answers, 1 is accepted

Sort by
0
Richard Slade
Top achievements
Rank 2
answered on 17 Sep 2010, 09:45 AM
Hi, 

I think this should work for you. 
Private Sub RadGridView1_SortChanged(ByVal sender As System.Object, ByVal e As Telerik.WinControls.UI.GridViewCollectionChangedEventArgs) Handles RadGridView1.SortChanged
    Me.RadGridView1.Cursor = Cursors.Default
End Sub
 
Private Sub RadGridView1_SortChanging(ByVal sender As System.Object, ByVal e As Telerik.WinControls.UI.GridViewCollectionChangingEventArgs) Handles RadGridView1.SortChanging
    Me.RadGridView1.Cursor = Cursors.WaitCursor
End Sub
Richard
0
erwin
Top achievements
Rank 1
Veteran
answered on 17 Sep 2010, 01:36 PM
Thanks Richard!

However, I have 2 problems

- Changing the Cursor in two places can leave the app with the Wait Cursor if for some reason the SortChanged Event handler does not fire.
 
- The SortChanging event does not seem to fire when only the direction of the sort changes but not the column (?)

Erwin
0
Richard Slade
Top achievements
Rank 2
answered on 17 Sep 2010, 11:49 PM
Hi Erwin,

Yes, it's a good point about changing the cursor in two places, but I don't think it would be up to the grid internally to manage the cursor either.
Don't have access to a dev environment at the moment, but from memory, I think you're right in that it doesn't fire when changing the direction of the coloumn. Just the change of column to sort on fires the event (which in my opinion is incorrect behaviour).

But even if the event fired at all the correct times, I'm not sure if there would be another way around it. Be interested to see what you come up with. If I think of another way, I'll be sure to post it.
Richard
0
Martin Vasilev
Telerik team
answered on 21 Sep 2010, 04:08 PM
Hello guys,

Using SortChanging and SortChanged events is the right way to change the cursor to hourglass. However, it is true that SortChanging event does not fire if only the sort direction is changed. This is an issue and we are going to address it in the next release. Until the issue is addressed, however, there is no workaround that will allow you to implement the desired scenarion. 

Best wishes,
Martin Vasilev
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Accepted
Emanuel Varga
Top achievements
Rank 1
answered on 24 Sep 2010, 10:32 PM
Hello guys,

I would suggest a workaround for the time being, it's not very clean and nice but it does what it should do, and until the SortChanging event will be fixed you don't need to use that method anymore.

First, in the form, register for the SortChanged event, and for the ContextMenuOpening event:
radGridView1.SortChanged += radGridView1_SortChanged;
radGridView1.GridBehavior = new MyBehavior();
radGridView1.ContextMenuOpening += radGridView1_ContextMenuOpening;

Second, we will create a custom behavior that checks if the left mouse click is in the cell header element and if so, set the Cursor to waiting state:
public class MyBehavior : BaseGridBehavior
    {
        protected override bool OnMouseDownLeft(MouseEventArgs e)
        {
            var element = this.GridControl.ElementTree.GetElementAtPoint(e.Location) as GridHeaderCellElement;
            if (element != null)
            {
                this.GridControl.Cursor = Cursors.WaitCursor;
            }
 
            return base.OnMouseDownLeft(e);
        }
    }

After this we will create the SortChanged event where we can set the cursor to the default state:
private void radGridView1_SortChanged(object sender, Telerik.WinControls.UI.GridViewCollectionChangedEventArgs e)
{
    this.radGridView1.Cursor = Cursors.Default;
}

With this everything will work fine if the user click on the table header element, but there is still on thing which we have to take care of if we are slowing also the header context menu, because sort operations can also be accessed from there,
void radGridView1_ContextMenuOpening(object sender, ContextMenuOpeningEventArgs e)
{
    if (e.ContextMenuProvider == null)
    {
        return;
    }
 
    foreach (var item in e.ContextMenu.Items)
    {
        if (item.Text.ToLower().Contains("sort") && ((RadMenuItem)item).ToggleState != ToggleState.On)
        {
            item.MouseUp += item_MouseUp;
        }
    }
}
 
void item_MouseUp(object sender, MouseEventArgs e)
{
    this.radGridView1.Cursor = Cursors.WaitCursor;
}

Here we are checking if the ContextMenuProvider is not null, and after that going trough all of the items in the menu, and those of which contain the sort keyword and are not currently selected we will register them for the MouseUp event to be able to set the cursor to waiting state before performing the operation.

I hope this helps, please let me know if there is something I've missed here.

By the way there is still one problem, when grouping not even the SortChanged event is fired after sorting...., if it were to fire then the custom behavior would change like this:
public class MyBehavior : BaseGridBehavior
{
    protected override bool OnMouseDownLeft(MouseEventArgs e)
    {
        var element = this.GridControl.ElementTree.GetElementAtPoint(e.Location) as GridHeaderCellElement;
        if (element != null)
        {
            this.GridControl.Cursor = Cursors.WaitCursor;
        }
        else if (this.GridControl.EnableGrouping)
        {
            var groupFieldElement = this.GridControl.ElementTree.GetElementAtPoint(e.Location) as GroupFieldElement;
            if (groupFieldElement != null)
            {
                this.GridControl.Cursor = Cursors.WaitCursor;
            }
        }
 
        return base.OnMouseDownLeft(e);
    }
}

BUT, because that event doesn't fire either you will just have always a waiting cursor, so for the time being the previous version should be used...

Best regards,
Emanuel Varga
0
erwin
Top achievements
Rank 1
Veteran
answered on 27 Sep 2010, 11:06 AM
Thanks, Emanuel for you in-depth analysis and suggestion.

Regards
Erwin
0
Hannah
Top achievements
Rank 2
answered on 16 May 2013, 11:57 PM
Hi all,

I'm looking for an update to this topic. I just now realized that a particular grid has many rows, and sorting does indeed take a bit of time.  Long enough to warrant an hourglass.

Martin mentioned that the next release would contain a fix.  While I am new to utilizing the Telerik controls, I would assume that since 2010 an update has been released.  :)

So my question is, how can we do this and in a clean, non-convoluted way?

Best regards,

Wayne
0
Martin Vasilev
Telerik team
answered on 21 May 2013, 01:18 PM
Hi Wayne,

We introduced some performance improvements for the sorting operation in our latest release. The new implementation uses hybrid internal data structure that holds the sorted rows of RadGridView. The new implementation uses the quick sort algorithm when the Rows collection contains up to 10000 rows. When the Rows collection contains more than that the sorting operation uses a red-black binary tree to perform the operation.

However, this optimization might cause issue when there is repetitive data in the grid and in this situation the new algorithm works slower, so you will have to switch back to the old one. To do that we added new property to control this behavior. However, the new API will be available with next our release.

Currently, as a workaround you can change the sorting behavior using this code snippet based on reflection:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
  
    private void Form1_Load(object sender, EventArgs e)
    {
  
        IList<Book> bookList = new List<Book>();
  
        for (int i = 0; i < 10000; i++)
        {
            bookList.Add(new Book { Price = new Random(i).NextDouble() * 100, HardCover = i % 2 == 0 ? "Y" : "N" });
        }
  
        grdBooks.DataSource = bookList;
  
        grdBooks.SortChanging += new Telerik.WinControls.UI.GridViewCollectionChangingEventHandler(grdBooks_SortChanging);
    }
  
    bool initIndex = false;
    void grdBooks_SortChanging(object sender, Telerik.WinControls.UI.GridViewCollectionChangingEventArgs e)
    {
        if (!initIndex)
        {
            AvlIndex<GridViewRowInfo> index = new AvlIndex<GridViewRowInfo>(grdBooks.MasterTemplate.DataView);
            FieldInfo fieldInfo = typeof(RadDataView<GridViewRowInfo>).GetField("indexer", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic);
            if (fieldInfo != null)
            {
                fieldInfo.SetValue(grdBooks.MasterTemplate.DataView, index);
  
            }
  
            fieldInfo = typeof(RadDataView<GridViewRowInfo>).GetField("groupBuilder", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic);
            if (fieldInfo != null)
            {
                fieldInfo.SetValue(grdBooks.MasterTemplate.DataView, new GroupBuilder<GridViewRowInfo>(index));
            }
  
            initIndex = true;
        }
    }
}

If this does not help, please provide us with an example demonstrating the issue, so we can investigate it and help you resolve it. If you want, you can open a new support ticket where you can attach a whole project.

Looking forward to your reply.

Best wishes,
Martin Vasilev
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Hannah
Top achievements
Rank 2
answered on 31 May 2013, 08:54 PM
I'm just looking to show an hourglass while sorting, all my sorting ops are pretty fast, save for one or two items...I decided to go with Richard Slade's solution, since it meets the KISS principle, and I have other fish to fry with my time. :)

Still, love the controls!  I've waited for over 10 years to play with them and there was no way I was going to pay for them myself.

Thanks!

Wayne
0
Peter Stanford
Top achievements
Rank 1
answered on 18 Oct 2013, 12:01 AM
Hi,

I've been following this to see why my code doesn't work. I'm only after the ability to change the cursor to an hourglass while I'm loading up my grid. I have a RadGridView on a windows form. I have a set of radio buttons containing 8 options for showing a list of products, of which there are about 5000 active at any one time. When the user selects one of the radio buttons and then clicks a "Search" button, I run the following code which does not change the cursor to an hourglass. Is the change of cursor only fired on a RadGridView event and if so, which one would I use in my case?

Thanks and best regards

Peter
With RadGridView2
    .BeginUpdate()
    .Cursor = Cursors.WaitCursor
    .DataSource = Collection
    .MasterTemplate.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill
    .Dock = DockStyle.Fill
    .MasterTemplate.AllowAddNewRow = False
    .MasterTemplate.EnableSorting = True
 
    Dim descriptor As New SortDescriptor()
    descriptor.PropertyName = "Invoice_Description"
    descriptor.Direction = ListSortDirection.Ascending
    .MasterTemplate.SortDescriptors.Add(descriptor)
 
    If .Rows.Count > 0 Then
        .AllowEditRow = False
        .AllowDeleteRow = False
        .AllowAddNewRow = False
        .Columns("EntityKey").IsVisible = False
        .Columns("EntityDisplayName").IsVisible = False
        .Columns("RowVersion").IsVisible = False
        .Columns("ID").IsVisible = False
        .Columns("CreationTime").IsVisible = False
        .Columns("CreationUser").IsVisible = False
        .Columns("LastWriteTime").IsVisible = False
        .Columns("LastWriteUser").IsVisible = False
        .Columns("Exclusive_CustomerID").IsVisible = False
        .Columns("Exclusive_Customer").IsVisible = False
        .Columns("BrandID").IsVisible = False
        .Columns("UOM_UnitID").IsVisible = False
        .Columns("UOM_ItemID").IsVisible = False
        .Columns("Unit_Barcode").IsVisible = False
        .Columns("Item_Barcode").IsVisible = False
        .Columns("Unit_Weight").IsVisible = False
        .Columns("Item_Weight").IsVisible = False
        .Columns("Product_GroupID").IsVisible = False
        .Columns("Unit_Actual_Cost").IsVisible = False
        .Columns("Pallet_Quantity").IsVisible = False
        .Columns("Pallet_Weight").IsVisible = False
        .Columns("GST_Percentage").IsVisible = False
        .Columns("Pallet_Layer_Quantity").IsVisible = False
        .Columns("Supplier_Discount_Type_1").IsVisible = False
        .Columns("Supplier_Discount_type_2").IsVisible = False
        .Columns("Supplier_Discount_Amount_1").IsVisible = False
        .Columns("Supplier_Discount_Amount_2").IsVisible = False
        .Columns("Unit_Average_Cost").IsVisible = False
        .Columns("Appropriation_Code").IsVisible = False
        .Columns("Appropriation_CodeID").IsVisible = False
        .Columns("Include_In_StockTake").IsVisible = False
        .Columns("Is_Stocked_Product").IsVisible = False
        .Columns("Is_BuyIn_Product").IsVisible = False
        .Columns("Is_Specialty_Product").IsVisible = False
        .Columns("Is_Quantity_Buy").IsVisible = False
        .Columns("Is_Seasonal_Product").IsVisible = False
        .Columns("Is_Halal_Product").IsVisible = False
        .Columns("Is_Gluten_Free_Product").IsVisible = False
        .Columns("Is_Vegetarian_Product").IsVisible = False
        .Columns("Classification").IsVisible = False
        .Columns("Sub_Classification").IsVisible = False
        .Columns("ClassificationID").IsVisible = False
        .Columns("Sub_ClassificationID").IsVisible = False
        .Columns("School_Canteen_Colour").IsVisible = False
        .Columns("Alternate_Code").IsVisible = False
        .Columns("Alternate_Description").IsVisible = False
        .Columns("Is_Discount_Allowed").IsVisible = False
        .Columns("Freight_Category").IsVisible = False
        .Columns("Freight_Cost").IsVisible = False
        .Columns("Description_Brand_Size").IsVisible = False
        .Columns("System_ComponentModel_IDataErrorInfo_Error").IsVisible = False
        .Columns("CodeFluent_Runtime_Utilities_IKeyable_System_Int32__Key").IsVisible = False
        .Columns("EntityState").IsVisible = False
        For Each column As GridViewDataColumn In .Columns
            column.BestFit()
            column.ReadOnly = True
        Next
        RadGridView2.EndUpdate()
        .Visible = True
    Else
        MsgBox("There are no Products matching your search criteria")
    End If
    RadGridView2.Cursor = Cursors.Default
 
End With
'Catch ex As Exception
'    MsgBox("What's going on?")
'End Try
RadGridView2.Cursor = Cursors.Default

0
George
Telerik team
answered on 22 Oct 2013, 02:15 PM
Hello Peter,

Thank you for writing.

If you set the cursor of the grid and immediately start a heavy operation the grid has no time to process the Cursor request as the UI thread becomes busy. There are two solutions in this case:
  1. Set the cursor and create a timer with some interval. In the timer's tick event start the heavy operations. This will give enough time for the grid to update its cursor.
  2. Use the Cursor property of the Form. This will set the form's cursor while the grid processes the data:
    void btn_Click(object sender, EventArgs e)
    {
        this.Cursor = Cursors.WaitCursor;
        List<string> list = new List<string>();
        for (int i = 0; i < 100000; i++)
        {
            list.Add("STR");
        }
     
        this.grid.DataSource = list;
        this.Cursor = Cursors.Default;
    }

I hope this will be suitable for your case. Let me know if there is anything else I can help you with.

Regards,
George
Telerik
TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WINFORMS.
Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
Sign up for Free application insights >>
0
Peter Stanford
Top achievements
Rank 1
answered on 23 Oct 2013, 03:32 AM
Hi George,

Thanks, I tried a few different options and ultimately the simplest was to use the form-based approach.

Thanks and best regards

Peter
0
George
Telerik team
answered on 25 Oct 2013, 03:30 PM
Hi Peter,

I am glad that this worked out for you.

Do not hesitate to contact us if you need any further assistance.

Regards,
George
Telerik
TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WINFORMS.
Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
Sign up for Free application insights >>
0
Kurt
Top achievements
Rank 1
answered on 03 Nov 2013, 08:42 PM
Hi Martin,

I notice in your reply that the Q3 release might now have the option to change the sorting style by column to the old sort method?

I have 7 columns of which 6 sort great. One is a string column with a selection of string values which can repeat a lot and the sorting on this column takes upwards of 10 seconds with up to 8000 values. Is there now a way to change the sorting behaviour on just this column? I couldn't figure out an elegant way to do it, I was trying to create a numeric column based on the strings, have it hidden and then do a sort on that, but it caused issues with the normal sorting on other columns.
0
George
Telerik team
answered on 06 Nov 2013, 01:59 PM
Hello Kurt,

Thank you for contacting us.

The following code will change the Threshold which defines what algorithm to be used when sorting:
RadDataView<GridViewRowInfo> dataView =this.grid.GridViewElement.Template.ListSource.CollectionView as RadDataView<GridViewRowInfo>;
FieldInfo indexerField =typeof(RadDataView<GridViewRowInfo>).GetField("indexer", BindingFlags.NonPublic | BindingFlags.Instance);
HybridIndex<GridViewRowInfo> indexer = indexerField.GetValue(dataView) as HybridIndex<GridViewRowInfo>;
indexer.Threshold = 500;

With Threshold of 500 if the count of the data items is more than 500 the sorting operation will be performed with a BinaryTree.

I hope this helps.

Regards,
George
Telerik
TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WINFORMS.
Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
Sign up for Free application insights >>
0
Kurt
Top achievements
Rank 1
answered on 07 Nov 2013, 10:16 PM
Thanks that did the trick, sorting is back to full speed.
0
George
Telerik team
answered on 12 Nov 2013, 11:49 AM
Hello Kurt,

I am glad that the problem is solved.

Do not hesitate to contact us if you have any further questions.

Regards,
George
Telerik
TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WINFORMS.
Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
Sign up for Free application insights >>
Tags
GridView
Asked by
erwin
Top achievements
Rank 1
Veteran
Answers by
Richard Slade
Top achievements
Rank 2
erwin
Top achievements
Rank 1
Veteran
Martin Vasilev
Telerik team
Emanuel Varga
Top achievements
Rank 1
Hannah
Top achievements
Rank 2
Peter Stanford
Top achievements
Rank 1
George
Telerik team
Kurt
Top achievements
Rank 1
Share this question
or