What I want to achieve is a pretty standard thing, I guess: While dragging a row from a DataGrid in WPF, if the mouse cursor reaches the top or bottom edge, the DataGrid should automatically scroll more content into view.
The following however is a bit of a mess due to legacy code that handles the drag/drop functionality. So far I start my scrolling operation from the DataGrid's MouseMove
event:
private void DataGrid_MouseMove(object sender, MouseEventArgs e)
{
...
var mouseposition = e.GetPosition(m_DataGrid);
if (mouseposition.Y < 50)
{
dispatcher.Invoke(() => DatagridAutomaticScroll(m_DataGrid, false), DispatcherPriority.Normal);
}
else if (mouseposition.Y > (m_DataGrid.Height - 50))
{
dispatcher.Invoke(() => DatagridAutomaticScroll(m_DataGrid, true), DispatcherPriority.Normal);
}
else
{
scrollwatch.Reset();
}
}
And this is the called method:
private void DatagridAutomaticScroll(DataGrid dataGrid, bool scrolldown)
{
if (scrollwatch.IsRunning && scrollwatch.ElapsedMilliseconds < 500) return;
ScrollViewer scroller = GetScrollViewer(dataGrid);
if (scrolldown)
{
// will be implemented later
}
else
{
if (scroller.VerticalOffset == 0) return;
scroller.ScrollToVerticalOffset(scroller.VerticalOffset - 1);
scrollwatch.Restart();
}
}
The stopwatch timer prevents the scroller from scrolling all the way immediately, however there are two issues with this:
- The way it is implemented now, the scrollviewer will only scroll as long as the user moves the mouse (since all of this is only called from the
MouseMove
event). - If I put everything into a loop, which scrolls every x ms as long as the mouse is on the edge, this will lock up my GUI.
I'm not quite sure how to solve this. Starting a new thread is impossible, since I don't think it will have access to GUI controls (also it seems counter intuitive to start a thread for a simple scrolling operation.)