Search code examples
wpfdatagridscrollview

WPF DataGrid ScrollIntoView doesn't scroll to requested row


I am using WPF DataGrid which has ~50 rows. I am using MVVM pattern. User can search for some text in a row and datagrid should highlight the row (not necessarily select the row) and scroll to that row if that row is not visible on screen yet.

Trimmed XAML code:

<DataGrid ItemsSource="{Binding MyDataView,Mode=TwoWay}" Name="myDataGrid"
          AutoGeneratingColumn="Generate_Column" 
          CurrentCell="{Binding DGCurrentCell, Mode=OneWayToSource}" SelectedItem="{Binding SelectedRow, Mode=TwoWay}"
          HorizontalScrollBarVisibility="Disabled" VirtualizingPanel.ScrollUnit="Item"
          VirtualizingStackPanel.VirtualizationMode="Recycling" VirtualizingStackPanel.IsVirtualizing="False"
          IsSynchronizedWithCurrentItem="True">

Code Behind:

public void ScrollToItem(object gridObj, object item)
{
    myDataGrid.Dispatcher.BeginInvoke((Action)(() =>
    {
        myDataGrid.Focus();
        myDataGrid.UpdateLayout();
        myDataGrid.ScrollIntoView(item);
    }));
}

ViewModel:

    protected override bool FindItem(string searchString)
    {
        bool itemFound=false;
        DataRow[] rows = this.MyDataTable.Select(searchString);
        if (rows.Count() > 0)
        {
            itemFound = true;
            //Scroll to the first row which is a match
            (this.View as SCDataGridView).ScrollToItem(this, rows[0]);
        }
        return itemFound;
    }

ScrollToItem API is called if item is found, but scrollviewer never scrolls to that item. I tried various combinations for the following fields but nothing has helped me so far:

HorizontalScrollBarVisibility- Auto or Disabled
VirtualizingPanel.ScrollUnit- Pixel or Item
VirtualizingStackPanel.VirtualizationMode- Standard or Recycling
VirtualizingStackPanel.IsVirtualizing - True or False

What am I missing?

Thanks,

RDV


Solution

  • I found the issue why ScrollIntoView didnt work for me. ScrollIntoView requires the exact object type bound to ItemsSource. In my case ItemsSource was bound to MyDataView and every item was of type DataRowView. When calling ScrollIntoView, i was passing DataRow object and hence it was not working.

    Once I passed correct DataRowView object, it worked. I didnt have to set the SelectedItem to this item (as I didnt want to select the item, just scroll to the searched item). Following is the working sample - I didnt have to call UpdateLayout() or beginInvoke

    public void ScrollToItem(object gridObj, int itemIdx)
    {
        myDataGrid.ScrollIntoView((this.DataContext).MyDataView[itemIdx], null);
    }
    

    Another important thing i realized while debugging this is that to set Virtualization on or off on a DataGrid/List etc., one should use ScrollViewer.CanScrollContent instead of VirtualizingPanel.ScrollUnit property as ScrollViewer.CanScrollContent is passed to scrollviewer which is actually responsible for implementing virtualization.

    Again, true/false value of ScrollViewer.CanScrollContent has no impact on ScrollIntoView functioning.

    Hope this helps someone.

    RDV