Hi All,
I use the DataGrid from .Net Framework 4.5 with row and column virtualization enabled. If I select an item in the DataGrid, add grouping using the DataGrid GroupStyle property and then execute a ScrollIntoView for the selected item, the selected item is not brought into view. I need the selected item to be brought into view programatically after adding the grouping without any interaction from the user.
Steps to reproduce:
- compile the code provided and start the application
- select the item with FirstName equal to "FirstName0000000030"
- press button "Add group"
- groups appear but the selected item is not brought into view
Notes:
- the issue does not reproduce for all items in the grid (for some it does, for some it doesn't). On my machine it allways reproduces with the item "FirstName0000000030". If it does not reproduce please try also with other items.
- pressing the button "Scroll to selection" multiple times after the "Add group" is pressed it finally bring the selected element into view (this is not a desireable solution for us because it involve user interaction from the user)
XAML:
<Window x:Class="ScrollIntoViewBug.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local ="clr-namespace:ScrollIntoViewBug" Title="ScrollIntoView" WindowState="Maximized" Loaded="Window_Loaded"><Window.Resources><GroupStyle x:Key="GroupHeaderStyle"><GroupStyle.Panel><ItemsPanelTemplate><VirtualizingStackPanel Orientation="Vertical" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Standard"/></ItemsPanelTemplate></GroupStyle.Panel><GroupStyle.ContainerStyle><Style TargetType="{x:Type GroupItem}"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type GroupItem}"><Expander Name="groupExpander" IsExpanded="True"><Expander.Header><StackPanel Orientation="Horizontal"><TextBlock Text="{Binding Path=ItemCount}"/><TextBlock Text="Items"/></StackPanel></Expander.Header><ItemsPresenter></ItemsPresenter></Expander></ControlTemplate></Setter.Value></Setter></Style></GroupStyle.ContainerStyle></GroupStyle></Window.Resources><Grid><Grid.ColumnDefinitions><ColumnDefinition Width="*"></ColumnDefinition></Grid.ColumnDefinitions><Grid.RowDefinitions><RowDefinition Height="30"></RowDefinition><RowDefinition Height="*"></RowDefinition></Grid.RowDefinitions><StackPanel Grid.Row="0" Grid.Column="0" Orientation="Horizontal"><Button Name="btnAddGrouping" Click="btnAddGrouping_Click" Margin="0,3,3,3">Add group</Button><Button Name="btnClearGrouping" Click="btnClearGrouping_Click" Margin="3">Clear group</Button><Button Name="btnScrollIntoView" Click="btnScrollIntoView_Click" Margin="3">Scroll to selection</Button></StackPanel><DataGrid Name="MyDataGrid" Grid.Row="1" Grid.Column="0" EnableRowVirtualization="True" EnableColumnVirtualization="True" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingPanel.IsVirtualizingWhenGrouping="True" VirtualizingPanel.VirtualizationMode="Standard"></DataGrid></Grid></Window>
Code behind:
namespace ScrollIntoViewBug { public enum Gender { Male, Female }; public class Customer { public string FirstName { get; set; } public string LastName { get; set; } public Gender Gender { get; set; } public string Department { get; set; } } public partial class MainWindow : Window { CollectionViewSource cvSource; public MainWindow() { InitializeComponent(); } private List<Customer> createRows() { System.Int64 rowNo = 100; System.Int64 noOfGroups = 80; // generate rows List<Customer> customers = new List<Customer>(); for (System.Int64 i = 0; i < rowNo; i++) { Gender gender; if (i % 2 == 0) gender = Gender.Male; else gender = Gender.Female; string deparment = "Dept" + (i % noOfGroups + 1).ToString("D10"); customers.Add(new Customer() { FirstName = "FirstName" + (i + 1).ToString("D10"), LastName = "LastName" + i.ToString("D10"), Gender = gender, Department = deparment }); } return customers; } private ObservableCollection<DataGridColumn> createColumns() { System.Int64 colNo = 100; // generate columns ObservableCollection<DataGridColumn> columns = new ObservableCollection<DataGridColumn>(); DataGridTextColumn textColumn = new DataGridTextColumn(); textColumn.Header = "First Name"; textColumn.Binding = new Binding("FirstName"); columns.Add(textColumn); DataGridComboBoxColumn comboColumn = new DataGridComboBoxColumn(); comboColumn.Header = "Gender"; comboColumn.TextBinding = new Binding("Gender"); comboColumn.ItemsSource = typeof(Gender).GetEnumValues(); columns.Add(comboColumn); DataGridTextColumn depColumn = new DataGridTextColumn(); depColumn.Header = "Department"; depColumn.Binding = new Binding("Department"); columns.Add(depColumn); for (System.Int64 i = 2; i < colNo; i++) { textColumn = new DataGridTextColumn(); textColumn.Header = "Last Name" + (i + 1).ToString("D10"); textColumn.Binding = new Binding("LastName"); columns.Add(textColumn); } return columns; } private void loadGridData() { // add columns ObservableCollection<DataGridColumn> columns = createColumns(); foreach (DataGridColumn col in columns) MyDataGrid.Columns.Add(col); // add rows cvSource = new CollectionViewSource(); cvSource.Source = createRows(); // set datagrid items Binding itemsSourceBinding = new Binding(); itemsSourceBinding.Source = cvSource; MyDataGrid.SetBinding(DataGrid.ItemsSourceProperty, itemsSourceBinding); } private void Window_Loaded(object sender, RoutedEventArgs e) { loadGridData(); } private void btnAddGrouping_Click(object sender, RoutedEventArgs e) { ICollectionView view = CollectionViewSource.GetDefaultView(MyDataGrid.ItemsSource); if (view == null) return; view.GroupDescriptions.Add(new PropertyGroupDescription("Department")); if (MyDataGrid.GroupStyle == null || MyDataGrid.GroupStyle.Count == 0) { GroupStyle groupStyle = TryFindResource("GroupHeaderStyle") as GroupStyle; if (groupStyle != null) { if (groupStyle.ContainerStyle != null) groupStyle.ContainerStyle.Seal(); MyDataGrid.GroupStyle.Add(groupStyle); } } ScrollToSelection(); } private void ScrollToSelection() { MyDataGrid.Focus(); MyDataGrid.Items.MoveCurrentTo(MyDataGrid.SelectedItem); MyDataGrid.ScrollIntoView(MyDataGrid.SelectedItem); } private void btnClearGrouping_Click(object sender, RoutedEventArgs e) { ICollectionView view = CollectionViewSource.GetDefaultView(MyDataGrid.ItemsSource); if (view == null) return; view.GroupDescriptions.Clear(); ScrollToSelection(); } private void btnScrollIntoView_Click(object sender, RoutedEventArgs e) { ScrollToSelection(); } } }
Do I use correctly the ScrollIntoView in the code example?
Is there a way to programmaticaly scroll to the selected item imediatly after adding the grouping?
Is this a bug in the DataGrid from .Net Framework 4.5 related to ScrollIntoView?