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

Adding 5000 distinct record for a column based on which grouping is done causing IE crash

14 Answers 131 Views
GridView
This is a migrated thread and some comments may be shown as answers.
Rajesh
Top achievements
Rank 1
Rajesh asked on 31 Jan 2011, 06:29 PM
Hello Telerik Admin,

I am trying to develop a application using GridView .In my application:

1. When page loads i am grouping based on a column name Notes.
2. Getting data in form of datatable.(Using Silverlight DataTable code provided by telerik).
3. Getting Datatable from 2 webservice.After fetching data from 1st webervice binding data to grid.
4. After that invoking 2nd webservice.After getting data from 2nd service adding datarow's from 2nd datatable to gridview's itemsource.

In 2nd datatable 4k-5k records are there(All disinct for group by column) .I am copying data in for loop.It is not coming to the end of the for loop and applicaion is hanging.Many times IE also crashed.

I tried with Defer refresh also but after calling defeerrefresh even i call refresh also it is not updating with new rows.
Kindly suggest.

Thanks,
Rajesh





14 Answers, 1 is accepted

Sort by
0
Vlad
Telerik team
answered on 01 Feb 2011, 08:14 AM
Hi,

 Can you clarify a bit on "am copying data in for loop.It is not coming to the end of the for loop and applicaion is hanging."?

Kind regards,
Vlad
the Telerik team
Let us know about your Windows Phone 7 application built with RadControls and we will help you promote it. Learn more>>
0
Rajesh
Top achievements
Rank 1
answered on 01 Feb 2011, 10:46 AM
Dear Vlad,

I am copying data from 2nd data data table to the 1st data table which is item source of gridview.I am looping through each dararow from 2nd datatable and creating a new row in first datatable (coying columnvalue from 2nd datatable's row to newly created row).If before the loop i am calling delayrefresh method in that case control is exiting from loop and UI is coming up but groups corresponding to newly added datarow's are not showing on UI.(Calling refresh method after loop exits).But if i am not calling delay refresh method UI is not reponsive at all.If i put breakpoint i can seee that even it is not exiting from the for loop and control never comes out of for loop.

Let me know if more details are required.
Thanks,
Rajesh


.
0
Vlad
Telerik team
answered on 01 Feb 2011, 10:47 AM
Hi,

 Can you send us small (runnable) example project via support ticket where we can check exactly your scenario and reproduce the problem? 

Greetings,
Vlad
the Telerik team
Let us know about your Windows Phone 7 application built with RadControls and we will help you promote it. Learn more>>
0
Rajesh
Top achievements
Rank 1
answered on 01 Feb 2011, 02:06 PM

Dear Vlad,

I have pasted code snippet below.This is a prototype and in my case i have many more columns.(Here there are only three).
You can see in timer_Tick method i have a for loop.In this loop it takes long time.For loop took around 8 minutes in last run which i did locally.I am going to log a support ticket as well but i think using this snippet you will get some idea what i am trying to do.

Thanks,
Rajesh


public partial class MainPage : UserControl 
    public MainPage() 
    
        InitializeComponent(); 
  
        RadGridView1.ItemsSource = GetDataTable1(); 
        RadGridView1.GroupDescriptors.Add(new GroupDescriptor() { Member = "Name" }); 
        DispatcherTimer timer = new DispatcherTimer(); 
        timer.Tick += new EventHandler(timer_Tick); 
        timer.Interval = new TimeSpan(0, 0, 25); 
        timer.Start(); 
    
    void timer_Tick(object sender, EventArgs e) 
    
        (sender as DispatcherTimer).Stop(); 
        (sender as DispatcherTimer).Tick -= timer_Tick; 
        DataTable dtable = RadGridView1.ItemsSource as DataTable; 
            //change 5000 to 6000 or 7000 
  
//Put breakpoint before start of this for loop and after end of this for loop
        for (int i = 21; i < 5000; i++) 
        
            DataRow dr = dtable.NewRow(); 
            dr["ID"] = i; 
            dr["Name"] = "TestName" + i.ToString(); 
            dr["Date"] = DateTime.Today; 
            dtable.Rows.Add(dr); 
        
    
    private DataTable GetDataTable1() 
    
        DataTable table = new DataTable(); 
        table.Columns.Add(new DataColumn() { ColumnName = "ID", DataType = typeof(int) }); 
        table.Columns.Add(new DataColumn() { ColumnName = "Name", DataType = typeof(string) }); 
        table.Columns.Add(new DataColumn() { ColumnName = "Date", DataType = typeof(DateTime) }); 
        for (int i = 0; i < 20; i++) 
        
            DataRow dr = table.NewRow(); 
            dr["ID"]= i; 
            dr["Name"] = "TestName" + i.ToString(); 
            dr["Date"] = DateTime.Today; 
            table.Rows.Add(dr); 
        
        return table; 
    
}
<Grid x:Name="LayoutRoot" Background="White" Margin="10">
      <Grid.RowDefinitions>
          <RowDefinition Height="Auto" />
          <RowDefinition />
      </Grid.RowDefinitions>
      <telerik:RadGridView x:Name="RadGridView1" AutoExpandGroups="True" Grid.Row="1" />
  </Grid>
