当布局更改时,防止WPF ListBox在鼠标下选择项目

Joe*_*ite 4 wpf listbox selecteditem mousemove

如果按住鼠标按钮时WPF ListBox获取MouseMove事件,它将更改列表框的选择.也就是说,如果在项目#1上单击鼠标,然后在项目#2上拖动,它将取消选择项目#1并选择项目#2.我怎么能阻止这个?

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

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

我不希望选择在我获得双击事件和用户释放鼠标的时间(布局更改后可能会很好)之间进行更改.我怀疑实现这一目标的最简单方法是禁用"拖动更改选择"行为,但我对其他建议持开放态度.

如何在双击时"锁定"选择,并防止它更改直到鼠标?

Joe*_*ite 17

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

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

编辑:事实证明,上面只是在您在列表框内移动鼠标时保持选择不变.如果将鼠标移动到列表框的上方或下方,则无效 - 然后自动滚动并启动选择.大多数自动滚动代码再次采用非虚方法; 看起来防止自动滚动的最佳方法可能是禁用鼠标捕获.ListBoxItem上的另一个覆盖可以解决这个问题.

看起来使用我自己的ListBoxItem后代的最好方法是从ListBox下载.最终代码看起来像这样:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)