【发布时间】:2014-12-19 12:27:11
【问题描述】:
我维护一个旧应用程序并请求添加一项功能。我有一个显示一些项目的列表框。当 Itemssource 更改时,我希望列表框滚动到顶部。
为此,我已订阅该活动:
private bool handlerAdded = false;
private void KommentarListBox_Loaded(object sender, RoutedEventArgs e)
{
if (handlerAdded) { return; }
var dpd = DependencyPropertyDescriptor.FromProperty(ItemsControl.ItemsSourceProperty, typeof(ListView));
if (dpd != null)
{
dpd.AddValueChanged(KommentarListBox, KommentarListBox_ItemsSourceChanged);
}
handlerAdded = true;
}
以及事件处理程序:
private void KommentarListBox_ItemsSourceChanged(object sender, EventArgs e)
{
if (KommentarListBox.ItemsSource == null) { return; }
object item = null;
foreach (var i in KommentarListBox.ItemsSource)
{
item = i;
break;
}
if (item != null)
{
KommentarListBox.ScrollIntoView(item);
}
}
但是,这不会向上滚动。如果我手动调用事件处理程序,例如通过按下一个按钮,它的工作原理。因此,为了好玩,我尝试从另一个线程执行它,并在其中进行睡眠,令我惊讶的是它也有效。然而,这是我不想留在代码库中的代码气味。我怀疑在 UI 有机会更新 UI 之前调用了事件处理程序,但我不确定。有谁知道如何比可怕的睡眠更有效地解决这个问题,并且知道发生了什么?
解决方案
问题可能是在 UI 有机会更新之前尝试滚动。因此,使用 Dispatcher 我们可以设置优先级,以便在我们尝试将项目滚动到视图中之前更新 UI。
Dispatcher.BeginInvoke((Action)(() => KommentarListBox.ScrollIntoView(item)), System.Windows.Threading.DispatcherPriority.ContextIdle, null);
【问题讨论】:
-
您可能正试图在窗口构造函数中调用它。在
Loaded这样做。 -
ItemsSource 更新时会正确调用。它只是不会滚动到顶部。
-
在表单加载后尝试设置
ItemsSource(又名Loaded)。 -
ItemsSource 是通过数据绑定设置的,所以除了基础对象更改时,我无法控制它何时真正设置。
-
然后只需调用
Loaded末尾的事件处理程序即可。更干净的是创建单独的方法ScrollToTop()并从属性更改事件中调用它,并直接在Loaded中调用一次。
标签: c# .net wpf listbox .net-4.5