在特定情况下自动滚动列表框

如何在添加新项目后自动滚动列表框,但前提是在添加项目之前滚动条位于底部?

你可以尝试一下:

listBox1.SelectedIndex = listBox1.Items.Count - 1; listBox1.SelectedIndex = -1; 

此示例代码可以帮助您。 我已经用TextBox多次完成了这个,但是需要一段时间才能找到一个ListBox

显然,它只是一个带有Button和ListBox的Form。 修改以满足您的需求:

 private void button1_Click(object sender, EventArgs e) { listBox1.Items.Add("Some Text " + listBox1.Items.Count.ToString()); //The max number of items that the listbox can display at a time int NumberOfItems = listBox1.ClientSize.Height / listBox1.ItemHeight; if (listBox1.TopIndex == listBox1.Items.Count - NumberOfItems - 1) { //The item at the top when you can just see the bottom item listBox1.TopIndex = listBox1.Items.Count - NumberOfItems + 1; } } 

我想出了以下解决方案,该解决方案也适用于具有可变高度项目的所有者绘制列表框。

基本思想是通过使用IndexToPoint方法和列表框底部的一个点来确定它是否滚动到底部,以查看最后一个项目是否在该位置。 这有一个轻微的缺陷,如果最后一个项目在底部但不完全可见,它仍然会认为它滚动到底部。

它使用TopIndex属性滚动列表框。 请注意,当将TopIndex设置为列表框中的最后一项时,如果有足够的空间容纳其他项目,则它实际上不会将其放在顶部。 在这种情况下,它会把它放在底部,这就是你想要的。

它还有一些额外的代码,用于将列表中的项目数量保持为最大数量(在常量MAX_LISTBOX_ITEMS的其他地方定义),方法是在其填满后删除最高项目。 当它执行此操作时,它会在需要滚动列表的位置找到相同的项目,即使在删除一个项目后也是如此。 如果您不关心控制添加到列表框中的项目数,您应该能够从代码中删除中间if子句以及scrollToIndex变量的任何提及。

 private void AddItemToListBox(ListBox listBox, object newItem) { int scrollToIndex = -1; bool scrollToEnd = false; //Work out if we should scroll to the end after adding a new item int lastIndex = listBox.IndexFromPoint(4, listBox.ClientSize.Height - 4); if ((lastIndex < 0) || (lastIndex == listBox.Items.Count - 1)) { scrollToEnd = true; } //To prevent listbox jumping about as we delete and scroll listBox.BeginUpdate(); //Work out if we have too many items and have to delete if (listBox.Items.Count >= MAX_LISTBOX_ITEMS) { //If deleting an item, and not scrolling to the end when new item added anyway, //then we will need to scroll to keep in the same place, work out new scroll index if (!scrollToEnd) { scrollToIndex = listBox.TopIndex - 1; if (scrollToIndex < 0) { scrollToIndex = 0; } } //Remove top item listBox.Items.Remove(listBox.Items[0]); } //Add new item listBox.Items.Add(newItem); //Scroll if necessary if (scrollToEnd) { listBox.TopIndex = listBox.Items.Count - 1; } else if (scrollToIndex >= 0) { listBox.TopIndex = scrollToIndex; } listBox.EndUpdate(); } 

我使用与colithium类似的方法解决了这个问题,除了我然后意识到并发更新存在错误。 因此,有一个名为m_previousCount的类成员,它在此更新发生之前存储ListBox中的项目数。

我使用ListView执行此操作,但它对ListBox应该是相同的。

在这种情况下,我的listView1内容绑定到listViewModel1.Entries。

 private void EventMessageViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { listView1.Dispatcher.BeginInvoke(DispatcherPriority.Background, new ScrollToLastItemDelegate(ScrollToLastItem)); } ///  /// Scroll to last item, unless you have scrolled up the list ///  private void ScrollToLastItem() { // Get scrollviewer Decorator border = System.Windows.Media.VisualTreeHelper.GetChild(listView1, 0) as Decorator; ScrollViewer scrollViewer = border.Child as ScrollViewer; double vo = scrollViewer.VerticalOffset; // assume they are all the same height ListBoxItem lbi = listView1.ItemContainerGenerator.ContainerFromIndex(0) as ListBoxItem; //The max number of items that the listbox can display at a time double NumberOfItemsOnScreen = listView1.ActualHeight / lbi.ActualHeight; // use previousCount in case we get multiple updates in one go if (m_previousCount > NumberOfItemsOnScreen) // scrollbar should be active { if (vo < (m_previousCount - NumberOfItemsOnScreen)) // you're not at the bottom { return; // don't scroll to the last item } } m_previousCount = listView1.Items.Count; // scroll to the last item listView1.SelectedItem = listView1.Items.GetItemAt(listViewModel1.Entries.Count - 1); listView1.ScrollIntoView(listView1.SelectedItem); }