Переполнение стека WPF Treeview, если событие SelectionChanged срабатывает слишком быстро? - PullRequest
1 голос
/ 09 февраля 2010

У меня есть TreeView с 1000 предметов. Когда я выбираю элемент, TreeView запускает событие, чтобы я мог что-то обновить в своем графическом интерфейсе. Обработчик событий не рекурсивный и не имеет циклов, но для его завершения требуется немного времени, может быть, 100 мс.

Если я выбираю верхний элемент и использую стрелку вниз для медленной прокрутки элементов, все работает нормально, но если я удерживаю клавишу со стрелкой, событие запускается слишком быстро и я получаю исключение stackoverflow.

Я думал о включении таймера в TreeView, чтобы событие SelectionChanged могло срабатывать только каждые 100 мс или около того, но это выглядит очень хакерским. Любые идеи для исправления этого?

Ответы [ 2 ]

3 голосов
/ 09 февраля 2010

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

Таким образом, у вас есть обработчик событий, который выполняет таймер. Таймер сбрасывается всякий раз, когда срабатывает событие selectedlected. Ваш таймер может быть, возможно, 500 мс, поэтому, если выбранное значение все еще выбрано после 500 мс, он сгенерирует ваш фактический код события, который вам нужно обработать.

Не сказать, что это лучший способ, как я видел это в окнах.

1 голос
/ 09 февраля 2010

Запуск обработчика событий асинхронно. Простейший способ сделать это заключается в следующем:

void SelectionEventHandler(object sender, EventArgs e)
{
    var ownerElement = sender as FrameworkElement; // this should be the TreeView itself
    ThreadPool.QueueUserWorkItem(o => {

        // Do stuff 

        ownerElement.Dispatcher.BeginInvoke(new Action(() => {

            // Update UI in response to stuff being done

        });
    });
}

Если вы используете что-то вроде Reactive Framework , тогда вы можете значительно сократить расходы, связанные с ThreadPools и т. Д.

Вы можете также рассмотреть библиотеку Parallel Task с ее классом Task<T> - Вы можете получить версию .NET 3.5, загрузив реактивную платформу.

ПРИМЕЧАНИЕ. Асинхронный запуск обработчика должен остановить переполнение стека, однако он не остановит выполнение обработчика 1000 раз, когда пользователь свернет список. Если вы хотите сделать это, вы можете либо внедрить таймер задержки, либо если вы используете Reactive Framework, у него есть некоторые функции, которые могут помочь вам в этом.

...