添加新项目后如何自动滚动列表框,但前提是在添加项目之前滚动条位于底部?
4 回答
你可以试试:
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));
}
/// <summary>
/// Scroll to last item, unless you have scrolled up the list
/// </summary>
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);
}