Reputation: 2026
The view having one DataGrid and The ViewModel having the following function
public DependencyObject ScrollViewer(DependencyObject targetControl)
{
if (targetControl is ScrollViewer)
{
return targetControl;
}
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(targetControl); i++)
{
var child = VisualTreeHelper.GetChild(targetControl, i);
var result = ScrollViewer(child);
if (result == null)
{
continue;
}
else
{
return result;
}
}
return null;
}
now i want to get scrollviewer of the grid using above function.
var scrolViewer = ScrollViewer(dataGridID) as ScrollViewer;
If i pass the datagrid id as parameter. i will get the result. But it is not possible in MVVM pattern. is there any way to get the visual child data grid ?
Upvotes: 1
Views: 1851
Reputation: 69372
I've created a quick Attached Property
that should allow you to stick with the MVVM concepts and also provide you the ability to scroll to the top and bottom of the DataGrid
. It can be improved (e.g. avoid two separate properties and use an IValueConverter
to decide how to scroll) but this should give you a good starting point.
First, we create the Attached Properties (one for scrolling to the bottom and one for the top)
public static class Scroller
{
//Create the attached property and register it
public static readonly DependencyProperty ScrollToBottomProperty =
DependencyProperty.RegisterAttached("ScrollToBottom", typeof(bool), typeof(Scroller), new PropertyMetadata(false, ScrollToBottomPropertyChanged));
//Create the get and set methods for the property
public static bool GetScrollToBottom(DependencyObject obj)
{
return (bool)obj.GetValue(ScrollToBottomProperty);
}
public static void SetScrollToBottom(DependencyObject obj, bool value)
{
obj.SetValue(ScrollToBottomProperty, value);
}
//Get the control that you've attached this to (DataGrid in this case) and find its ScrollViewer
private static void ScrollToBottomPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var scrollViewer = GetScrollViewer(d) as ScrollViewer;
if (scrollViewer != null && (bool)e.NewValue)
{
//Use built in ScrollToBottom method to scroll to...well...the bottom :)
scrollViewer.ScrollToBottom();
}
}
//Same as above but for "ScrollToTop" method
public static readonly DependencyProperty ScrollToTopProperty =
DependencyProperty.RegisterAttached("ScrollToTop", typeof(bool), typeof(Scroller), new PropertyMetadata(false, ScrollToTopPropertyChanged));
public static bool GetScrollToTop(DependencyObject obj)
{
return (bool)obj.GetValue(ScrollToTopProperty);
}
public static void SetScrollToTop(DependencyObject obj, bool value)
{
obj.SetValue(ScrollToTopProperty, value);
}
private static void ScrollToTopPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var scrollViewer = GetScrollViewer(d) as ScrollViewer;
if (scrollViewer != null && (bool)e.NewValue)
{
scrollViewer.ScrollToTop();
}
}
//Your ScrollViewerMethod (I renamed it to GetScrollViewer for clarity)
public static DependencyObject GetScrollViewer(DependencyObject targetControl)
{
if (targetControl is ScrollViewer)
{
return targetControl;
}
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(targetControl); i++)
{
var child = VisualTreeHelper.GetChild(targetControl, i);
var result = GetScrollViewer(child);
if (result == null)
{
continue;
}
else
{
return result;
}
}
return null;
}
}
In your XAML, you need to add the relevant namespace (change yours accordingly)
xmlns:custom="clr-namespace:ScrollExampleMVVM"
We can then attach the properties to our DataGrid
<DataGrid custom:Scroller.ScrollToBottom="{Binding ScrollBottom}" custom:Scroller.ScrollToTop="{Binding ScrollTop}" ...?
In your ViewModel, you can have your public ScrollBottom
and ScrollTop
properties
private bool _scrollBottom = false;
public bool ScrollBottom
{
get { return _scrollBottom; }
set
{
_scrollBottom = value;
NotifyPropertyChanged("ScrollBottom");
}
}
private bool _scrollTop = false;
public bool ScrollTop
{
get { return _scrollTop; }
set
{
_scrollTop = value;
NotifyPropertyChanged("ScrollTop");
}
}
Finally handle your buttons (I'm guessing you're using ICommands
) to call the scrolling
private void ScrollBottomCommand(object param)
{
//Immediately set back to false so that it can be reused
ScrollBottom = true;
ScrollBottom = false;
}
private void ScrollTopCommand(object param)
{
ScrollTop = true;
ScrollTop = false;
}
That should work. As mentioned earlier, you could probably improve it to avoid the reset code but hopefully this should give an idea.
Upvotes: 1