【问题标题】:Async Await Stops... C# WPF异步等待停止... C# WPF
【发布时间】:2015-09-16 17:35:40
【问题描述】:

我有一个函数,它获取 Func 作为参数并在异步方法中的任务内部执行它,以便在函数工作时显示不确定的进度条......

private async void Invoke(Func<string> function)
{
       if(calculation?.Status == TaskStatus.Running) await calculation;
       calculation = Task.Run(function);
       InvokeA(() => prg.Height = double.NaN);
       InvokeA(() => prg.Visibility = Visibility.Visible);
       Result = await calculation;
       InvokeA(() => prg.Visibility = Visibility.Hidden);
       InvokeA(() => prg.Height = 0);
}

问题是函数何时到达:

Result = await Calculation;

它有点停止......它永远不会真正设置值或关闭进度条。

如果键为 Enter,则从 Textbox.KeyDown 方法调用 Invoke:

if (SpecialCommands.DoesExist(Text))
    {
          Invoke(() => SpecialCommands.Invoke(Parameter));
          if (!string.IsNullOrEmpty(Result)) Text += $"   --->   {Result}";
     }

变量定义:

calculation = Task<string>
Result = string
prg = ProgressBar
Parameter = string that isn't connected to the UI

【问题讨论】:

  • 搜索“async Task.Run on GUI thread”你会找到死锁的原因。
  • calculation 设置在哪里,它的类型是什么?通常,您会使用 await 关键字以及 async 方法的实际调用。
  • 请提供演示问题的示例代码,而不是感谢信(已删除)。您到目前为止显示的代码应该可以工作。还要确保在“它刚刚停止”时显示一堆有趣的阅读,并在更新帖子时查看有关“C# async Wait deadlock”的类似帖子。
  • 旁注:当您谈论程序时,“crash”和“stops”通常是不同的东西。 “停止”的同义词是“冻结”; “崩溃”通常意味着异常/终止。
  • @JamesWright 计算是一个任务,结果是一个字符串

标签: c# wpf asynchronous task


【解决方案1】:

我使用以下 XAML 创建了一个标准的新 WPF 应用程序项目

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Canvas>
        <Button x:Name="button" Content="Button" Canvas.Left="62" Canvas.Top="40" Width="75" Click="button_Click"/>
        <ProgressBar x:Name="prg" Height="23" Canvas.Left="62" Canvas.Top="265" Width="347" IsIndeterminate="True"/>
    </Canvas>
</Window>

和后面的代码

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    Task<string> calculation;
    string Result;
    string Text;

    private async void button_Click(object sender, RoutedEventArgs e)
    {
        await Invoke(() => Foo());
        if (!string.IsNullOrEmpty(Result)) Text += $"   --->   {Result}";
    }

    private async Task Invoke(Func<string> function)
    {
        if (calculation?.Status == TaskStatus.Running) await calculation;
        calculation = Task.Run(function);
        InvokeA(() => prg.Height = double.NaN);
        InvokeA(() => prg.Visibility = Visibility.Visible);
        Result = await calculation;
        InvokeA(() => prg.Visibility = Visibility.Hidden);
        InvokeA(() => prg.Height = 0);
    }

    private void InvokeA(Action a) { a(); }

    static string Foo()
    {
        Thread.Sleep(5000);
        return "Bar";
    }
}

它按预期工作。所以问题出在你提供的其他地方。

编辑根据您的评论,值得尝试以下操作,因为那是您代码的不正确部分:

首先,将Invoke方法的签名改为

private async Task Invoke(Func<string> function)

然后使用

await Invoke(() => Foo());
if (!string.IsNullOrEmpty(Result)) Text += $"   --->   {Result}";

希望对您有所帮助。

【讨论】:

  • 在调试和更改了一些东西之后,我仍然遇到了问题,但现在我看到调用方法已执行,并且我调用它之后的行没有被执行...Invoke(() =&gt; Foo()); 这是执行,if (!string.IsNullOrEmpty(Result)) Text += $" ---&gt; {Result}";这不是
  • 哈,那是因为Result 为空或为空!
  • 不是这样,我不是说Text 没有改变,我的意思是调试器只是跳过了if 的整行,它甚至没有检查它。 ..
  • 那我也没什么想法了。正如您可能已经看到的那样,我的两个测试样本都可以正常工作。祝你好运!
  • 实际上我尝试像您在编辑中所做的那样更改方法签名,现在一切正常...
猜你喜欢
  • 2013-02-26
  • 2021-12-22
  • 2017-04-17
  • 1970-01-01
  • 1970-01-01
  • 2018-08-13
  • 2019-07-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多