0
votes

I've added standard drag drop functionality to a Listview. I've also added code to detect when I'm near the top or bottom in order to scroll when dragging.

Unfortunately, if I grab an unselected item, drag up/ down and scroll, on Drop the ListView will jump back to the vertical offset that it started with when drag began.

I've attempted to reset the vertical offset, but so far I am unable to prevent this jump. Is there a way to prevent this behavior?

EDIT: This code is executed before the drag (used to give focus to a textbox). Although, if I prevent this code from being called then the jump will not occur.

private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var element = Keyboard.FocusedElement;
        if (element is ListViewItem)
        {
            Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(delegate ()
            {
                (element as ListViewItem).MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
            }));
        }
    }

The issue may be with the way I begin my drag operation. Given the invocation.

    protected void BeginDrag(object sender, MouseEventArgs e, Action<object> action)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            Point position = e.GetPosition(this);
            this.ListView.ReleaseMouseCapture();

            if ((Math.Abs(position.X - _startPoint.X) > 10
                || Math.Abs(position.Y - _startPoint.Y) > 10)
                && !IsDragging)
            {
                try
                {
                    IsDragging = true;
                    Application.Current.Dispatcher.Invoke(
                        DispatcherPriority.Normal,
                        new System.Threading.ParameterizedThreadStart(action),
                        e);
                }
                catch (InvalidOperationException) { }
                finally
                {
                    IsDragging = false;
                }
            }
        }
    }
1

1 Answers

1
votes

There was an issue if the BeginInvoke in SelectionChanged was called before the Invoke in the Drop. For one reason or another the BeginInvoke did not finish before the Invoke was called.

The Solution to this issue was to simply assure that the BeginInvoke for setting the focus was not called until AFTER the Invoke.

A fix is to attach the code to a different event, in this case I used MouseUp.

private void ListView_MouseUp(object sender, MouseButtonEventArgs e)
    {
        var element = Keyboard.FocusedElement;
        if (element is ListViewItem)
        {
            Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Input, new Action(delegate ()
            {
                (element as ListViewItem).MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
            }));
        }
    }

Not 100% perfect. When I drag and drop, the event for mouse up is not called. This means that the focus will not be set when I drag and drop; which may or may not be an issue.