Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/297.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用异步连续更新GUI_C#_Wpf_Asynchronous_Async Await - Fatal编程技术网

C# 如何使用异步连续更新GUI

C# 如何使用异步连续更新GUI,c#,wpf,asynchronous,async-await,C#,Wpf,Asynchronous,Async Await,刚刚创建了一个WPF项目.NET4.6 把这个代码放进去 lbl1是GUI上的标签 但是标签从未更新,或者while循环仅继续1次 private void Button_Click_1(object sender, RoutedEventArgs e) { var t = Task.Run( async () => { await AsyncLoop(); }); }

刚刚创建了一个WPF项目.NET4.6

把这个代码放进去

lbl1
是GUI上的标签

但是标签从未更新,或者while循环仅继续1次

        private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        var t = Task.Run(
       async () =>
      {
           await AsyncLoop();
       });

    }

    async Task AsyncLoop()
    {
        while (true)
        {
            string result = await LoadNextItem();
            lbl1.Content = result;
        }
    }

    private static int ir11 = 0;
    async Task<string> LoadNextItem()
    {
        ir11++;
        return "aa " + ir11;
    }
private void按钮\u单击\u 1(对象发送者,路由目标)
{
var t=Task.Run(
异步()=>
{
等待异步循环();
});
}
异步任务AsyncLoop()
{
while(true)
{
字符串结果=等待LoadNextItem();
lbl1.内容=结果;
}
}
私有静态int ir11=0;
异步任务LoadNextItem()
{
ir11++;
返回“aa”+ir11;
}

请使用user Application.Current.Dispatcher.Invoke访问ui线程

async Task AsyncLoop()
    {
        while (true)
        {
            string result = await LoadNextItem();
Application.Current.Dispatcher.Invoke(new Action(() => {  lbl1.Content = result; }));

        }
    }
C#编译器会给你一个警告,告诉你问题出在哪里

具体而言,此方法不是异步的:

async Task<string> LoadNextItem()
{
  ir11++;
  return "aa " + ir11;
}
或者,如果您没有异步操作,而是有一些紧密的CPU绑定循环,则可以通过
任务将这些循环推送到后台线程。运行

string LoadNextItem()
{
  ir11++;
  return "aa " + ir11;
}

while (true)
{
  string result = await Task.Run(() => LoadNextItem());
  lbl1.Content = result;
}

通过调用Task.Run,您断开了与GUI线程(或WPF调度程序)的关联(SynchronizationContext),并丢失了大部分async/await“goodness”

为什么不使用一个异步void事件处理程序,并为每个步骤返回SynchronizationContext(GUI线程/调度程序)

private async void Button_Click_1(object sender, RoutedEventArgs e)
{
    while (true)
    {
        string result = await LoadNextItem();
        lbl1.Content = result;
    }
}

private static int ir11 = 0;
Task<string> LoadNextItem()
{
    await Task.Delay(1000); // placeholder for actual async work
    ir11++;
    return "aa " + ir11;
}
private async void按钮\u单击\u 1(对象发送方,RoutedEventArgs e)
{
while(true)
{
字符串结果=等待LoadNextItem();
lbl1.内容=结果;
}
}
私有静态int ir11=0;
任务LoadNextItem()
{
等待任务。延迟(1000);//实际异步工作的占位符
ir11++;
返回“aa”+ir11;
}
或者,如果您确实想为“正在进行的”操作分离状态机,请尝试传递一个
IProgress
(在这种情况下,默认的impl.
Progress
或具体的
Progress
应该可以很好地工作)。看

他的例子与你在问题中所说的非常接近。我把它复制到这里是为了保持独立

public async void StartProcessingButton_Click(object sender, EventArgs e)
{
  // The Progress<T> constructor captures our UI context,
  //  so the lambda will be run on the UI thread.
  var progress = new Progress<int>(percent =>
  {
    textBox1.Text = percent + "%";
  });

  // DoProcessing is run on the thread pool.
  await Task.Run(() => DoProcessing(progress));
  textBox1.Text = "Done!";
}

public void DoProcessing(IProgress<int> progress)
{
  for (int i = 0; i != 100; ++i)
  {
    Thread.Sleep(100); // CPU-bound work
    if (progress != null)
      progress.Report(i);
  }
}
public async void StartProcessingButton\u单击(对象发送方,事件参数e)
{
//进度构造函数捕获我们的UI上下文,
//因此lambda将在UI线程上运行。
变量进度=新进度(百分比=>
{
textBox1.Text=百分比+“%”;
});
//DoProcessing在线程池上运行。
等待任务。运行(()=>DoProcessing(progress));
textBox1.Text=“完成!”;
}
公共无效数据处理(IProgress progress)
{
对于(int i=0;i!=100;++i)
{
Thread.Sleep(100);//CPU绑定的工作
如果(进度!=null)
进度报告(一);
}
}

Edit:我必须承认,虽然
Progress
是一个很好的抽象,但在本例中,它将落在Dispatcher.调用@Pamparanpa建议的调用上。

的可能重复;具体看,我明白了。所以它实际上抛出了一个无声的错误,因此停止了。有没有办法快速键入或复制粘贴?Application.Current.Dispatcher.Invoke(新操作(()=>{是的,您可以在wpf中直接从另一个线程访问ui线程。这是等到ui更新后才进行的吗?还是仅仅是调度程序调用并立即返回?这是一个非阻塞操作。它可以工作,但错过了对async/await的固有支持,即在等待之后“返回”ui线程。在上述函数中等待的唯一优点是值得注意的是,在LoadNextItem上“等待”时,不会占用线程池线程。这是相当可观的,但在这种情况下,不会“完全”使用它。
public async void StartProcessingButton_Click(object sender, EventArgs e)
{
  // The Progress<T> constructor captures our UI context,
  //  so the lambda will be run on the UI thread.
  var progress = new Progress<int>(percent =>
  {
    textBox1.Text = percent + "%";
  });

  // DoProcessing is run on the thread pool.
  await Task.Run(() => DoProcessing(progress));
  textBox1.Text = "Done!";
}

public void DoProcessing(IProgress<int> progress)
{
  for (int i = 0; i != 100; ++i)
  {
    Thread.Sleep(100); // CPU-bound work
    if (progress != null)
      progress.Report(i);
  }
}