EnableRowVirtualization = true crashes BringIntoView

Nov 7, 2008 at 8:41 PM
Edited Nov 7, 2008 at 8:44 PM
Hello guys,

If I try to do something like this, the program crashes if EnableRowVirtualization is true:
                    itemCollection.Add(item);

                    ((ListCollectionView)dataGrid.ItemsSource).Refresh();

                    dataGrid.SelectedItem = item;
                    dataGrid.ScrollIntoView(item);

where data is binded liked this:
            itemCollection = new GroupCollection().Load();
            ListCollectionView dgcv = new ListCollectionView(itemCollection) { Filter = SearchFilter };
            dataGrid.ItemsSource = dgcv;

ScrollIntoView fails with a NullReferenceException. The exception is thrown from VirtualizingStackPanel.

If EnableRowVirtualization is false, nothing happens. The code runs just fine. Can anybody tell why this happens?

Thanks & Regards,
Yogesh.
Nov 8, 2008 at 1:31 PM
Guys...

Anybody???

Why ScrollIntoView fails when EnableRowVirtualization == false? I cannot disable EnableRowVirtualization as it slows the grid as hell (table contains 100,000 rows).
Coordinator
Nov 8, 2008 at 6:23 PM
Can you post a simple sample of XAML and code behind which crashes with Null ref exception?
Nov 8, 2008 at 7:49 PM
Hello
I have this problem too..
we just bind grid to dataview in better way we have
CollectionViewSource viewSource;
viewSource.Source = dataview
gtagrid.ItemsSource = viewSource.View as BindingListCollectionView;

after we want to set new item in grid ( in currentitem cganged event of viewSource.View)
  void View_CurrentChanged(object sender, EventArgs e)
        {

            if (entityGrid.CurrentItem != viewSource.View.CurrentItem)
                {
                    entityGrid.CurrentItem = viewSource.View.CurrentItem;
           
                }
    }
this error raised.
also after we set filter of dataview again this error happened too.
/////////////////////
for us if disable
EnableRowVirtualization = false
 and BringIntoView a row, that row has not any cell in content and can not focus a cell in it.

please any help...
Nov 9, 2008 at 6:37 AM
I am posting only portions for reference. Here is the xaml:
        <toolkit:DataGrid Style="{StaticResource DataGridStyle}" x:Name="dataGrid" Grid.Row="1" Height="250" Width="500"
            ItemsSource="{Binding}" IsReadOnly="True" Sorting="dataGrid_Sorting" Margin="10,0,10,0"
            EnableRowVirtualization="True" />

Here is the code behind:
Loaded:
            itemCollection = new GroupCollection(); // itemCollection is a private member
            ListCollectionView dgcv = new ListCollectionView(itemCollection) { Filter = SearchFilter };
            dataGrid.ItemsSource = dgcv;

Now if I add a new item on the fly and try to use ScrollIntoView, the program crashes. The crash does not happen inside toolkit, but inside PresentationCore.dll. You can easily reproduce the error (atleast I did) with a large number of rows and using Filter with ListViewCollection as the datasource.
            itemCollection.Add(item);

            ((ListCollectionView)dataGrid.ItemsSource).Refresh();

            dataGrid.SelectedItem = item;
            dataGrid.Items.Refresh(); // This hardly makes a difference
            ScrollIntoView(item); // The program crashes here if EnableRowVirtualization is true

