Posts Tagged ‘ ScrollIntoView ’

ListBox – Automatically scroll to bottom

In WinForms it was so simple to tell the ListBox to scroll to the buttom.
But in WPF it seems to be rather difficult but it is not.
You can simply create an attached property and once done it will do it for you.

Simply add the attached property to your ListBox

<ListBox ItemsSource="{....}" Extenders:ListBoxExtenders.AutoScrollToEnd="True" />

And here is the source code of the attached property

/// <summary>
  /// This class contains a few useful extenders for the ListBox
  /// </summary>
  public class ListBoxExtenders : DependencyObject
  {
    public static readonly DependencyProperty AutoScrollToEndProperty = DependencyProperty.RegisterAttached("AutoScrollToEnd", typeof(bool), typeof(ListBoxExtenders), new UIPropertyMetadata(default(bool), OnAutoScrollToEndChanged));

    /// <summary>
    /// Returns the value of the AutoScrollToEndProperty
    /// </summary>
    /// <param name="obj">The dependency-object whichs value should be returned</param>
    /// <returns>The value of the given property</returns>
    public static bool GetAutoScrollToEnd(DependencyObject obj)
    {
      return (bool)obj.GetValue(AutoScrollToEndProperty);
    }

    /// <summary>
    /// Sets the value of the AutoScrollToEndProperty
    /// </summary>
    /// <param name="obj">The dependency-object whichs value should be set</param>
    /// <param name="value">The value which should be assigned to the AutoScrollToEndProperty</param>
    public static void SetAutoScrollToEnd(DependencyObject obj, bool value)
    {
      obj.SetValue(AutoScrollToEndProperty, value);
    }

    /// <summary>
    /// This method will be called when the AutoScrollToEnd
    /// property was changed
    /// </summary>
    /// <param name="s">The sender (the ListBox)</param>
    /// <param name="e">Some additional information</param>
    public static void OnAutoScrollToEndChanged(DependencyObject s, DependencyPropertyChangedEventArgs e)
    {
      var listBox = s as ListBox;
      var listBoxItems = listBox.Items;
      var data = listBoxItems.SourceCollection as INotifyCollectionChanged;

      var scrollToEndHandler = new System.Collections.Specialized.NotifyCollectionChangedEventHandler(
          (s1, e1) =>
          {
            if (listBox.Items.Count > 0)
          {
            object lastItem = listBox.Items[listBox.Items.Count - 1];
            listBoxItems.MoveCurrentTo(lastItem);
            listBox.ScrollIntoView(lastItem);
          }
          });

      if ((bool)e.NewValue)
        data.CollectionChanged += scrollToEndHandler;
      else
        data.CollectionChanged -= scrollToEndHandler;
    }
  }

Note that it is similar to the scroll current element into view
So check this out: scroll current item into view

ListBox – Automatically scroll CurrentItem into View

If you are binding a Collection to the ListBox you probably would like the ListBox to automatically scroll the CurrentItem into the view.
Well you can achieve this by doing the following.

Just create a AttachedProperty which listens for the CurrentChanged – Event of the ListBoxItems.
Then it just scrolls the current item into the view.

You can easily add the attached property like this to your ListBox

<ListBox ItemsSource="{...}" IsSynchronizedWithCurrentItem="True" Extenders:ListBoxExtenders.AutoScrollToCurrentItem="True" />

The implementation of the attached property should look like this

  /// <summary>
  /// This class contains a few useful extenders for the ListBox
  /// </summary>
  public class ListBoxExtenders : DependencyObject
  {
    #region Properties

    public static readonly DependencyProperty AutoScrollToCurrentItemProperty = DependencyProperty.RegisterAttached("AutoScrollToCurrentItem", typeof(bool), typeof(ListBoxExtenders), new UIPropertyMetadata(default(bool), OnAutoScrollToCurrentItemChanged));

    /// <summary>
    /// Returns the value of the AutoScrollToCurrentItemProperty
    /// </summary>
    /// <param name="obj">The dependency-object whichs value should be returned</param>
    /// <returns>The value of the given property</returns>
    public static bool GetAutoScrollToCurrentItem(DependencyObject obj)
    {
      return (bool)obj.GetValue(AutoScrollToCurrentItemProperty);
    }

    /// <summary>
    /// Sets the value of the AutoScrollToCurrentItemProperty
    /// </summary>
    /// <param name="obj">The dependency-object whichs value should be set</param>
    /// <param name="value">The value which should be assigned to the AutoScrollToCurrentItemProperty</param>
    public static void SetAutoScrollToCurrentItem(DependencyObject obj, bool value)
    {
      obj.SetValue(AutoScrollToCurrentItemProperty, value);
    }

    #endregion

    #region Events

    /// <summary>
    /// This method will be called when the AutoScrollToCurrentItem
    /// property was changed
    /// </summary>
    /// <param name="s">The sender (the ListBox)</param>
    /// <param name="e">Some additional information</param>
    public static void OnAutoScrollToCurrentItemChanged(DependencyObject s, DependencyPropertyChangedEventArgs e)
    {
      var listBox = s as ListBox;
      if (listBox != null)
      {
        var listBoxItems = listBox.Items;
        if (listBoxItems != null)
        {
          var newValue = (bool)e.NewValue;

          var autoScrollToCurrentItemWorker = new EventHandler((s1, e2) => OnAutoScrollToCurrentItem(listBox, listBox.Items.CurrentPosition));

          if (newValue)
            listBoxItems.CurrentChanged += autoScrollToCurrentItemWorker;
          else
            listBoxItems.CurrentChanged -= autoScrollToCurrentItemWorker;
        }
      }
    }

    /// <summary>
    /// This method will be called when the ListBox should
    /// be scrolled to the given index
    /// </summary>
    /// <param name="listBox">The ListBox which should be scrolled</param>
    /// <param name="index">The index of the item to which it should be scrolled</param>
    public static void OnAutoScrollToCurrentItem(ListBox listBox, int index)
    {
      if (listBox != null && listBox.Items != null && listBox.Items.Count > index && index >= 0)
        listBox.ScrollIntoView(listBox.Items[index]);
    }

    #endregion
  }

Have fun! 🙂