Reputation: 166
I am using WPF Datagrid and I would like to have it autoscrolled when a new row is added. For this, I added the CollectionChanged event for the ItemsSource and it works fine.
private void dataGrid_Loaded(object sender, RoutedEventArgs e)
{
var items = (dataGrid.ItemsSource as ObservableCollection<MyViewModel>);
if (items == null)
return;
items.CollectionChanged += MainWindow_CollectionChanged;
}
private void MainWindow_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (dataGrid.Items !=null && dataGrid.Items.Count > 0)
dataGrid.ScrollIntoView(dataGrid.Items[dataGrid.Items.Count - 1]);
}
The problem is I want the autoscroll feature disabled while I click on any of the scroll bars of the Datagrid. Is there any way I can do this?
Thanks!
Upvotes: 0
Views: 2073
Reputation: 166
After some more investigation, I found the following simple solution. For the Datagrid, I added the scroll event.
XAML:
<DataGrid Name="dataGrid" ScrollBar.Scroll ="dataGrid_Scroll">
</DataGrid>
CS:
private void dataGrid_Scroll(object sender, RoutedEventArgs e)
{
ScrollEventArgs scrollEvent = e as ScrollEventArgs;
if (scrollEvent != null)
{
if (scrollEvent.ScrollEventType == ScrollEventType.EndScroll)
{
isScrolling = false;
}
else
{
isScrolling = true;
}
}
}
Upvotes: 2
Reputation: 13458
You can use an attached property to observe the relevant ScrollBar events. Note, in the following example I am using two properties: EnableUserScrollingObserver
in order to enable the event listeners and IsUserScrolling
to report the current scrolling state.
public static class Attached
{
public static bool GetEnableUserScrollingObserver(DependencyObject obj)
{
return (bool)obj.GetValue(EnableUserScrollingObserverProperty);
}
public static void SetEnableUserScrollingObserver(DependencyObject obj, bool value)
{
obj.SetValue(EnableUserScrollingObserverProperty, value);
}
public static readonly DependencyProperty EnableUserScrollingObserverProperty =
DependencyProperty.RegisterAttached("EnableUserScrollingObserver", typeof(bool), typeof(Attached),
new FrameworkPropertyMetadata(false, new PropertyChangedCallback(EnableUserScrollingObserverChanged)));
private static void EnableUserScrollingObserverChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var s = d as ScrollBar;
if (s != null)
{
s.Scroll -= Scrollbar_Scroll;
if ((bool)e.NewValue)
{
s.Scroll += Scrollbar_Scroll;
}
}
else
{
// Using this on anything other than a ScrollBar sucks
throw new InvalidOperationException("EnableUserScrollingObserver is designed for ScrollBar elements!");
}
}
static void Scrollbar_Scroll(object sender, ScrollEventArgs e)
{
var s = sender as ScrollBar;
switch (e.ScrollEventType)
{
case ScrollEventType.EndScroll:
SetIsUserScrolling(s, false);
break;
/* All the things handled by default
case ScrollEventType.First:
break;
case ScrollEventType.LargeDecrement:
break;
case ScrollEventType.LargeIncrement:
break;
case ScrollEventType.Last:
break;
case ScrollEventType.SmallDecrement:
break;
case ScrollEventType.SmallIncrement:
break;
case ScrollEventType.ThumbPosition:
break;
case ScrollEventType.ThumbTrack:
break;
*/
default:
SetIsUserScrolling(s, true);
break;
}
}
public static bool GetIsUserScrolling(DependencyObject obj)
{
return (bool)obj.GetValue(IsUserScrollingProperty);
}
public static void SetIsUserScrolling(DependencyObject obj, bool value)
{
obj.SetValue(IsUserScrollingProperty, value);
}
public static readonly DependencyProperty IsUserScrollingProperty =
DependencyProperty.RegisterAttached("IsUserScrolling", typeof(bool), typeof(Attached),
new FrameworkPropertyMetadata(false));
}
Then connect the scroll information to your viewmodel IsScrolling
property
<Style TargetType="ScrollBar">
<Setter Property="local:Attached.EnableUserScrollingObserver" Value="True"/>
<Setter Property="local:Attached.IsUserScrolling" Value="{Binding IsScrolling,Mode=OneWayToSource}"/>
</Style>
Finally, in your MainWindow_CollectionChanged
method, add a check for the IsScrolling
property.
Upvotes: 0