Убить асинхронную задачу c #, wpf - PullRequest
0 голосов
/ 05 мая 2019

В моем приложении у меня есть класс PrimaryViewModel (абстрактный) и каждый ViewModel наследовать от него. Чтобы получать данные каждые X секунд, я написал следующий виртуальный метод

 protected virtual async void RunSynchronizeTask()
    {
        await Task.Run(() =>
        {
            while (true)
            {
                Thread.Sleep(RefreshTime);
                if (DateTime.Now.TimeOfDay - LastSyncrhonization.TimeOfDay > RefreshTime)
                {
                    Application.Current.Dispatcher.Invoke(delegate
                    {
                        GetDataAndRefreshUI();
                    });
                    LastSyncrhonization = DateTime.Now;
                }
            }
        });
    }

Таким образом, у каждого viewModel есть свой метод и своя задача, которая будет получать данные из БД и обновлять привязанные элементы управления (например, messageViewModel обновляет список сообщений каждые 0,5 секунды)

но проблема в том, что когда я запускаю выпущенное приложение (без режима отладки, просто собираю как выпуск и открываю exe) и закрываю, приложение закрывается, но эта асинхронная задача все еще работает (я вижу это в диспетчере задач)

Что мне делать? Как назначить эту задачу на что-то, я не могу сделать: var task = await.Task.Run (...)

Если бы я мог, я бы создал какой-то статический список со ссылками на эти задачи, и при закрытии приложения я бы убил их или что-то ...

Ответы [ 2 ]

3 голосов
/ 05 мая 2019

Вы переходите от async void к Task.Run(), что удваивается.
И тогда вы делаете фактическую работу в Dispatcher.Invoke()

Единственное, что действительно является асинхронным (параллельным), это Thread.Sleep().

Таким образом, вы можете заменить все это DispatcherTimer. Это должно вылечить и твою проблему.

0 голосов
/ 05 мая 2019

Спасибо, Фабиан!отлично работает с токеном отмены:

  protected virtual async void RunSynchronizeTask()
        {
            var cancelationToken = new CancellationToken();
            App.TaskToDisposeTokens.Add(cancelationToken);
            await Task.Run(() =>
            {
                try { 
                while (true)
                {
                    Thread.Sleep(RefreshTime);
                    if (DateTime.Now.TimeOfDay - LastSyncrhonization.TimeOfDay > RefreshTime)
                    {
                        Application.Current.Dispatcher.Invoke(delegate
                        {
                            GetDataAndRefreshUI();
                        });
                        LastSyncrhonization = DateTime.Now;
                    }
                }
                }
                catch(OperationCanceledException) { }
            }, cancelationToken);

        }

App.Cs

 private void Application_Exit(object sender, ExitEventArgs e)
        {
            foreach(var token in TaskToDisposeTokens)
            {
                token.ThrowIfCancellationRequested();
            }
        }

и в App.Xaml

<Application x:Class="RandevouWpfClient.App"
           ...
             Exit="Application_Exit">
...