使用WPF杀死异步任务C#

时间:2019-05-05 07:45:45

标签: c# asynchronous task

在我的应用程序中,我有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 个答案:

答案 0 :(得分:3)

您从async void转到Task.Run(),这是原来的两倍。
然后,您可以在Dispatcher.Invoke()

中进行实际工作

这里唯一真正异步(并发)的是Thread.Sleep()

因此,您可以使用DispatcherTimer替换所有这些。那也应该解决您的停顿问题。

答案 1 :(得分:0)

感谢Fabian!  与取消令牌配合使用效果很好:

  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">