Nov 9, 2008 at 12:53 PM
hello
any help
these are my stack trace :
//////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\
>    PresentationFramework.dll!System.Windows.Controls.VirtualizingStackPanel.InsertContainer(int childIndex = 0, System.Windows.UIElement container = {Microsoft.Windows.Controls.DataGridRow}, bool isRecycled) + 0x144 bytes   
     PresentationFramework.dll!System.Windows.Controls.VirtualizingStackPanel.AddContainerFromGenerator(int childIndex, System.Windows.UIElement child, bool newlyRealized) + 0x29 bytes   
     PresentationFramework.dll!System.Windows.Controls.VirtualizingStackPanel.BringIndexIntoView(int index) + 0x98 bytes   
     WPFToolkit.dll!Microsoft.Windows.Controls.Primitives.DataGridRowsPresenter.InternalBringIndexIntoView(int index = 19) Line 48 + 0xe bytes    C#
     WPFToolkit.dll!Microsoft.Windows.Controls.DataGrid.ScrollRowIntoView(object item = {System.Data.DataRowView}) Line 1617 + 0xd bytes    C#
     WPFToolkit.dll!Microsoft.Windows.Controls.DataGrid.ScrollCellIntoView(object item = {System.Data.DataRowView}, Microsoft.Windows.Controls.DataGridColumn column = {Tools.WPF.UI.EntityGridViewColumn}) Line 1638 + 0xb bytes    C#
     WPFToolkit.dll!Microsoft.Windows.Controls.DataGrid.OnCurrentCellChanged(System.Windows.DependencyObject d = {Tools.WPF.UI.EntityGridView Items.Count:40 Grid Name : grdPrinterInfo}, System.Windows.DependencyPropertyChangedEventArgs e = {System.Windows.DependencyPropertyChangedEventArgs}) Line 2832 + 0x3e bytes    C#
     WindowsBase.dll!System.Windows.DependencyObject.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) + 0x4a bytes   
     PresentationFramework.dll!System.Windows.FrameworkElement.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) + 0x50 bytes   
     WindowsBase.dll!System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs args) + 0x2c bytes   
     WindowsBase.dll!System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex entryIndex = {System.Windows.EntryIndex}, System.Windows.DependencyProperty dp = {CurrentCell}, System.Windows.PropertyMetadata metadata, System.Windows.EffectiveValueEntry oldEntry, ref System.Windows.EffectiveValueEntry newEntry = {System.Windows.EffectiveValueEntry}, bool coerceWithDeferredReference, System.Windows.OperationType operationType) + 0x515 bytes   
     WindowsBase.dll!System.Windows.DependencyObject.SetValueCommon(System.Windows.DependencyProperty dp, object value, System.Windows.PropertyMetadata metadata, bool coerceWithDeferredReference, System.Windows.OperationType operationType, bool isInternal) + 0x1eb bytes   
     WindowsBase.dll!System.Windows.DependencyObject.SetValue(System.Windows.DependencyProperty dp, object value) + 0x2e bytes   
     WPFToolkit.dll!Microsoft.Windows.Controls.DataGrid.CurrentCell.set(Microsoft.Windows.Controls.DataGridCellInfo value = {Microsoft.Windows.Controls.DataGridCellInfo}) Line 2775 + 0x45 bytes    C#
     WPFToolkit.dll!Microsoft.Windows.Controls.DataGrid.OnCurrentItemChanged(System.Windows.DependencyObject d = {Tools.WPF.UI.EntityGridView Items.Count:40 Grid Name : grdPrinterInfo}, System.Windows.DependencyPropertyChangedEventArgs e = {System.Windows.DependencyPropertyChangedEventArgs}) Line 2729 + 0x3d bytes    C#
     WindowsBase.dll!System.Windows.DependencyObject.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) + 0x4a bytes   
     PresentationFramework.dll!System.Windows.FrameworkElement.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e) + 0x50 bytes   
     WindowsBase.dll!System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs args) + 0x2c bytes   
     WindowsBase.dll!System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex entryIndex = {System.Windows.EntryIndex}, System.Windows.DependencyProperty dp = {CurrentItem}, System.Windows.PropertyMetadata metadata, System.Windows.EffectiveValueEntry oldEntry, ref System.Windows.EffectiveValueEntry newEntry = {System.Windows.EffectiveValueEntry}, bool coerceWithDeferredReference, System.Windows.OperationType operationType) + 0x515 bytes   
     WindowsBase.dll!System.Windows.DependencyObject.SetValueCommon(System.Windows.DependencyProperty dp, object value, System.Windows.PropertyMetadata metadata, bool coerceWithDeferredReference, System.Windows.OperationType operationType, bool isInternal) + 0x1eb bytes   
     WindowsBase.dll!System.Windows.DependencyObject.SetValue(System.Windows.DependencyProperty dp, object value) + 0x2e bytes   
     WPFToolkit.dll!Microsoft.Windows.Controls.DataGrid.CurrentItem.set(object value = {System.Data.DataRowView}) Line 2711 + 0x12 bytes    C#
     Tools.WPF.exe!Tools.WPF.UI.EntityBindingSource.View_CurrentChanged(object sender = {System.Windows.Data.BindingListCollectionView}, System.EventArgs e = {System.EventArgs}) Line 193 + 0x2f bytes    C#
Nov 9, 2008 at 7:29 PM
hello again
we trace program and use dataGrid.BeginInvoke() that call datagrid.scrollintoview  after dataview( source of datagrid)  changed,
It does good without any errors but  after  we  insert new datarow in dataview again have problem . we think
maybee (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) does not work good because before call datagrid.scrollintoview
ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerate is true but we see grid in "moole visualizer " grid does not draw and there are not any
datarowgrid.
///
sorry we need know where all rows in virtual panel are created is there an event?


