代码之家  ›  专栏  ›  技术社区  ›  Juan

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

  •  9
  • Juan  · 技术社区  · 16 年前

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

    4 回复  |  直到 12 年前
        1
  •  10
  •   scrat789    12 年前

    你可以试试:

    listBox1.SelectedIndex = listBox1.Items.Count - 1;    
    listBox1.SelectedIndex = -1;
    
        2
  •  9
  •   colithium    16 年前

    这个示例代码应该可以帮助您解决这个问题。我用一个文本框做了很多次,但是花了一段时间才找到一个列表框

    显然,它只是一个有按钮和列表框的表单。修改以满足您的需要:

    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;
        }
    }
    
        3
  •  1
  •   dunni    14 年前

    我提出了以下解决方案,也将适用于业主绘制的列表框与可变高度的项目。

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

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

    它还有一些额外的代码,可以在列表中的项目数达到最大值(在其他地方由常量max_listbox_items定义),方法是在列表满后删除顶部的项目。当它这样做的时候,它会计算出它需要在哪里滚动列表,以保持相同的项目显示,即使在一个被删除后。如果您不想控制添加到列表框中的项的数量,那么应该可以从代码中删除middle 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();
        }
    
        4
  •  0
  •   metao    14 年前

    我用与colithium类似的方法解决了这个问题,但后来我意识到并发更新有一个bug。所以有一个名为m_previouscount的类成员,它在更新之前将项目的数量存储在列表框中。

    我是用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);
    }