DispatcherTimer не срабатывает в приложении wpf

Недавно я реорганизовал свой код WPF, и теперь мой DispatcherTimer перестал срабатывать. Я проверил другие подобные сообщения здесь, но все они казались проблемами с неправильным набором потока диспетчера, который я пробовал...

Мой код выглядит так:

class MainWindow : Window
{
    private async void GoButton_Click(object sender, RoutedEventArgs e)
    {
        Hide();

        m_files = new CopyFilesWindow();
        m_files.Show();

        m_dispatcherTimer = new DispatcherTimer();
        m_dispatcherTimer.Tick += dispatcherTimer_Tick;
        m_dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 250);
        m_dispatcherTimer.Start();

        await SomeLongRunningTask();

        m_files.Hide();
        Show();
    }

(Текущий класс — это мой основной объект Window, который я скрываю на время копирования файла. CopyFilesWindow — это простое окно Xaml, содержащее элементы управления, которые я изменяю... CopyFilesWindow сам по себе абсолютно ничего не делает.)

По сути, я ожидаю длительной задачи (копирования большого количества файлов), и мой DispatcherTimer должен обновлять ход выполнения в dispatcherTimer_Tick. Однако я установил точку останова для этой функции, и она не сработала.

Я также попытался установить Dispatcher с помощью конструктора следующим образом:

        m_dispatcherTimer = new DispatcherTimer(DispatcherPriority.Normal, m_files.Dispatcher);
        m_dispatcherTimer = new DispatcherTimer(DispatcherPriority.Normal, this.Dispatcher);

Но ни одна из этих вещей не меняет поведение... он по-прежнему не срабатывает.

Что я здесь делаю неправильно?


person LCC    schedule 21.07.2013    source источник


Ответы (1)


DispatcherTime работает в потоке ... Dispatcher. Который застрял в ожидании SomeLongRunningTask() завершения.

Действительно, когда вы нажимаете кнопку Go, поток диспетчера выполняет GoButton_Click. Таким образом, вы никогда не должны вызывать метод из пользовательского интерфейса (потока диспетчера) async.

private void GoButton_Click(object sender, RoutedEventArgs e)
{
    Hide();

    m_files = new CopyFilesWindow();
    m_files.Show();

    m_dispatcherTimer = new DispatcherTimer();
    m_dispatcherTimer.Tick += dispatcherTimer_Tick;
    m_dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 250);
    m_dispatcherTimer.Start();

    SomeLongRunningTask.ContinueWith(() => 
    {
        // Executes this once SomeLongRunningTask is done (even if it raised an exception)
        m_files.Hide();
        Show();
    }, TaskScheduler.FromCurrentSynchronizationContext());  // This paramater is used to specify to run the lambda expression on the UI thread.
}
person Cédric Bignon    schedule 21.07.2013
comment
Спасибо! То, как я структурировал свой код, сделало непрактичным использование ContinueWith (приведенный выше код — просто упрощение того, что я делаю). Однако перемещение всего содержимого GoButton_Click в собственный асинхронный метод (и отмена пометки GoButton_Click как асинхронного) с несколькими другими незначительными изменениями устранило проблему. Я не осознавал, что «ожидаю» в потоке диспетчера... Как только я понял, что проблема была в этом, было легко переместить работу в другой поток. - person LCC; 22.07.2013