尝试设置键盘焦点时 ListView 跳回拖动位置

ListView jumping back to drag location when attempting to set keyboard focus

我已将标准拖放功能添加到列表视图。我还添加了代码来检测何时接近顶部或底部以便在拖动时滚动。

不幸的是,如果我抓住一个未选中的项目,向上/向下拖动并滚动,在拖放时 ListView 将跳回到拖动开始时的垂直偏移。

我已经尝试重置垂直偏移,但到目前为止我无法阻止这种跳跃。有没有办法防止这种行为?

编辑: 此代码在拖动之前执行(用于将焦点置于文本框)。虽然,如果我阻止调用此代码,则不会发生跳转。

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));
            }));
        }
    }

问题可能出在我开始拖动操作的方式上。给定调用。

    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;
                }
            }
        }
    }

如果在 Drop 中的 Invoke 之前调用 SelectionChanged 中的 BeginInvoke,则会出现问题。由于某种原因,BeginInvoke 在调用 Invoke 之前没有完成。

此问题的解决方案是简单地确保在调用之后才调用用于设置焦点的 BeginInvoke。

解决方法是将代码附加到不同的事件,在本例中我使用了 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));
            }));
        }
    }

并非 100% 完美。当我拖放时,不会调用鼠标松开事件。这意味着当我拖放时不会设置焦点;这可能是也可能不是问题。