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

15 posts, 0 answers
  1. Rajesh
    Rajesh avatar
    27 posts
    Member since:
    Jan 2011

    Posted 31 Jan 2011 Link to this post

    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





  2. Vlad
    Admin
    Vlad avatar
    11100 posts

    Posted 01 Feb 2011 Link to this post

    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>>
  3. Rajesh
    Rajesh avatar
    27 posts
    Member since:
    Jan 2011

    Posted 01 Feb 2011 Link to this post

    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


    .
  4. Vlad
    Admin
    Vlad avatar
    11100 posts

    Posted 01 Feb 2011 Link to this post

    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>>
  5. Rajesh
    Rajesh avatar
    27 posts
    Member since:
    Jan 2011

    Posted 01 Feb 2011 Link to this post

    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>
  6. Rajesh
    Rajesh avatar
    27 posts
    Member since:
    Jan 2011

    Posted 01 Feb 2011 Link to this post

    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
  7. Rajesh
    Rajesh avatar
    27 posts
    Member since:
    Jan 2011

    Posted 02 Feb 2011 Link to this post

    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
  8. Vlad
    Admin
    Vlad avatar
    11100 posts

    Posted 04 Feb 2011 Link to this post

    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>>
  9. Rajesh
    Rajesh avatar
    27 posts
    Member since:
    Jan 2011

    Posted 04 Feb 2011 Link to this post

    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
  10. Vlad
    Admin
    Vlad avatar
    11100 posts

    Posted 07 Feb 2011 Link to this post

    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>>
  11. Rajesh
    Rajesh avatar
    27 posts
    Member since:
    Jan 2011

    Posted 07 Feb 2011 Link to this post

    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.

  12. Rajesh
    Rajesh avatar
    27 posts
    Member since:
    Jan 2011

    Posted 07 Feb 2011 Link to this post

    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

  13. Vlad
    Admin
    Vlad avatar
    11100 posts

    Posted 07 Feb 2011 Link to this post

    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>>
  14. Rajesh
    Rajesh avatar
    27 posts
    Member since:
    Jan 2011

    Posted 07 Feb 2011 Link to this post

    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
  15. Jaroslav Půbal
    Jaroslav Půbal avatar
    52 posts
    Member since:
    Dec 2009

    Posted 31 Mar 2011 Link to this post

    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.
Back to Top