Автопрокрутка списка в определенной ситуации

Как автоматически прокручивать список после добавления нового элемента, но только если полоса прокрутки находится внизу до добавления элемента?


person Community    schedule 27.01.2009    source источник


Ответы (4)


Вы можете просто попробовать:

listBox1.SelectedIndex = listBox1.Items.Count - 1;    
listBox1.SelectedIndex = -1;
person scrat789    schedule 20.04.2012
comment
Это, очевидно, лучшее решение. - person Good Night Nerd Pride; 20.09.2012
comment
Хотя это не полностью отвечает на вопрос, который требует, чтобы поведение прокрутки происходило только в том случае, если полоса прокрутки находится внизу до добавления элемента, это отличное решение, которое помогло мне достичь того, что я хотел сделать. Благодарю вас! - person Tom Catullo; 19.09.2016

Этот пример кода должен вам помочь. Я делал это много раз с 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;
    }
}
person colithium    schedule 03.02.2009
comment
Я добавил кнопкуMultipleAdds_Click для случая, когда вам нужно добавить/удалить любое количество строк. - person huha; 25.02.2014

Я придумал следующее решение, которое также будет работать для нарисованных владельцем списков с элементами переменной высоты.

Основная идея заключается в том, что он определяет, прокручивается ли он вниз, используя метод 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();
    }
person dunni    schedule 26.10.2010

Я решил эту проблему, используя метод, аналогичный 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);
}
person metao    schedule 03.06.2010