0
Rajesh
Top achievements
Rank 1
answered on 01 Feb 2011, 04:58 PM
Dear Vlad,

I was trying to upload the source code but somehow was not able to locate the URI from where i can open support ticket.
If the snippet which i have provided is not enough to reproduce the scenario in that case Kindly let me know procedure of opening a new support ticket.

Thanks,
Rajesh
0
Rajesh
Top achievements
Rank 1
answered on 02 Feb 2011, 01:59 PM
Dear Vlad,

Was you able to reproduce the issue which i have mentioned in previous mails.
Can you please give me some suggestion of fixing this.

Thanks,
Rajesh
0
Vlad
Telerik team
answered on 04 Feb 2011, 02:47 PM
Hello,

 I've checked the code and I've found what is causing this issue. RadGridView will try to respond to every CollectionChanged event raised from the DataTable in order to refresh the UI - here is an example how to avoid this:

void timer_Tick(object sender, EventArgs e)
{
    (sender as DispatcherTimer).Stop();
    (sender as DispatcherTimer).Tick -= timer_Tick;
    DataTable dtable = RadGridView1.ItemsSource as DataTable;

    RadGridView1.ItemsSource = null; 
    //change 5000 to 6000 or 7000 


    //Put breakpoint before start of this for loop and after end of this for loop
    for (int i = 21; i < 5000; i++)
    {
        DataRow dr = dtable.NewRow();
        dr["ID"] = i;
        dr["Name"] = "TestName" + i.ToString();
        dr["Date"] = DateTime.Today;
        dtable.Rows.Add(dr);
    }

    RadGridView1.ItemsSource = dtable;
    RadGridView1.GroupDescriptors.Add(new GroupDescriptor() { Member = "Name" });

}

Regards,
Vlad
the Telerik team
Let us know about your Windows Phone 7 application built with RadControls and we will help you promote it. Learn more>>
0
Rajesh
Top achievements
Rank 1
answered on 04 Feb 2011, 03:46 PM
Dear Vlad,

Thanks for your response.I am also using same kind of code which you have suggested with few changes.

Approach 1 (suggested by you)# You are setting itemsource to null the basic problem is that you will have to apply group by again because after setting null as itemsource group by columns will not be available.

Approach 2(My approach) # In my case I am creating a clone of datatable and adding a dummy item and then applying that dummy item as itemsource.So in my case i don't have to add all group by columns again to maintain group by state .

Other problem with both these approaches is that it will not maintain the state if you have groups in expanded state because datasource is changing 
For e.g take a scenario in which
1.whenever  I am dragging and dropping new columns based on which i want to apply group by i am adding new items to datatable(similar code as timer_Tick).
2.User has dragged and dropped 2 group by columns and few of items are in expanded state.
3.User is dragging 3rd column to perform group by based on that column.You can see that state will not be maintained because the underlying datasource we have changed.

The other problem is when i try to add 2-3 new rows after having 2000 distinct groups it takes really long time.

Can you suggest me some approach where i don't have to change the datasource without compromising on performance.I have seen many posts from you and due to that i am hopeful you can suggest me some approach using which i can overcome this issue.

Thanks,
Rajesh
0
Vlad
Telerik team
answered on 07 Feb 2011, 10:31 AM
Hi Rajesh,

 The main problem comes from the fact that RadGridView is grouped. When you add an item in the source collection the grid will re-group in order to position the item in the proper group - this operation is expensive. When you do this 5000 times in a loop actually you will force RadGridView to re-group 5000 times and because of this you have such performance problem.

The other possible approach will be to use RadObservableCollection<> in the DataTable instead ObservableCollection<>. Here is an example how to change the code:

private void CreateInternalView()
{
    this.internalView = (IList)Activator.CreateInstance(typeof(RadObservableCollection<>).MakeGenericType(this.ElementType));
    ((INotifyCollectionChanged)internalView).CollectionChanged += (s, e) => { this.OnCollectionChanged(e); };
}
 
public void SuspendNotifications()
{
    ((ISuspendNotifications)this.InternalView).SuspendNotifications();
}
 
public void ResumeNotifications()
{
    ((ISuspendNotifications)this.InternalView).ResumeNotifications();
}


