尝试设置键盘焦点时 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% 完美。当我拖放时,不会调用鼠标松开事件。这意味着当我拖放时不会设置焦点;这可能是也可能不是问题。
我已将标准拖放功能添加到列表视图。我还添加了代码来检测何时接近顶部或底部以便在拖动时滚动。
不幸的是,如果我抓住一个未选中的项目,向上/向下拖动并滚动,在拖放时 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% 完美。当我拖放时,不会调用鼠标松开事件。这意味着当我拖放时不会设置焦点;这可能是也可能不是问题。