【问题标题】:Autoscrolling a Listbox under a certain situation在特定情况下自动滚动列表框
【发布时间】:2009-01-27 20:53:32
【问题描述】:

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

【问题讨论】:

    标签: c# listbox scroll


    【解决方案1】:

    你可以试试看:

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

    【讨论】:

    • 这显然是最好的解决方案。
    • 虽然这不能完美地回答问题,它要求滚动行为发生在“只有在添加项目之前滚动条位于底部时”,这是一个很好的解决方案并帮助我实现我想做的事。谢谢!
    【解决方案2】:

    此示例代码应该可以帮助您。我已经用 TextBox 做了很多次,但花了一段时间才弄清楚 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。
    【解决方案3】:

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

    基本思想是,它通过使用 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();
        }
    

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 2016-11-06
        • 1970-01-01
        • 1970-01-01
        • 2021-05-16
        • 1970-01-01
        • 2010-11-21
        • 2021-07-14
        • 2020-05-06
        • 2014-01-19
        相关资源
        最近更新 更多