Here is also how to use these methods:
void timer_Tick(object sender, EventArgs e)
{
    (sender as DispatcherTimer).Stop();
    (sender as DispatcherTimer).Tick -= timer_Tick;
    DataTable dtable = RadGridView1.ItemsSource as DataTable;
 
    dtable.SuspendNotifications();
 
    for (int i = 21; i < 5000; i++)
    {
        DataRow dr = dtable.NewRow();
        dr["ID"] = i;
        dr["Name"] = "TestName" + i.ToString();
        dr["Date"] = DateTime.Today;
        dtable.Rows.Add(dr);
    }
 
    dtable.ResumeNotifications();
}


All the best,
Vlad
the Telerik team
Let us know about your Windows Phone 7 application built with RadControls and we will help you promote it. Learn more>>
0
Rajesh
Top achievements
Rank 1
answered on 07 Feb 2011, 01:31 PM

Thanks Vlad.I will look into this and will check whether there is any issue which i get due to this approach.I just want to ask you regarding one approach which i am currently using.Let me know if this is also ok without changing datatable.

void timer_Tick(object sender, EventArgs e)
{
    (sender as DispatcherTimer).Stop();
    (sender as DispatcherTimer).Tick -= timer_Tick;
    DataTable dtable = RadGridView1.ItemsSource as DataTable;
//Defer the refresh cycle
 using(RadGridView1.DeferRefresh())
{
   
 
for (int i = 21; i < 5000; i++)
    {
        DataRow dr = dtable.NewRow();
        dr["ID"] = i;
        dr["Name"] = "TestName" + i.ToString();
        dr["Date"] = DateTime.Today;
        dtable.Rows.Add(dr);
    }
 }
//A dummy row to refresh and  update all rows.after deferred update
   DataRow dr = dtable.NewRow();
dtable.Rows.Add(dr);
dtable.Rows.Remove(dr);

}

Please let me know if this approach also i can use without any issue.
Here i am deferring refresh and adding all rows in deferred cycle.After that i am adding and removing a dummy row to bring grid control to normal state.

0
Rajesh
Top achievements
Rank 1
answered on 07 Feb 2011, 01:47 PM

Dear Vlad,

ISuspendNotification interface is in which namespace or assembly.I am using 2010 Q2 release and i am not able to get that interface.

Thanks,
Rajesh

0
Vlad
Telerik team
answered on 07 Feb 2011, 02:21 PM
Hi Rajesh,

 This interface is available in our Q3 2010 release and above. Generally you do not need to add and remove the dummy row - to achieve the same you can call Rebind(). For example:

(sender as DispatcherTimer).Stop();
(sender as DispatcherTimer).Tick -= timer_Tick;
DataTable dtable = RadGridView1.ItemsSource as DataTable;
 
using (RadGridView1.DeferRefresh())
{
    for (int i = 21; i < 5000; i++)
    {
        DataRow dr = dtable.NewRow();
        dr["ID"] = i;
        dr["Name"] = "TestName" + i.ToString();
        dr["Date"] = DateTime.Today;
        dtable.Rows.Add(dr);
    }
}
 
RadGridView1.Rebind();


Kind regards,
Vlad
the Telerik team
Let us know about your Windows Phone 7 application built with RadControls and we will help you promote it. Learn more>>
0
Rajesh
Top achievements
Rank 1
answered on 07 Feb 2011, 02:46 PM
Thanks Vlad,

Actually i have tried with Rebind method but somehow it is now working in my case.Problem is that if i have multiple level grouping applied in that case Rebind method call collapses groups of lower level.

Rajesh
0
Jaroslav Půbal
Top achievements
Rank 1
answered on 31 Mar 2011, 05:00 PM
I had same problem. When RadGrid has filter set then "AddRange" method never return.
The problem suprise me, but solution was simple.

RadObservableCollection<string> stringy;
....
  
stringy.SuspendNotifications();
stringy.Clear();
stringy.AddRange(wsCall.Result.Body.@return); //@return is ObservableCollection<>
stringy.ResumeNotifications();

It will be nice if you provide "using()" member.

RadObservableCollection<string> stringy; 
.... 
    
using (stringy.DeferNotifications()) {
    stringy.Clear(); 
    stringy.AddRange(wsCall.Result.Body.@return); //@return is ObservableCollection<> 
}

And another point .. when ending "using()" or call "ResumeNotifications()" one all-in-one notification should be fired.
We typically dont want stop all notifications, rather we want one bulk notification.
Tags
GridView
Asked by
Rajesh
Top achievements
Rank 1
Answers by
Vlad
Telerik team
Rajesh
Top achievements
Rank 1
Jaroslav Půbal
Top achievements
Rank 1
Share this question
or