ListBox的ScrollIntoView和SelectedItem不可靠

3
我目前有一个列表框设置如下:
.xaml:
<ListBox Name="DetailsList" ItemsSource="{Binding}" LayoutUpdated="DetailsList_LayoutUpdated" />

.xaml.cs:
private ObservableCollection<string> details = new ObservableCollection<string>();

在窗口构造函数中:
DetailsList.DataContext = details;

我有一个按钮,它可以做以下的事情:
details.Add(System.DateTime.Now.ToString("HH:mm:ss ") + someString);
DetailsList.UpdateLayout();
var lastItem = DetailsList.Items[DetailsList.Items.Count - 1];
DetailsList.SelectedItem = lastItem;
DetailsList.ScrollIntoView(lastItem);

这应该选择列表中的最后一个项目并滚动到它,但只有大约75%的时间会这样做。相反,它经常会选择倒数第二个并滚动到该位置。

我尝试将滚动和选择移动到LayoutUpdated事件处理程序中,但没有改变。

我尝试了两个单独的按钮-一个用于添加,一个用于选择和滚动。如果我一次添加一个项目然后滚动,它似乎要可靠一些-它有90%的成功率。如果我在滚动之前添加半打项目,它几乎从不起作用。通常它会选择其中一个新项目,但不是最后一个。

我是做错了什么,还是System.Windows.Controls.ListBox存在错误?


1
“someString”是什么?它的值总是相同的吗?如果您每秒按下按钮超过一次,则可能存在平等问题。 - Kai G
我认为这个值并不重要。是的,对于按钮测试来说它是一个常量。这是否意味着没有办法区分具有相同内容的元素?有些情况下,“真实”的数据可能相同,并且在一秒钟内多次添加。 - Jean W
值可能很重要。当您在ListBox中设置SelectedItem时,它将调用其项上的Equals方法以查找要选择的项。如果您有两个具有相同文本的字符串,它将无法确定您指的是哪一个,并且您将获得观察到的行为。 - Kai G
您需要一种唯一识别列表项的方式。如果您的“真实”数据可能相同,您将无法直接将字符串添加到列表中。您必须将它们封装在一个类中。该类的默认Equals方法应该解决这个问题。 - Kai G
谢谢。我会通过在时间戳中添加毫秒来欺骗。如果有一个简单的“scrollToEnd”方法,那就太好了。这似乎是一个相当常见的功能。 - Jean W
我已经发布了一个答案,以便解决这个问题。 - Kai G
1个回答

8
问题在于同一字符串值的多个项目已添加到列表中。在设置ListView上的SelectedItem属性时,它会调用Equals方法来查找正确的项目。它将选择第一个Equals返回true的项目,这就是为什么您会得到观察到的行为。
您需要添加唯一的字符串(例如添加毫秒)或将其包装在另一个类中以能够唯一地标识它们。

我正在直接从文本框添加项目,有没有解决办法来避免这个问题?而不是防止最终用户两次添加相同的项目? - Ahmed Alayat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接