is it a bug or we are wrong.....
any help...
Nov 11, 2008 at 8:25 AM
Edited Nov 11, 2008 at 8:27 AM
again hello  
there are not any solutions..........
please help.....
Coordinator
Nov 12, 2008 at 2:06 PM
yjagota,

For your issue, try this instead, 

dataGrid.ScrollIntoView(dataGrid.Items[dataGrid.Items.Count -1]);

Nov 12, 2008 at 5:21 PM
Didn't solved the issue Vincent.
Nov 15, 2008 at 7:46 AM
@Vincent:

I dug up a little deeper and found that the exception is raised in VirtualizingStackPanel class, inside InsertContainer method.

The block which causes the exception is:
            if (IsVirtualizing && InRecyclingMode)
            {
                _realizedChildren.Insert(childIndex, container);
            }

There is no check for _realizedChildren is null. In case of DataGrid, it is. Calling the private method EnsureRealizedChildren might have cured the issue, but I don't know why it's not called.

So, for the time being just disabling recycling mode solves the issue, but this is also a temporary solution as this solution uses more memory.

I hope you will look into this.

Coordinator
Nov 26, 2008 at 2:48 AM

yjagota,
Does the ItemsSource of the DataGrid implement INotifyCollectionChanged interface ?

When ItemsSource is modified and INotifyCollectionChanged  is not implemented, DataGrid is not aware of these changes. That could be the reason for these exceptions.

Try this as a work around. Set the ItemsSource to null, make changes to your ItemsSource (add/delete/clear). Now set ItemsSource again.

dataGrid.ItemsSource = null;
itemCollection.Add(item);
ListCollectionView dgcv = new ListCollectionView(itemCollection) { Filter = SearchFilter };
dataGrid.ItemsSource = dgcv;

OR
After modifying ItemsSource try
(dataGrid.Items

as ICollectionView).Refresh();

Hope this helps.

 

Nov 29, 2008 at 11:57 AM
Didn't helped.

I tried both the ways, i.e. creating a separate instance of the collection and implementing INotifyCollectionChanged.
Dec 8, 2008 at 5:06 PM
Still no word on this?
Coordinator
Dec 8, 2008 at 9:15 PM
I think I have understood the cause for the problem. Refresh call leads to an asychronous call to UpdateLayout operation. When you set the SelectedItem,it causes for that item to be scrolled into view. UpdateLayout is not getting completed by the time ScrollIntoView is called, hence the exception. We have a fix for this issue, but meanwhile you can use this as a work around. 

After Refresh, schedule any SelectedItem or ScrollIntoView as an asynchronous operation to the Dispatcher, with a DispatcherPriority of Loaded or lower priority.

itemCollection.Add(item);
dataGrid.Items.Refresh();
Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new DispatcherOperationCallback(ScrollItemsIntoView), item);

 

Definition of ScrollItemsIntoView:

private object ScrollItemsIntoView(object item)
{
dataGrid.SelectedItem = item;
dataGrid.ScrollIntoView(item);
return null;
}

Dec 9, 2008 at 5:43 AM
Thanks a lot for the fix man. Works perfectly now. :)
Feb 25, 2009 at 11:26 PM
Hi kedecond,

The work around you provided is cool (thank you) - but it will not work for me unfortunately, so I just want to let the WPF know in case if you guys/gals think this is fixed (or maybe I am doing something wrong).

In my case I have a master/details scenario where I have a master grid, and when a row in that is selected I set the ItemsSource of a details grid to another collection, and I try to scroll the details grid to the last item.

In my case using the above workaround, sometimes it works and sometimes it crashes. I am assuming because the details grid may have had it's items source updated again (by scrolling through the master) before the DispatcherOperationCallback operation got a chance to execute.  Then the DispatcherOperationCallback executes and bombs.

Does this sound like a scenario that should work?
Cheers,
Jon


Coordinator
Feb 26, 2009 at 10:57 PM
JonProactiveLogic,
1. Does the crash occur in the master grid or details grid ?
2. Is your ItemsSource for the details grid an ObservableCollection or implement INotifyCollectionChanged  ?
3. "the details grid may have had it's items source updated again (by scrolling through the master)". It could be that the layout is showing the latest ItemsSource already and you are invoking scroll on the previous ItemsSource. Perhaps in the DispatcherOperationCallback, you can have some kind of check that you scroll in the most recent ItemsSource and not the previous ItemsSource.

If you can send me a small repro of your app, I can look into the issue.
Mar 30, 2010 at 6:11 PM

Ok, it is March 2010. I am using February 2010 Release of WPF ToolKit and still having the same issue.

The work aroung using Dispatcher.BeginInvoke works, but I thought you said you have a fix.

Am I missing something?