【发布时间】:2021-09-20 23:14:00
【问题描述】:
我目前正在尝试编写一个简单的 C#-WPF-Application 来作为一个简单的通用“启动器”。我们针对不同的应用程序进行编程。
其目的是检查“真实”软件的当前软件版本,如果有新版本可用,它会开始从网络共享复制安装程序,然后运行安装程序。 然后它启动“真正的”应用程序,仅此而已。
用户界面主要由一个启动窗口组成,它向用户显示当前执行的操作(版本检查、复制、安装、启动...)。
现在我在 App.cs 中重写的 StartUp 方法中创建我的视图和我的 viewModel
public override OnStartup(string[] args)
{
var viewModel = new StartViewModel();
var view = new StartView();
view.DataContext = viewModel;
view.Show();
// HERE the logic for the Launch starts
Task.Run(() => Launch.Run(args));
}
问题是,如果我不在这里异步,主线程将被阻塞,我无法更新 UI。因此我使用Task.Run(...) 让它工作。这解决了我阻塞 UI 线程的问题,但我对此有一些问题/疑问:
- 我不能等待任务,因为这会再次阻塞 UI。在哪里等待呢?
- 首先我在此处启动此工作流程的想法是否可行?
一些更新澄清:在我向用户展示 UI 后,我的逻辑开始执行繁重的 IO 工作。我想出的可能调用有以下 3 个变体:
view.Show();
// v1: completely blocks the UI, exceptions are caught
DoHeavyIOWork();
// v2: doesn't block the UI, but exceptions aren't caught
Task.Run(() => DoHeavyIOWork());
// v3: doesn't block the UI, exceptions are caught
await Task.Run(() => DoHeavyIOWork());
目前我不在我的工作电脑上,所以我很抱歉没有给你原始代码。这是一个即时创建的版本。
我猜 v1 和 v2 不好,因为异常和 UI 阻塞。
当我在办公室尝试 v3 时,我认为它不起作用。现在它似乎适用于我的本地示例。但是我真的不确定v3。因为我在那里使用async void StartUp(...)。这里可以吗?
【问题讨论】:
-
我通常使用 ViewModel 参数制作一个 View ctor,而不是在 View 类之外设置 DataContext。此外,我将在您制作“view.Show()”之前运行该任务,我不调用“view.Show()”,而是调用“Run(view)”。但是,是的,看起来不错(至少对我来说)
-
你为什么不能
awaitTask?would block the UI again是什么意思?代码中的Task.Run()正在线程池上排队一个新的Thread并以即发即弃的方式执行它。您的代码不会等待Launch.Run()完成,因为您不是awaitingTask.Run()。如果应该在OnStartup()执行之后的代码之前完成Launch.Run(),这可能会导致问题。 -
您似乎正在尝试重新发明ClickOnce 技术:"ClickOnce 应用程序可以自我更新。它们可以在新版本可用时检查并自动替换任何更新的文件. 根据安装类型,ClickOnce 提供了几个更新选项。应用程序可以配置为在启动时或启动后检查更新。" Deploy a .NET Windows desktop application using ClickOnce
-
关于“ClickOnce”:在我的设置中,我们有许多机器运行我们的软件,但它用于生产设置,用户可以而且不应该接受或拒绝安装。此外,不同的机器有时必须运行不同版本的软件。我只是不知道 ClickOnce 是否是那里的最佳选择。
-
@FlyingHubert stackoverflow.com/questions/20859048/…
标签: c# wpf async-await task