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

时间:2011-04-14 18:40:10

标签: wpf listbox selecteditem mousemove

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

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

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

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

如何在双击时“锁定”选择,并防止它在鼠标上改变?

1 个答案:

答案 0 :(得分:15)

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