Reputation: 3327
I', using ScrollIntoView
to scroll to the topmost item in list (by default it's always scrolled to the bottom ones, but in some specified case I need this the other way)
So first items are added to list, and then ScrollIntoView(Items[0])
called.
ScrollIntoView called inside Dispatcher.BeginInvoke
, so it's in UI thread.
The general idea is that user sees initial list with items 'short' description, then selects one of them, and sees all the info, which contains also 'short' part.
I.e.:
1)
2)
So when I'm clicking on element 1 in case 1, I'm expecting to see the picture 2. But instead sometimes I see
I noticed, for example, that view is always updated properly, when cursor stayed on listbox. I've checked callstack of the "AddItem" and "ScrollTop" methods, they are in correct ordering, and "ScrollTop" is always called properly.
In all other cases (when I'm picking up Item 2, or Item 0) "ScrollTop" working well.
So I think it's some kind of WPF optimization or so. Because Item 1 info in 1) is same and on the same place as in case 2). WPF just does not each time updates the view.
Is there any way, to make list box to be updated every time after I scroll to top?
I've tried with UpdateLayout()
. It didn't help.
UPDATE (code example): main thread code:
UIManager.AddListItem(item1);
UIManager.AddListItem(item2);
UIManager.AddListItem(item3);
UIManager.ScrollToTop();
UIManager implementation:
public void AddListItem(ListItem item)
{
ExecuteUI(() =>
{
MyList.AddItem(item);
});
}
public void ScrollToTop()
{
ExecuteUI(() =>
{
MyList.ScrollToTop();
});
}
MyListModel implementation:
public void AddItem(ListItem item)
{
lock (linesLock)
{
if (Lines == null)
Lines = new ObservableCollection<ItemModel>();
ItemModel line = new ItemModel(item);
Lines.Add(line); //When line added it automatically scrolls to it
// via ((INotifyCollectionChanged)ListLines.Items).CollectionChanged += LinesChanged;
}
}
public void ScrollToTop()
{
if (Lines.Count == 0 || ScrollEvent == null)
return;
ScrollEvent(this, new ScrollEventArgs(Lines[0]));
// via Model.ScrollEvent += ScrollEvent;
}
Model xaml code:
// ListLines is a ListBox
private void LinesChanged(object sender, NotifyCollectionChangedEventArgs e)
{
ListLines.ScrollIntoView(e.NewItems[0]);
}
private void ScrollEvent(object sender, ScrollEventArgs e)
{
ListLines.ScrollIntoView(e.Item);
}
Upvotes: 0
Views: 164
Reputation: 169150
Try to use the ScrollToVerticalOffset
or the ScrollToTop
method of the ScrollViewer
:
public void Click(object sender, RoutedEventArgs e)
{
ScrollViewer sv = GetChildOfType<ScrollViewer>(listBox);
if (sv != null)
sv.ScrollToVerticalOffset(0);
}
public static T GetChildOfType<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj == null)
return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = (child as T) ?? GetChildOfType<T>(child);
if (result != null)
return result;
}
return null;
}
But please also always remember to provide a Minimal, Complete, and Verifiable example of your issue when asking a question.
Upvotes: 1