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

时间:2009-01-27 20:53:33

标签: c# listbox scroll

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

4 个答案:

答案 0 :(得分:10)

你可以尝试一下:

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

答案 1 :(得分:9)

此示例代码可以帮助您解决问题。我已经用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;
    }
}

答案 2 :(得分: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();
    }

答案 3 :(得分: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);
}