Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to automatically scroll ScrollViewer - only if the user did not change scroll position

I would like to create the following behaviour in a ScrollViewer that wraps ContentControl:
When the ContentControl height grows , the ScrollViewer should automatically scroll to the end. This is easy to achive by using ScrollViewer.ScrollToEnd().
However, if the user uses the scroll bar, the automatic scrolling shouldn't happen anymore. This is similar to what happens in VS output window for example.

The problem is to know when a scrolling has happened because of user scrolling and when it happened because the content size changed. I tried to play with the ScrollChangedEventArgsof ScrollChangedEvent, but couldn't get it to work.

Ideally, I do not want to handle all possible Mouse and keyboard events.

like image 853
Elad Avatar asked Jun 06 '10 15:06

Elad


People also ask

How do I set up automatic scrolling?

To use you just need to press CTRL+ Left click of your mouse and drag the mouse a bit in the direction you want to scroll the page. For example, if you want to scroll up to the page automatically, click CTRL+ left click and slightly move your mouse upwards, the tool will start scrolling up the page.

How do I make Div scroll automatically?

Set the overflow-x:hidden; and overflow-y:auto; that will automatically hide the horizontal scroll bar and present only vertical scrollbar. Here the scroll div will be vertically scrollable.

How do I automatically scroll down a page in HTML?

The first one is with javascript: set the scrollTop property of the scrollable element (e.g. document. body. scrollTop = 1000; ). The second is setting the link to point to a specific id in the page e.g.


2 Answers

You can use ScrollChangedEventArgs.ExtentHeightChange to know if a ScrollChanged is due to a change in the content or to a user action... When the content is unchanged, the ScrollBar position sets or unsets the auto-scroll mode. When the content has changed you can apply auto-scrolling.

Code behind:

    private Boolean AutoScroll = true;      private void ScrollViewer_ScrollChanged(Object sender, ScrollChangedEventArgs e)     {         // User scroll event : set or unset auto-scroll mode         if (e.ExtentHeightChange == 0)         {   // Content unchanged : user scroll event             if (ScrollViewer.VerticalOffset == ScrollViewer.ScrollableHeight)             {   // Scroll bar is in bottom                 // Set auto-scroll mode                 AutoScroll = true;             }             else             {   // Scroll bar isn't in bottom                 // Unset auto-scroll mode                 AutoScroll = false;             }         }          // Content scroll event : auto-scroll eventually         if (AutoScroll && e.ExtentHeightChange != 0)         {   // Content changed and auto-scroll mode set             // Autoscroll             ScrollViewer.ScrollToVerticalOffset(ScrollViewer.ExtentHeight);         }     } 
like image 105
KBH Avatar answered Sep 30 '22 02:09

KBH


Here is an adaptation from several sources.

public class ScrollViewerExtensions     {         public static readonly DependencyProperty AlwaysScrollToEndProperty = DependencyProperty.RegisterAttached("AlwaysScrollToEnd", typeof(bool), typeof(ScrollViewerExtensions), new PropertyMetadata(false, AlwaysScrollToEndChanged));         private static bool _autoScroll;          private static void AlwaysScrollToEndChanged(object sender, DependencyPropertyChangedEventArgs e)         {             ScrollViewer scroll = sender as ScrollViewer;             if (scroll != null)             {                 bool alwaysScrollToEnd = (e.NewValue != null) && (bool)e.NewValue;                 if (alwaysScrollToEnd)                 {                     scroll.ScrollToEnd();                     scroll.ScrollChanged += ScrollChanged;                 }                 else { scroll.ScrollChanged -= ScrollChanged; }             }             else { throw new InvalidOperationException("The attached AlwaysScrollToEnd property can only be applied to ScrollViewer instances."); }         }          public static bool GetAlwaysScrollToEnd(ScrollViewer scroll)         {             if (scroll == null) { throw new ArgumentNullException("scroll"); }             return (bool)scroll.GetValue(AlwaysScrollToEndProperty);         }          public static void SetAlwaysScrollToEnd(ScrollViewer scroll, bool alwaysScrollToEnd)         {             if (scroll == null) { throw new ArgumentNullException("scroll"); }             scroll.SetValue(AlwaysScrollToEndProperty, alwaysScrollToEnd);         }          private static void ScrollChanged(object sender, ScrollChangedEventArgs e)         {             ScrollViewer scroll = sender as ScrollViewer;             if (scroll == null) { throw new InvalidOperationException("The attached AlwaysScrollToEnd property can only be applied to ScrollViewer instances."); }              // User scroll event : set or unset autoscroll mode             if (e.ExtentHeightChange == 0) { _autoScroll = scroll.VerticalOffset == scroll.ScrollableHeight; }              // Content scroll event : autoscroll eventually             if (_autoScroll && e.ExtentHeightChange != 0) { scroll.ScrollToVerticalOffset(scroll.ExtentHeight); }         }     } 

Use it in your XAML like so:

<ScrollViewer Height="230" HorizontalScrollBarVisibility="Auto" extensionProperties:ScrollViewerExtension.AlwaysScrollToEnd="True">     <TextBlock x:Name="Trace"/> </ScrollViewer> 
like image 21
Magikos Avatar answered Sep 30 '22 02:09

Magikos