Michael
Michael

Reputation: 11

Maintain scroll position on updating the ItemSource of a silverlight datagrid

I'm using a DataGrid in my silverlight application to display some data that's refreshed on a timer. My problem is that when this happens the vertical scrollbar in the grid resets to the top, whereas I want it to stay in the same position. Does anyone know how I can make this happen?

I've tried overriding the ItemsSource property on the grid to store the vertical scroll position and then reset it, but this only affects the scrollbar and doesn't force the correct rows to be displayed. Is there a way to force this behaviour?

Upvotes: 1

Views: 10799

Answers (5)

kukabuka
kukabuka

Reputation: 91

I've modified CodeMaster's solution so that you don't need a class level variable. Put this code in the method that updates the ItemsSource. It will dynamically create the eventhandler, attach it, then detach it.

EventHandler MyDataGrid_LayoutUpdated = null;

MyDataGrid_LayoutUpdated = (s, e) =>
    {
        MyDataGrid.ScrollIntoView(dataItem, MyDataGrid.Columns[0]);
        MyDataGrid.LayoutUpdated -= MyDataGrid_LayoutUpdated;
    };

MyDataGrid.LayoutUpdated += MyDataGrid_LayoutUpdated;

Upvotes: 0

R4cOOn
R4cOOn

Reputation: 2575

I couldn't find a decent answer last time I looked. I wanted to keep the current element selected in the grid but that wouldn't work on an ICollectionView refresh (I use MVVM and get automatic updates from the server).

ScrollIntoView() was not an option for me because the currently selected item may NOT be in view. Having the CurrentChanged event firing out of control was also quite a bother.

In the end, I used the Infragistics grid and it does just that out of the box. Problem solved for me.

You may have a look at the DevExpress free grid. I think it had the same nice behaviour (I tested it but I can't remember the outcome).

Upvotes: 1

user227181
user227181

Reputation:

I've also had issues with this. I solved it by remembering the item I want to scroll to, then re-binding the DataGrid. I handle the LayoutUpdated event in order to implement the desired functionality:

void MyDataGrid_LayoutUpdated(object sender, EventArgs e)
    {
        // Reference the data item in the list you want to scroll to.
        object dataItem = yourDataItem;

        // Make sure the item is not null and didn't already scroll to the item.
        if (dataItem != null && this.dataItemScrolledTo != dataItem)
        {
            // Remember the item scrolled to.
            this.dataItemScrolledTo = dataItem;

            // Scroll datagrid to the desired item.
            MyDataGrid.ScrollIntoView(dataItem, MyDataGrid.Columns[0]);
        }
    }

Upvotes: 0

Jacob Adams
Jacob Adams

Reputation: 3994

Here is a similar question about Setting the scroll bar position on a ListBox

After rebinding Silverlight Listbox control how do you get it listbox to scroll to back to the top?

Since the DataGrid also supports a ScrollIntoView method, you should be able to use a similar technique such as

theDataGrid.ItemsSource = data; 
theDataGrid.UpdateLayout(); 
theDataGrid.ScrollIntoView(theDataGrid.SelectedItem, theDataGrid.Columns[0]);

Upvotes: 2

Neil
Neil

Reputation: 1922

You could try setting the SelectedItem thro the UI thread, so that the UI can refresh itself, like so

private void Button_Click(object sender, RoutedEventArgs e)
    {
        Person p = new Person() { Name="sss",Age=11};  //datagird's itemsSource is Collection<person>
        people.Add(p);
        dg.SelectedItem = p;  //dg is my datagrid name
        Dispatcher.BeginInvoke(() => { dg.SelectedItem = p; });
    }

Im assuming that new rows are loaded thro the ViewModel, so thats why it makes sense to place the BeginInvoke there. Since the ViewModel operations run on a different thread, and just setting the SelectedItem on its own might not work, this has worked for someone else

Upvotes: 0

Related Questions