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

9
如何在添加新项目之后自动滚动 Listbox,但仅当滚动条在添加项目之前位于底部时?
4个回答

12

你可以尝试一下:

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

1
这显然是最佳解决方案。 - Good Night Nerd Pride
虽然这并不能完美地回答问题,因为它要求滚动行为在添加项目之前“仅当滚动条在底部时发生”,但这是一个很好的解决方案,帮助我实现了我想要做的事情。谢谢! - Tom Catullo

9
这个示例代码应该可以帮到你。我之前使用TextBox做过类似的事情,但要在ListBox上实现却花了一些时间来搞清楚。
显然,这只是一个有按钮和ListBox的窗体。根据你的需要进行修改:
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;
    }
}

我添加了buttonMultipleAdds_Click,以备需要添加/删除任意数量的行的情况。 - huha

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();
    }

0

我使用了与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);
}

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