【问题标题】:Is this the right way of chaining async calls (C#/WPF)?这是链接异步调用(C#/WPF)的正确方法吗?
【发布时间】:2021-01-18 22:42:19
【问题描述】:

经过:

https://docs.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming

How to bind WPF button to a command in ViewModelBase?

我想出了以下异步(或同步?)读取文件内容并将其呈现到窗口的代码:

class AppliedJobsViewModel
{
    private TexParser texParser; 

    private ICommand _openTexClick;
    public ICommand OpenTexClick
    {
        get
        {
            return _openTexClick ?? (_openTexClick = new CommandHandler(() => ReadAndParseTexFile(), () => CanExecute));
        }
    }
    public bool CanExecute
    {
        get
        {
            // check if executing is allowed, i.e., validate, check if a process is running, etc. 
            return true;
        }
    }

    public async Task ReadAndParseTexFile()
    {
        if (texParser == null)
        {
            texParser = new TexParser();
        }
        // Read file asynchronously here
        await ReadAndParseTexFileAsync();            
        string[][] appliedJobs = texParser.getCleanTable();
    }

    private async Task ReadAndParseTexFileAsync()
    {
        texParser.ReadTexFile();
        await Task.Delay(100);
    }

    public ObservableCollection<AppliedJob> AppliedJobs {
        get;
        set;
    }
}

哪个“有效”,但我不喜欢 Task.Delay(100)(恒定等待时间)。

VS 也在线告诉我:

    return _openTexClick ?? (_openTexClick = new CommandHandler(() => ReadAndParseTexFile(), () => CanExecute));

“因为没有等待这个调用,所以在调用完成之前这个方法的执行还在继续”。

但是这种方法将代码绑定到 wpf 视图。默认不是异步的吗?

【问题讨论】:

  • CommandHandler 是什么?
  • 一个路由点击(或任何形式的用户交互)的类。取自(复制)自stackoverflow.com/questions/12422945/…
  • 看来CommandHandler 只是实现了ICommand 类似中继命令的接口。它同时执行传递的Action。要进行异步执行,您可以使用 async relay command 或在 xaml 中设置 IsAsync
  • 谢谢!我会试一试。你知道Task.Delay(100);的方法吗?
  • 我认为没有理由在代码中使用 await Task.Delay(100)。如果您需要一些延迟,绑定中有Delay 属性

标签: c# wpf multithreading asynchronous async-await


【解决方案1】:

只是在方法或任务签名中删除异步并不意味着您正在异步执行任何操作。

阅读:

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/using-async-for-file-access

请注意,这不仅仅是在名称中添加异步的情况,而是使 File.ReadAllTextAsync 异步。

您应该阅读异步和等待。 例如 https://blog.stephencleary.com/2012/02/async-and-await.html

这是一个复杂的主题。需要仔细阅读和思考才能理解。

阅读完之后,请重新考虑您的代码。

在那个警告中,你的 ide 告诉你你的代码是同步的。

你有同步代码在那里读取该文件。

在其中粘贴 await some-other-code 不会使您的文件读取代码异步,这只是意味着 ide 看到了 await 任务。无意义的等待任务。

现在你知道这是没有意义的。

取出

await Task.Delay(100);

替换你的文件读取代码
 string contents = await File.ReadAllTextAsync(filePath); 

可以使文件异步读取。

如果这是一个被读入内存的大文件,那么仅仅读取它可能会产生很大的开销,并且您的 UI 可能会保持响应。

如果您正在对文件进行一些实质性处理,那么您可能会更好地将其推送到后台线程。

你可以的

 await Task.Run(() => ProcessFileText(someurl));

这里 ProcessFileText 将是一个 Task 或者 Task 并返回一个字符串或字符串数​​组。它将在后台线程上运行并在完成后返回。 由于这是一个不同的线程,因此如果需要一段时间才能完成工作,它不会冻结您的 UI。

请注意,由于它现在不在 UI 线程上,因此此任务无法读取或写入 UI 属性,否则您会遇到线程错误。 等待之后的行中的代码返回到 ui 线程。

【讨论】:

    猜你喜欢
    • 2014-12-17
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-26
    • 1970-01-01
    相关资源
    最近更新 更多