防止 WPF ListBox 在布局更改时选择鼠标下的项目 [英] Prevent WPF ListBox from selecting item under mouse when layout changes

查看:33
本文介绍了防止 WPF ListBox 在布局更改时选择鼠标下的项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果 WPF 列表框在按住鼠标按钮时收到 MouseMove 事件,它将更改列表框的选择.也就是说,如果您在项目#1 上单击鼠标,然后拖动到项目#2,它将取消选择项目#1 并选择项目#2.如何防止这种情况发生?

If a WPF ListBox gets a MouseMove event while the mouse button is held down, it will change the listbox's selection. That is, if you click the mouse on item #1, and then drag over item #2, it will deselect item #1 and select item #2 instead. How can I prevent this?

这是简短的版本.稍长的版本是这样的:当用户双击我的 ListBox 中的一个项目时,我对我的布局进行了其他更改,其中包括在 ListBox 上方显示其他控件.这会将 ListBox 向下移动,这意味着鼠标现在位于与用户双击时不同的 ListBoxItem 上.

That's the short version. The slightly longer version is this: When the user double-clicks an item in my ListBox, I make other changes to my layout, which includes showing other controls above the ListBox. This moves the ListBox downwards, which means the mouse is now positioned over a different ListBoxItem than it was when the user double-clicked.

由于我为响应 DoubleClick 事件(这是一个鼠标按下事件)进行了这些布局更改,因此很可能在此布局更改完成时仍会按下鼠标按钮,这意味着 WPF 将向 ListBox 发送一个MouseMove 事件(因为鼠标相对于 ListBox 的位置已经改变).ListBox 将此视为拖动,并选择现在位于鼠标下的事件.

Since I make these layout changes in response to the DoubleClick event (which is a mouse-down event), it's very likely that the mouse button will still be pressed when this layout change completes, which means WPF will send the ListBox a MouseMove event (since the mouse's position, relative to the ListBox, has changed). ListBox treats this as a drag, and selects the event that's now under the mouse.

我不希望选择在我获得双击事件和用户释放鼠标的时间之间发生变化(这可能是在布局更改之后).我怀疑实现这一点的最简单方法是禁用拖动时更改选择"行为,但我愿意接受其他建议.

I don't want the selection to change between the time I get the double-click event and the time the user releases the mouse (which might be well after the layout changes). I suspect that the simplest way to achieve this would be to disable the "change selection on drag" behavior, but I'm open to other suggestions.

我怎样才能在双击时锁定"选择,并防止它在 mouseup 之前改变?

How can I "lock in" the selection on double-click, and prevent it from changing until mouseup?

推荐答案

ILSpy 中进行了一番挖掘后,我发现没有禁用拖动选择"行为的属性,也没有我可以标记为已处理的事件来停止它.

After some digging around in ILSpy, I found that there's no property that disables the "drag to select" behavior, nor is there an event I can mark as Handled to stop it.

但是改变这种行为有一个很好的转折点:ListBoxItem.OnMouseEnter 是虚拟的,它回调到列表框以改变选择.它似乎没有做任何其他实质性的事情,所以我需要做的就是覆盖它并且什么都不做.

But there is a good inflection point for changing this behavior: ListBoxItem.OnMouseEnter is virtual, and it calls back into the listbox to change the selection. It doesn't seem to do anything else substantive, so all I need to do is override it and do nothing.

事实证明,上面的内容只会在您在列表框内移动鼠标时防止选择发生变化.如果您将鼠标移动到列表框的上方或下方,这将无济于事——然后自动滚动启动并移动选择.大多数自动滚动代码又是在非虚拟方法中;看起来防止自动滚动的最佳方法可能是禁用鼠标捕获.ListBoxItem 上的另一个覆盖可以解决这个问题.

As it turns out, the above only keeps the selection from changing while you move the mouse around inside the listbox. It doesn't help if you move the mouse above or below the listbox -- then the auto-scroll kicks in and moves the selection. Most of the auto-scroll code is again in non-virtual methods; it looks like the best way to prevent auto-scroll is probably to disable mouse capture. Another override on ListBoxItem can take care of this.

看起来使用我自己的 ListBoxItem 后代的最佳方法是从 ListBox 下降.最终代码如下所示:

It looks like the best way to use my own ListBoxItem descendant is to descend from ListBox. The final code looks something like this:

public class ListBoxEx : ListBox
{
    protected override DependencyObject GetContainerForItemOverride()
    {
        return new ListBoxExItem();
    }
    protected override bool IsItemItsOwnContainerOverride(object item)
    {
        return item is ListBoxExItem;
    }
}
public class ListBoxExItem : ListBoxItem
{
    private Selector ParentSelector
    {
        get { return ItemsControl.ItemsControlFromItemContainer(this) as Selector; }
    }

    protected override void OnMouseEnter(MouseEventArgs e)
    {
    }
    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
        base.OnMouseLeftButtonDown(e);
        ParentSelector?.ReleaseMouseCapture();
    }
}

这篇关于防止 WPF ListBox 在布局更改时选择鼠标下的项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