Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DataGrid VerticalOffset Resets to Zero after ItemsSource Change #2722

Closed
robloo opened this issue Dec 28, 2018 · 14 comments
Closed

DataGrid VerticalOffset Resets to Zero after ItemsSource Change #2722

robloo opened this issue Dec 28, 2018 · 14 comments
Labels
DataGrid 🔠 Issues on DataGrid control feature request 📬 A request for new changes to improve functionality

Comments

@robloo
Copy link
Contributor

robloo commented Dec 28, 2018

I'm submitting a...

  • Bug report (I searched for similar issues and did not find one)

Current behavior

The DataGrid vertical offset and scroll position is reset to zero (the top) every time the ItemsSource is changed in code.

This single issue is preventing the DataGrid from being usable in many app scenarios where data is only displayed and updated in separate interfaces.

More detail:

DataGrid does not support ObservableCollection. Actually if you set ItemsSource to an ObservableCollection the app crashes with NotSupportedException on method DataGridInternals.DataGridDataConnection.NotifyingDataSource_CollectionChanged. What's ironic is they spend the time to connect to the CollectionChanged event only to throw an exception as a 'TODO'. Anyway, without using an ObservableCollection, code must change the ItemsSource to get the DataGrid to update itself programatically (a really common requirement). However, every single time ItemsSource is set the DataGrid resets it's position to the top of the list. No other sanely implemented DataGrid control does this. WPF certainly did not. This is an existing issue carried over from the Silverlight days and there are several discussions about it.

Worse still, all attempted work-arounds fail. It's possible to get the vertical scroll bar from the visual tree and save then restore the Value (offset) after setting the ItemsSource. However, the DataGrid will not refresh itself. It's only connected to the scroll event. There appears to be no way to force an update of the DataGrid after changing the vertical scrollbar offset unless I trick it into thinking the user clicked the scrollbar which uses a restricted capability inputInjectionBrokered. Not a workable solution for the Microsoft Store.

Also don't even mention ScrollIntoView. It simply isn't designed for this case and causes more issues than it solves.

Expected behavior

Scroll position must be maintained when ItemsSource is changed. Better yet, add a method that allows the developer to get/set the first visible DataGridRow (Not the same as ScrollIntoView).

Minimal reproduction of the problem with instructions

Setup a DataGrid and set the ItemsSource. Scroll down in the list of items and then programatically change the ItemsSource again (whether by button or the like). The scroll position will be reset to the top.

Environment

All environments with support for the DataGrid control.

@skendrot
Copy link
Contributor

Resetting the scroll bar to the top is expected when changing the ItemsSource.

The issue isn't that the scrollbar resets, it's that ObservableCollections are not supported. Please update the issue or close this one and open a new issue

@robloo
Copy link
Contributor Author

robloo commented Dec 28, 2018

Resetting the scroll bar to the top is expected when changing the ItemsSource.

I have to disagree. Look at how ListBox works: I can change ItemsSource all day and the scroll bar relative position is maintained as expected. Also, other DataGrid implementations I've seen do not reset the vertical scrollbar position. WPF didn't. Other control libraries don't.

This is an old issue:
https://stackoverflow.com/questions/1839445/maintain-scroll-position-on-updating-the-itemsource-of-a-silverlight-datagrid

@nmetulev
Copy link
Contributor

nmetulev commented Jan 7, 2019

ping @RBrid and @harinikmsft

@nmetulev nmetulev added the DataGrid 🔠 Issues on DataGrid control label Jan 7, 2019
@RBrid RBrid added the feature request 📬 A request for new changes to improve functionality label Jan 8, 2019
@RBrid
Copy link
Contributor

RBrid commented Jan 8, 2019

You meant to say that the NotifyCollectionChangedAction.Replace action is not supported by the DataGrid, right? (Neither is CollectionChange.ItemChanged for IObservableVector).
The actions NotifyCollectionChangedAction.Add, Remove and Reset are supported as far as I know.
Just want to make sure we are on the same page. Thanks.

FYI, one thing I would try, as a workaround, if I were in your place, is use an intermediary INotifyCollectionChange implementation that translates

  • NotifyCollectionChangedAction.Add into the same NotifyCollectionChangedAction.Add.
  • NotifyCollectionChangedAction.Remove into the same NotifyCollectionChangedAction.Remove.
  • NotifyCollectionChangedAction.Reset into NotifyCollectionChangedAction.Reset.
  • NotifyCollectionChangedAction.Replace into two NotifyCollectionChangedAction.Remove + NotifyCollectionChangedAction.Add actions.
    I would use that INotifyCollectionChange implementation as the DataGrid.ItemsSource, and of course its source would be your current DataGrid.ItemsSource.

