Запретить WPF ListBox от выбора элемента под мышью при изменении макета - PullRequest
2 голосов
/ 14 апреля 2011

Если WPF ListBox получает событие MouseMove, пока кнопка мыши удерживается нажатой, это изменит выбор списка.То есть, если щелкнуть мышью на элементе № 1, а затем перетащить элемент № 2, он отменит выбор элемента № 1 и выберет элемент № 2. Как я могу предотвратить это?

Это короткая версия.Немного более длинная версия такова: когда пользователь дважды щелкает элемент в моем ListBox, я делаю другие изменения в моем макете, включая отображение других элементов управления над ListBox.Это перемещает ListBox вниз, что означает, что мышь теперь расположена над другим ListBoxItem, чем он был при двойном щелчке пользователя.

Поскольку я делаю эти изменения макета в ответ на событие DoubleClick (которое представляет собой мышь-down), весьма вероятно, что кнопка мыши будет по-прежнему нажата, когда это изменение макета завершится, что означает, что WPF отправит ListBox событие MouseMove (поскольку позиция мыши относительно ListBox изменилась).ListBox обрабатывает это как перетаскивание и выбирает событие, которое теперь находится под мышью.

Я не хочу, чтобы выбор менялся между временем получения события двойного щелчка и временем, когда пользователь отпускает мышь(что может быть хорошо после изменения макета).Я подозреваю, что самый простой способ добиться этого - отключить поведение «изменить выделение при перетаскивании», но я открыт для других предложений.

Как можно «заблокировать» выделение при двойном щелчке, и помешать ему поменяться до mouseup?

1 Ответ

15 голосов
/ 15 апреля 2011

После некоторого поиска в 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();
    }
}
...