Yep, probably I've found the reason:
Here's the code of DataGrid.ScrollIntoView (decompiled by Resharper)
internal void ScrollIntoView(ItemsControl.ItemInfo info)
{
if (this.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
this.OnBringItemIntoView(info);
else
this.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, (Delegate) new DispatcherOperationCallback(((ItemsControl) this).OnBringItemIntoView), (object) info);
}
Here they cast info
to the object type. Whell, the problem is really that DispatcherOperationCallback
expects object
.
But ItemsControl
has two overloads for OnBringItemIntoView
:
one for ItemsControl.ItemInfo
and the second for object
type.
internal object OnBringItemIntoView(ItemsControl.ItemInfo info)
{
FrameworkElement frameworkElement = info.Container as FrameworkElement;
if (frameworkElement != null)
frameworkElement.BringIntoView();
else if ((info = this.LeaseItemInfo(info, true)).Index >= 0)
{
VirtualizingPanel virtualizingPanel = this.ItemsHost as VirtualizingPanel;
if (virtualizingPanel != null)
virtualizingPanel.BringIndexIntoView(info.Index);
}
return (object) null;
}
internal object OnBringItemIntoView(object arg)
{
return this.OnBringItemIntoView(this.NewItemInfo(arg, (DependencyObject) null, -1));
}
Guess, which one is selected? ;-)
So they get ItemInfo
wrapped in ItemInfo
. That's why this.LeaseItemInfo(info, true)
iside
internal object OnBringItemIntoView(ItemsControl.ItemInfo info)
{
FrameworkElement frameworkElement = info.Container as FrameworkElement;
if (frameworkElement != null)
frameworkElement.BringIntoView();
else if ((info = this.LeaseItemInfo(info, true)).Index >= 0)
{
VirtualizingPanel virtualizingPanel = this.ItemsHost as VirtualizingPanel;
if (virtualizingPanel != null)
virtualizingPanel.BringIndexIntoView(info.Index);
}
return (object) null;
}
recieves incorrect item and calls IndexOf
with wrong value:
internal ItemsControl.ItemInfo LeaseItemInfo(ItemsControl.ItemInfo info, bool ensureIndex = false)
{
if (info.Index < 0)
{
info = this.NewItemInfo(info.Item, (DependencyObject) null, -1);
if (ensureIndex && info.Index < 0)
info.Index = this.Items.IndexOf(info.Item);
}
return info;
}
But this should break ScrollIntoView
for all the cases when containers were not generated. The simple workaround is to call ScrollIntoView
via Dispatcher.BeginInvoke
I'll wait for the answer of MS.