75

I am using a Winforms ListBox as a small list of events, and want to populate it so that the last event (bottom) is visible. The SelectionMode is set to none. The user can scroll the list but I would prefer it start out scrolled to the end.

Looking at the lack of support for things like ScrollIntoView, EnsureVisible, I am assuming I will need to create a custom control that inherits from ListBox; however I'm not sure what to do from there.

Some pointers?

JYelton
  • 35,664
  • 27
  • 132
  • 191
  • 3
    Did the normal `listBox1.SelectedIndex = listBox1.Items.Count - 1;` not work for you? – M.Babcock Jan 09 '12 at 23:42
  • 1
    That works when `SelectionMode` is not set to `None`. I need to prevent selecting items in this particular list (to avoid user confusion). – JYelton Jan 09 '12 at 23:44

4 Answers4

98

I believe you can do that easily by setting the TopIndex property appropriately.

For example:

int visibleItems = listBox.ClientSize.Height / listBox.ItemHeight;
listBox.TopIndex = Math.Max(listBox.Items.Count - visibleItems + 1, 0);
Jon
  • 428,835
  • 81
  • 738
  • 806
  • +1 A bit convoluted, but that's certainly not your fault! Thanks for the solution and example. – JYelton Jan 10 '12 at 00:05
  • 44
    It seems to work fine if you just set `TopIndex` to the last item instead of worrying about which should really be at the top, e.g. `listBox.TopIndex = listBox.Items.Count - 1;` – Craig W Nov 08 '13 at 04:13
80

Scroll to the bottom:

listbox.TopIndex = listbox.Items.Count - 1;

Scroll to the bottom, and select the last item:

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

WSBT
  • 33,033
  • 18
  • 128
  • 133
2

This is what I ended up with for WPF (.Net Framework 4.6.1):

Scroll.ToBottom(listBox);

Using the following utility class:

public partial class Scroll
{
    private static ScrollViewer FindViewer(DependencyObject root)
    {
        var queue = new Queue<DependencyObject>(new[] { root });

        do
        {
            var item = queue.Dequeue();
            if (item is ScrollViewer) { return (ScrollViewer)item; }
            var count = VisualTreeHelper.GetChildrenCount(item);
            for (var i = 0; i < count; i++) { queue.Enqueue(VisualTreeHelper.GetChild(item, i)); }
        } while (queue.Count > 0);

        return null;
    }

    public static void ToBottom(ListBox listBox)
    {
        var scrollViewer = FindViewer(listBox);

        if (scrollViewer != null)
        {
            scrollViewer.ScrollChanged += (o, args) =>
            {
                if (args.ExtentHeightChange > 0) { scrollViewer.ScrollToBottom(); }
            };
        }
    }
}
Sean Vikoren
  • 1,084
  • 1
  • 13
  • 24
0

If you want a winforms listbox that "sticks to bottom when at bottom" you can:

int visibleItems = lb.ClientSize.Height / lb.ItemHeight;
if (lb.Items.Count > lb && lb.TopIndex > lb.Items.Count - visibleItems - 2)
  lb.TopIndex = lb.Items.Count - visibleItems + 1;

When scrolled to bottom, new items will cause it to scroll down to show them, but if you scroll up a bit, then it ceases its "jump to bottom" behavior yso you can carry on looking at what you scrolled up to see

Caius Jard
  • 72,509
  • 5
  • 49
  • 80