@robloo
Copy link
Contributor Author

robloo commented Jan 8, 2019

I really don't think you should consider the main point of this report a feature request. As it stands there is no (non-hack) way use the DataGrid and update it's data external to the grid itself without resetting the user's view. That makes it unusable for end users in several cases. I'm not editing content right in the grid -- it's edited remotely. Separately, if the DataGrid doesn't support the replace action and throws an exception... that's a bug more than a feature.

We have to keep two topics separate here.

(1) My original point is that the vertical scroll position is reset to zero (the top) whenever the ItemsSource reference is changed. There is no way to override the scroll position to fix this (a helper method to get/set scroll offsets would be invaluable for many situations; although I realize no one has done this in a DataGrid-type control before). Other list view controls do not reset the vertical scroll position. I would challenge anyone to take a look at the UWP ListBox or WPF DataGrid -- vertical scroll position is maintained when ItemsSource is changed.

(2) In an attempt to workaround the primary issue I tried using an ObservableCollection which I then discovered wasn't supported and threw an exception. I didn't dig into the internals on what the exception was. It could very well be the replace action and that would make some sense. My code was updating any existing rows by index with a replace and then adding/removing rows as necessary to the end of the list/collection (quick an dirty prototype). The code was below (apparently I still have it copy/pasted in a Notepad++ tab)

View Code

if ((tableView.ItemsSource is IList<ViewTableRow>) == false)
{
    tableView.ItemsSource = new ObservableCollection<ViewTableRow>();
}

var existingList = tableView.ItemsSource as IList<ViewTableRow>;
if (state.AccountViewTables[i] != null)
{
    for (int row = 0; row < state.AccountViewTables[i].Rows.Count; row++)
    {
        if (row < existingList.Count)
        {
            // Modify existing row
            existingList[row] = state.AccountViewTables[i].Rows[row];
        }
        else
       {
            // Create a new row
            existingList.Add(state.AccountViewTables[i].Rows[row]);
        }
    }

    // Remove any excess rows
    while (existingList.Count > state.AccountViewTables[i].Rows.Count)
    {
        existingList.RemoveAt(existingList.Count - 1);
    }
}
else
{
    existingList.Clear();
}

@RBrid
Copy link
Contributor

RBrid commented Jan 9, 2019

@harinikmsft, FYI, in UWP:

  • the ListBox control preserves the vertical offset when changing the ItemsSource property.
  • the GridView and ListView controls reset the vertical offset to 0 when changing the ItemsSource property (like this UWP DataGrid).

@windowstoolkitbot
Copy link

This issue seems inactive. It will automatically be closed in 14 days if there is no activity.

@robloo
Copy link
Contributor Author

robloo commented Jan 23, 2019

Why will this be automatically closed? If there is a reasonable work-around to make the DataGrid usable with externally updated data let me know. Otherwise, seems like this should be open.

@windowstoolkitbot
Copy link

This issue seems inactive. It will automatically be closed in 14 days if there is no activity.

1 similar comment
@windowstoolkitbot
Copy link

This issue seems inactive. It will automatically be closed in 14 days if there is no activity.

@windowstoolkitbot
Copy link

Issue is inactive. It was automatically closed.

@anawishnoff
Copy link

We are not adding features to this DataGrid at this time. I know you've already added some feedback into the WinUI discussion issue, but feel free to add more if you have more ideas. Thanks!

@ghost ghost removed the no-recent-activity 📉 Open Issues that require attention label Oct 31, 2019
@Borismegabanan
Copy link

Borismegabanan commented Mar 19, 2020

private void ScrollViewer_OnScrollChanged(object sender, ScrollChangedEventArgs e)
		{
			if (e.VerticalOffset == 0 && e.VerticalChange!=0)
			{
				ArrowUp.Visibility = Visibility.Collapsed;
			}
			else if (e.VerticalOffset != 0 && e.ViewportHeight != 0)
			{
				ArrowUp.Visibility = Visibility.Visible;
			}
		}
``` My Hack

@Kyaa-dost
Copy link
Contributor

Closing this issue as @anawishnoff already responded with the WinUI discussion link.

@CommunityToolkit CommunityToolkit locked as resolved and limited conversation to collaborators Aug 23, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
DataGrid 🔠 Issues on DataGrid control feature request 📬 A request for new changes to improve functionality
Projects
None yet
Development

No branches or pull requests

8 participants