none
Programmatically Scroll WPF DataGrid

    Question

  •  It seems I can not programmatically scroll the DataGrid control included in the 2008 WPF toolkit.  I basically want to scroll to the bottom everytime an item is added to the itemssource. Does anyone know how to do this?  Is this a bug?


    FYI, I am using this control only to display items, there is a seperate control to add items to the itemssource. 
    Eric Kaufman
    Friday, September 19, 2008 3:23 PM

Answers

  • In your ButtonClick method right before calling DataGrid.ScrollIntoView, call DataGrid.UpdateLayout().
    • Marked as answer by Eric Kaufman Tuesday, September 23, 2008 1:59 PM
    Tuesday, September 23, 2008 12:15 PM

All replies

  • Have you tried DataGrid.ScrollIntoView method?

    http://msdn.microsoft.com/en-us/library/system.windows.controls.datagrid.scrollintoview(VS.95).aspx
    Bigsby, Lisboa, Portugal
    Friday, September 19, 2008 3:48 PM
  • In addition to ScrollIntoView, you also have a ScrollViewer visual.  DataGrid is similar to a ListView in the sense that the control template is built with a ScrollViewer.  You can get a reference to the ScrollViewer directly from the DataGrid visual tree.  With the ScrollViewer you can programmatically scroll to the bottom.  Of course, ScrollIntoView is a lot more straighforward to use.
    Saturday, September 20, 2008 1:52 AM
  • When using DataGrid.ScrollIntoView I always get this error:

    Object reference not set to an instance of an object.

    System.NullReferenceException: Object reference not set to an instance of an object.
       at System.Windows.Controls.VirtualizingStackPanel.InsertContainer(Int32 childIndex, UIElement container, Boolean isRecycled)
       at System.Windows.Controls.VirtualizingStackPanel.AddContainerFromGenerator(Int32 childIndex, UIElement child, Boolean newlyRealized)
       at System.Windows.Controls.VirtualizingStackPanel.BringIndexIntoView(Int32 index)
       at Microsoft.Windows.Controls.DataGridRowsPresenter.InternalBringIndexIntoView(Int32 index)
       at Microsoft.Windows.Controls.DataGrid.ScrollRowIntoView(Object item)
       at Microsoft.Windows.Controls.DataGrid.ScrollIntoView(Object item)
       at ....SaveButton_Click(Object sender, RoutedEventArgs e) in ...


    Here is the line the code is erroring out at:

    dgDataGrid.ScrollIntoView(dgDataGrid.Items(dgDataGrid.Items.Count - 1))

    I have also tried referencing the list directly:

    dgDataGrid.ScrollIntoView(dataGridItemSource.Items(dataGridItemSource.Items.Count - 1))

    I have also tried passing the first column as the second parameter, to no avail.  Also, I am binding to IList of an NHibernate object.    Any suggestions? 


    Eric Kaufman
    • Edited by Eric Kaufman Sunday, September 21, 2008 11:09 PM
    Sunday, September 21, 2008 11:08 PM
  • If you get a NullReferenceException is because, at least, one of the objects in that line doesn't exist or might not have been instanciate yet.

    If you debug that line you might see wich one of them it is and, only then, start thinking about why.
    Bigsby, Lisboa, Portugal
    Sunday, September 21, 2008 11:12 PM
  • If you get a NullReferenceException is because, at least, one of the objects in that line doesn't exist or might not have been instanciate yet.

    If you debug that line you might see wich one of them it is and, only then, start thinking about why.
    Bigsby, Lisboa, Portugal
    • Proposed as answer by Jim Zhou - MSFT Tuesday, September 23, 2008 6:42 AM
    Sunday, September 21, 2008 11:12 PM
  • Thanks for the quick reply! Yes, it is odd. When I add dataGridItemSource.Items(dataGridItemSource.Items.Count - 1) to my watch I do get an object.
    So, it has been instantiated and is an in the collection.  I will try and replicate the problem in a new project. 
    Eric Kaufman
    Sunday, September 21, 2008 11:18 PM
  • what about the DataGrid?
    Bigsby, Lisboa, Portugal
    Sunday, September 21, 2008 11:20 PM
  •  The datagrid is also instantiated and shows no errors when debugging.
    Eric Kaufman
    Sunday, September 21, 2008 11:24 PM
  • Duplicating it is, then.
    Bigsby, Lisboa, Portugal
    Sunday, September 21, 2008 11:26 PM
  • Duplicating it is, then.
    Bigsby, Lisboa, Portugal
    Sunday, September 21, 2008 11:26 PM
  • Here is some code where issue is replicated:

    Imports System.ComponentModel

    Class Window1
        Private myDataGridItemsSource As List(Of MyItem) = New List(Of MyItem)

        Public Property DataGridItemsSource() As List(Of MyItem)
            Get
                Return myDataGridItemsSource
            End Get
            Set(ByVal value As List(Of MyItem))
                myDataGridItemsSource = value
            End Set
        End Property

        Public Sub New()

            PopulateItemsSource()
            Me.DataContext = Me

            ' This call is required by the Windows Form Designer.
            InitializeComponent()

            ' Add any initialization after the InitializeComponent() call.
        End Sub

        Private Sub PopulateItemsSource()
            For i As Integer = 0 To 11 Step 3
                Dim item As New MyItem With {.Value1 = i, .Value2 = i + 1, .Value3 = i + 2}
                DataGridItemsSource.Add(item)
            Next
        End Sub


        Private Sub Button_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
            Try
                Dim item As New MyItem With {.Value1 = txt1.Text, .Value2 = txt2.Text, .Value3 = txt3.Text}
                DataGridItemsSource.Add(item)
                dgDataGrid.Items.Refresh()
                dgDataGrid.ScrollIntoView(dgDataGrid.Items(dgDataGrid.Items.Count - 1))
            Catch ex As Exception
                MessageBox.Show(ex.ToString)
            End Try
        End Sub

    End Class

    <Window x:Class="Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:dg="http://schemas.microsoft.com/wpf/2008/toolkit"
        Title="Window1" Height="314.413" Width="608.828">
        <Window.Resources>
            <DataTemplate x:Key="Value1">
                <TextBlock Text="{Binding Value1}" FontSize="14" VerticalAlignment="Center" TextTrimming="CharacterEllipsis"  TextWrapping="WrapWithOverflow"/>
            </DataTemplate>
            <DataTemplate x:Key="Value2">
                <TextBlock Text="{Binding Value2}" FontSize="14"  VerticalAlignment="Center" TextTrimming="CharacterEllipsis" TextWrapping="WrapWithOverflow"/>
            </DataTemplate>
            <DataTemplate x:Key="Value3">
                <TextBlock Text="{Binding Value3}" FontSize="14"  VerticalAlignment="Center" TextTrimming="CharacterEllipsis" TextWrapping="WrapWithOverflow"/>
            </DataTemplate>

            <SolidColorBrush x:Key="DataGrid_Style0_Header" Color="#FF4F81BD"/>
            <SolidColorBrush x:Key="DataGrid_Style0_Alt0" Color="White"/>
            <SolidColorBrush x:Key="DataGrid_Style0_Alt1" Color="#FFE7EFFF"/>
            <Style x:Key="ColumnHeaderStyle" TargetType="{x:Type dg:DataGridColumnHeader}"
                       BasedOn="{StaticResource {x:Type dg:DataGridColumnHeader}}">
                <Setter Property="Background" Value="{StaticResource DataGrid_Style0_Header}" />
                <Setter Property="Foreground" Value="White" />
                <Setter Property="BorderThickness" Value="1"/>
                <Setter Property="BorderBrush" Value="LightGray"/>
                <Setter Property="HorizontalContentAlignment" Value="Center" />
            </Style>

            <!--this is the style for the selected row-->
            <Style x:Key="CellStyle" TargetType="{x:Type dg:DataGridCell}">
                <Style.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter Property="Background" Value="LightBlue" />
                        <Setter Property ="Foreground" Value ="Black" />
                    </Trigger>
                </Style.Triggers>
            </Style>

            <Style x:Key="RowStyle" TargetType="dg:DataGridRow" >
                <Style.Triggers>
                    <Trigger Property="AlternationIndex" Value="1" >
                        <Setter Property="Background" Value="{StaticResource DataGrid_Style0_Alt1}" />
                    </Trigger>
                    <Trigger Property="AlternationIndex" Value="0" >
                        <Setter Property="Background" Value="{StaticResource DataGrid_Style0_Alt0}" />
                    </Trigger>
                    <Trigger Property ="IsMouseOver" Value ="True" >
                        <Setter Property ="Background" Value ="LightYellow" />
                        <Setter Property ="Foreground" Value ="Black" />
                    </Trigger>
                </Style.Triggers>
            </Style>

        </Window.Resources>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="auto"/>
            </Grid.RowDefinitions>
            <dg:DataGrid Grid.Column="0" HorizontalAlignment="Stretch" ItemsSource="{Binding DataGridItemsSource}" AlternationCount="2" RowStyle="{StaticResource RowStyle}"
              x:Name="dgDataGrid" CanUserReorderColumns="False" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible"
              ColumnHeaderHeight="30" FontSize="16" HeadersVisibility="Column" MinColumnWidth="60" VerticalGridLinesBrush="Transparent"
              AutoGenerateColumns="False" RowHeight="30" CanUserSortColumns="True" SelectionMode="Single" IsEnabled="True" SelectionUnit="FullRow"  CanUserResizeColumns="False" CanUserAddRows="False"
              >
                <dg:DataGrid.Columns>
                    <dg:DataGridTemplateColumn Header="Value1" CellTemplate="{StaticResource Value1}" Width="150" SortMemberPath="Value1" />
                    <dg:DataGridTemplateColumn Header="Value2" CellTemplate="{StaticResource Value2}" Width="150" SortMemberPath="Value2" />
                    <dg:DataGridTemplateColumn Header="Value3" CellTemplate="{StaticResource Value3}" Width="*" SortMemberPath="Value3" />
                </dg:DataGrid.Columns>
            </dg:DataGrid>

            <!--Row 1 GridSplitter-->
            <GridSplitter Grid.Row="1" HorizontalAlignment="Stretch" Margin="5,0,5,0" />
           
            <!--Row 2 Input Controls-->
            <Grid Grid.Row="2">
                <Grid.RowDefinitions>
                    <RowDefinition/>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>

                <Grid  Margin="5" >
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="auto"/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="Value1: "/>
                    <TextBox Grid.Column="1" HorizontalAlignment="Stretch" Name="txt1"/>
                </Grid>

                <Grid Grid.Column="1" Margin="5" >
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="auto"/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="Value2: "/>
                    <TextBox Grid.Column="1" HorizontalAlignment="Stretch" Name="txt2"/>
                </Grid>

                <Grid Grid.Column="2" Margin="5" >
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="auto"/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="Value3: "/>
                    <TextBox Grid.Column="1" HorizontalAlignment="Stretch" Name="txt3"/>
                </Grid>

                <Button Grid.Row="1" Grid.Column="2" Content="Add Item" Margin="5" Click="Button_Click"/>
               
            </Grid>
        </Grid>
    </Window>


     


    Eric Kaufman
    Sunday, September 21, 2008 11:59 PM
  • If I cannot achieve this with ScrollIntoView. Does anyone have an example of accessing the Scroll Viewer to scroll to a particular item?  Also I would settle with scrolling to the bottom every time. 
    Eric Kaufman
    Monday, September 22, 2008 8:10 PM
  • In your ButtonClick method right before calling DataGrid.ScrollIntoView, call DataGrid.UpdateLayout().
    • Marked as answer by Eric Kaufman Tuesday, September 23, 2008 1:59 PM
    Tuesday, September 23, 2008 12:15 PM
  • That worked! Thank you!
    Eric Kaufman
    Tuesday, September 23, 2008 2:00 PM
  • When using DataGrid.ScrollIntoView I always get this error:

    Object reference not set to an instance of an object.

    System.NullReferenceException: Object reference not set to an instance of an object.
       at System.Windows.Controls.VirtualizingStackPanel.InsertContainer(Int32 childIndex, UIElement container, Boolean isRecycled)
       at System.Windows.Controls.VirtualizingStackPanel.AddContainerFromGenerator(Int32 childIndex, UIElement child, Boolean newlyRealized)
       at System.Windows.Controls.VirtualizingStackPanel.BringIndexIntoView(Int32 index)
       at Microsoft.Windows.Controls.DataGridRowsPresenter.InternalBringIndexIntoView(Int32 index)
       at Microsoft.Windows.Controls.DataGrid.ScrollRowIntoView(Object item)
       at Microsoft.Windows.Controls.DataGrid.ScrollIntoView(Object item)
       at ....SaveButton_Click(Object sender, RoutedEventArgs e) in ...


    Here is the line the code is erroring out at:

    dgDataGrid.ScrollIntoView(dgDataGrid.Items(dgDataGrid.Items.Count - 1))

    I have also tried referencing the list directly:

    dgDataGrid.ScrollIntoView(dataGridItemSource.Items(dataGridItemSource.Items.Count - 1))

    I have also tried passing the first column as the second parameter, to no avail.  Also, I am binding to IList of an NHibernate object.    Any suggestions? 


    Eric Kaufman

    Me too facing the same issue.
    I'm trying - 
    senderDataGrid.ScrollIntoView(senderDataGrid.CurrentItem, senderDataGrid.Columns[0]); 

    Fixed by -

    senderDataGrid.UpdateLayout();
    senderDataGrid.ScrollIntoView(senderDataGrid.CurrentItem, senderDataGrid.Columns[0]); 

     

    This is an issue in February 2010 WPF toolkit. This issue is not reproducible with June 2009 WPF Toolkit
    Friday, April 01, 2011 6:05 AM