Hi,
I'm using the grid to bind to an ICollectionView. I've added a behaviour on the grid so that it binds to the CurrentItem.When the CurrentItem changes, it will select the corresponding row and call ScrollIIntoView on it. Vice-versa selecting a row calls MoveCurrentTo() on the ICollectionView.
I've used that in some other part of the application and it works great. However, on this new grid I do the following operations (the grid uses TemplateColumns):
- _myCollectionView.Clear();
- var savedPosition = _myCollectionView.CurrentPosition;
- foreach(...) { _myCollectionView.Add(myObject); }
- _myCollectionView.MoveCurrentToPosition(savedPosition);
Unfortunately the current item is selected (the row is coloured), but it's not brought into view.
Now if I replace the last instruction by:
- SynchronizationContext.Current.Post((o) => _myCollectionView.MoveCurrentToPosition(savedPosition));
Then it brings the current item to view.
Am I doing something wrong or is this a bug of the grid?
PS: If I can I'll try to create a test project.
Cheers.
Could you post the code that you are calling to scroll the row into view?
Could you also provide information about your rows / columns / layouts - are there column layouts, etc.
Thanks,
Thanks for the quick reply. Here's a copy/paste of the grid itself from production code
<igGrid:XamWebGrid VerticalAlignment="Stretch" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" ItemsSource="{Binding ReferencePoints}" Behaviors:XamWebGridCurrentItemBindingBehavior.CurrentCollectionView="{Binding ReferencePoints}" UseLayoutRounding="True" AutoGenerateColumns="False" CellStyle="{StaticResource CellControlStyleForColouredRows}" IsAlternateRowsEnabled="True" RowHover="Row" ColumnLayoutHeaderVisibility="Never" RowHeight="Dynamic" ColumnWidth="*" HeaderVisibility="Visible" > <igGrid:XamWebGrid.AddNewRowSettings> <igGrid:AddNewRowSettings AllowAddNewRow="None" /> </igGrid:XamWebGrid.AddNewRowSettings> <igGrid:XamWebGrid.RowSelectorSettings> <igGrid:RowSelectorSettings EnableRowNumbering="False" /> </igGrid:XamWebGrid.RowSelectorSettings> <igGrid:XamWebGrid.SortingSettings> <igGrid:SortingSettings AllowMultipleColumnSorting="True" AllowSorting="True" ShowSortIndicator="True" /> </igGrid:XamWebGrid.SortingSettings> <igGrid:XamWebGrid.SelectionSettings> <igGrid:SelectionSettings CellClickAction="SelectRow" CellSelection="None" ColumnSelection="None" RowSelection="Single" /> </igGrid:XamWebGrid.SelectionSettings> <igGrid:XamWebGrid.ColumnResizingSettings> <igGrid:ColumnResizingSettings AllowDoubleClickToSize="True" AllowColumnResizing="Immediate" /> </igGrid:XamWebGrid.ColumnResizingSettings> <igGrid:XamWebGrid.Columns> <igGrid:TemplateColumn Key="EditButton" IsReadOnly="True" IsResizable="False" Width="SizeToCells" IsSortable="False" MinimumWidth="5" HeaderStyle="{StaticResource HeaderCellControlStyleForNoSorting}"> <igGrid:TemplateColumn.ItemTemplate> <DataTemplate> <Button Command:Click.Command="{Binding Path=Value, Source={StaticResource EditSymbolCommand}}" Command:Click.CommandParameter="{Binding }" Behaviors:ToolTipBindingBehavior.ToolTipContent="{Binding Resource.ReferencePointEditSymbol, Source={StaticResource LocalizedStrings}}" Margin="0" Padding="3,0,3,0" > <Image Source="{Binding Configuration, Source={StaticResource ImagesPath}}" VerticalAlignment="Center" HorizontalAlignment="Center" Width="12" Stretch="Uniform"/> </Button> </DataTemplate> </igGrid:TemplateColumn.ItemTemplate> <igGrid:TemplateColumn.HeaderTemplate> <DataTemplate> <Image Source="{Binding Configuration, Source={StaticResource ImagesPath}}" VerticalAlignment="Center" HorizontalAlignment="Center" Width="12" Stretch="Uniform"/> </DataTemplate> </igGrid:TemplateColumn.HeaderTemplate> </igGrid:TemplateColumn> <igGrid:TemplateColumn Key="RenameButton" IsReadOnly="True" IsResizable="False" Width="SizeToCells" IsSortable="False" MinimumWidth="5" HeaderStyle="{StaticResource HeaderCellControlStyleForNoSorting}"> <igGrid:TemplateColumn.ItemTemplate> <DataTemplate> <Button Command:Click.Command="{Binding Path=Value, Source={StaticResource RenameCommand}}" Command:Click.CommandParameter="{Binding }" Behaviors:ToolTipBindingBehavior.ToolTipContent="{Binding Resource.ReferencePointRename, Source={StaticResource LocalizedStrings}}" Margin="0" Padding="3,0,3,0" > <Image Source="{Binding GroupRename, Source={StaticResource ImagesPath}}" VerticalAlignment="Center" HorizontalAlignment="Center" Width="12" Stretch="Uniform"/> </Button> </DataTemplate> </igGrid:TemplateColumn.ItemTemplate> <igGrid:TemplateColumn.HeaderTemplate> <DataTemplate> <Image Source="{Binding GroupRename, Source={StaticResource ImagesPath}}" VerticalAlignment="Center" HorizontalAlignment="Center" Width="12" Stretch="Uniform"/> </DataTemplate> </igGrid:TemplateColumn.HeaderTemplate> </igGrid:TemplateColumn> <igGrid:TemplateColumn Key="DeleteButton" IsReadOnly="True" IsResizable="False" Width="SizeToCells" IsSortable="False" MinimumWidth="5" HeaderStyle="{StaticResource HeaderCellControlStyleForNoSorting}"> <igGrid:TemplateColumn.ItemTemplate> <DataTemplate> <Button Command:Click.Command="{Binding Path=Value, Source={StaticResource DeleteCommand}}" Command:Click.CommandParameter="{Binding }" Behaviors:ToolTipBindingBehavior.ToolTipContent="{Binding Resource.DeleteReferencePoint, Source={StaticResource LocalizedStrings}}" Margin="8,0,0,0" Padding="3,0,3,0" > <Image Source="{Binding Delete, Source={StaticResource ImagesPath}}" VerticalAlignment="Center" HorizontalAlignment="Center" Width="12" Stretch="Uniform"/> </Button> </DataTemplate> </igGrid:TemplateColumn.ItemTemplate> <igGrid:TemplateColumn.HeaderTemplate> <DataTemplate> <Image Source="{Binding Delete, Source={StaticResource ImagesPath}}" VerticalAlignment="Center" HorizontalAlignment="Center" Width="12" Stretch="Uniform"/> </DataTemplate> </igGrid:TemplateColumn.HeaderTemplate> </igGrid:TemplateColumn> <igGrid:TemplateColumn Key="SymbolAddress" Width="SizeToCells" VerticalContentAlignment="Center" HorizontalContentAlignment="Center"> <igGrid:TemplateColumn.ItemTemplate> <DataTemplate> <Image Source="{Binding SymbolAddress}" Stretch="None" Margin="5,0,5,0" /> </DataTemplate> </igGrid:TemplateColumn.ItemTemplate> <igGrid:TemplateColumn.HeaderTemplate> <DataTemplate> <TextBlock Text="{Binding Resource.ReferencePointHeaderSymbol, Source={StaticResource LocalizedStrings}}" /> </DataTemplate> </igGrid:TemplateColumn.HeaderTemplate> </igGrid:TemplateColumn> <igGrid:TextColumn Key="Name" Width="SizeToCells"> <igGrid:TextColumn.HeaderTemplate> <DataTemplate> <TextBlock Text="{Binding Resource.ReferencePointHeaderName, Source={StaticResource LocalizedStrings}}" /> </DataTemplate> </igGrid:TextColumn.HeaderTemplate> </igGrid:TextColumn> <igGrid:TemplateColumn Key="Filler" IsReadOnly="True" IsResizable="False" Width="*" HeaderText=" "> <igGrid:TemplateColumn.ItemTemplate> <DataTemplate> <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> </Grid> </DataTemplate> </igGrid:TemplateColumn.ItemTemplate> </igGrid:TemplateColumn> </igGrid:XamWebGrid.Columns> </igGrid:XamWebGrid>
Here's a copy/paste of the behaviour that keeps the current row in synch with the current item:
public static class XamWebGridCurrentItemBindingBehavior { public static readonly DependencyProperty CurrentCollectionViewProperty = DependencyProperty.RegisterAttached("CurrentCollectionView", typeof(ICollectionView), typeof(XamWebGridCurrentItemBindingBehavior), new PropertyMetadata(OnCurrentCollectionViewSetCallback)); public static ICollectionView GetCurrentCollectionView(DependencyObject obj) { return (ICollectionView)obj.GetValue(CurrentCollectionViewProperty); } public static void SetCurrentCollectionView(DependencyObject obj, ICollectionView value) { obj.SetValue(CurrentCollectionViewProperty, value); } private static void OnSelectedRowsCollectionChanged(object sender, SelectionCollectionChangedEventArgs<SelectedRowsCollection> e) { var grid = (DependencyObject)sender; var collectionView = GetCurrentCollectionView(grid); if (collectionView != null && e.NewSelectedItems.Count > 0) { collectionView.MoveCurrentTo(e.NewSelectedItems[0].Data); } } private static void OnActiveCellChanging(object sender, ActiveCellChangingEventArgs e) { e.Cancel = true; } private static void OnCurrentChanged(XamWebGrid grid) { var collectionView = GetCurrentCollectionView(grid); if (collectionView != null) { if (collectionView.CurrentItem == null) { grid.SelectionSettings.SelectedRows.Clear(); } else { Row rowToSelect = grid.Rows.FirstOrDefault(r => r.Data == collectionView.CurrentItem); if (rowToSelect == null) { grid.SelectionSettings.SelectedRows.Clear(); } else { if (grid.SelectionSettings.SelectedRows.Count != 1 || ( grid.SelectionSettings.SelectedRows.Count == 1 && grid.SelectionSettings.SelectedRows[0] != rowToSelect ) ) { rowToSelect.IsSelected = true; grid.ScrollCellIntoView(rowToSelect.Cells[0]); } } } } } private static void OnCurrentCollectionViewSetCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) { var oldCollection = (ICollectionView)e.OldValue; var newCollection = (ICollectionView)e.NewValue; var grid = (XamWebGrid)d; if (oldCollection != null) { oldCollection.CurrentChanged -= (o, ev) => OnCurrentChanged(grid); } if (newCollection != null) { newCollection.CurrentChanged += (o, ev) => OnCurrentChanged(grid); } grid.SelectedRowsCollectionChanged -= OnSelectedRowsCollectionChanged; grid.ActiveCellChanging -= OnActiveCellChanging; grid.SelectedRowsCollectionChanged += OnSelectedRowsCollectionChanged; grid.ActiveCellChanging += OnActiveCellChanging; } }
And in my code what I do on an update is:
var savedPosition = _referencePoints.CurrentPosition; using (_referencePoints.DeferRefresh()) { _referencePoints.Clear(); foreach (var referencePoint in referencePoints) { _referencePoints.Add(new ReferencePointWithAddress(referencePoint, _profileAddressHelperService, _profileService)); } } if (savedPosition < _referencePoints.Count) { SynchronizationContext.Current.Post((o) => _referencePoints.MoveCurrentToPosition(savedPosition), null); }
It is really not that easy to replicate the problem in my environment, considering the complex configuration you have.
There are some known issues / limitations with the ScrollCellIntoView, but your case does not seem similar.
Could you just try delaying a bit the call to the ScrollCellIntoView, e.g. by calling grid.Dispatcher.BeginInvoke(() => { grid.ScrollCellIntoView(rowToSelect.Cells[0]);});
or by using a DispatcherTimer:
DispatcherTimer t = new DispatcherTimer() { Interval = new TimeSpan(0, 0, 1) };
t.Tick += (s, e2) =>
{
grid.ScrollCellIntoView(rowToSelect.Cells[0]);
};
just to see if that will have some effect on the issue.
As I said in my initial post, that's what I'm doing currently and it kind of makes the problem go away.
I use the SynchronizationContext class because my code is on the ViewModel side and doesn't have a Dispatcher handy.
I say "kind of" because it happens that the current cell is just barely visible at the bottom (while it should be the last fully visible row).
We've seen similar issue in other scenarios with the ScrollCellIntoView, so this might be caused by the same bug - we have opened a bug item for it to track it internally.
Regards,