Listview SelectedIndexChanged с MessageBox запускает ItemDrag

У меня есть ListView с обработчиками событий SelectedIndexChanged и ItemDrag. Если я открываю MessageBox в SelectedIndexChanged, он запускает ItemDrag.

Проблему легко воспроизвести, создав список с некоторым элементом и поставив MessageBox в SelectedIndexChanged, а точку останова в метод ItemDrag.

private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{        
        MessageBox.Show("Selected Index Changed");
}

private void listView1_ItemDrag(object sender, ItemDragEventArgs e)
{
}

Любые предложения о том, почему это происходит?


person andreat    schedule 03.10.2014    source источник
comment
откуда вы знаете, что он запускает ItemDrag? Кода там нет.   -  person Ňɏssa Pøngjǣrdenlarp    schedule 03.10.2014
comment
Да в образце кода, без кода; но в реальном проекте у меня есть код для dnd. Дело в том, что после закрытия окна сообщения listview запускает перетаскивание элементов?   -  person andreat    schedule 03.10.2014


Ответы (1)


Я вижу это. Уведомление приходит прямо из Windows, .NET не задействован. Такого рода проблемы, вызванные MessageBox, не редкость, они вызывают проблемы с повторным входом, которые очень похожи на страдания, вызванные печально известным методом DoEvents(). ListView просто не был написан так, чтобы предположить, что его событие SelectedIndexChanged делает что-то настолько резкое.

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

Существует универсальное решение для таких проблем с повторным входом, которое также работает для решения этой проблемы. Подход состоит в том, чтобы отложить отображение диалогового окна, ожидая, пока событие будет отправлено и обработано элементом управления, а код внутри ListView перестанет быть активным. Это можно сделать с помощью таймера, но самый элегантный способ — использовать метод BeginInvoke():

    private void listView1_SelectedIndexChanged(object sender, EventArgs e) {
        this.BeginInvoke(new Action(() => MessageBox.Show("Okay now")));
    }
person Hans Passant    schedule 04.10.2014