Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.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# Dispatcher.BeginInvoke()未异步运行_C#_Wpf_Asynchronous_Task_Dispatcher - Fatal编程技术网

C# Dispatcher.BeginInvoke()未异步运行

C# Dispatcher.BeginInvoke()未异步运行,c#,wpf,asynchronous,task,dispatcher,C#,Wpf,Asynchronous,Task,Dispatcher,以下是我想做的一个简化版本: 单击按钮,将异步运行aNewMethod(),以保持UI响应。就这样 我读了一些答案,下面是我能想到的: private async void button_Click(object sender, RoutedEventArgs e) { Task task = Task.Run(() => aNewMethod()); await task; } private void aNewMetho

以下是我想做的一个简化版本:

单击
按钮
,将异步运行
aNewMethod()
,以保持UI响应。就这样

我读了一些答案,下面是我能想到的:

    private async void button_Click(object sender, RoutedEventArgs e)
    {
        Task task = Task.Run(() => aNewMethod());
        await task;
    }

    private void aNewMethod()
    {
        if (progress.Value == 0)
        {
            //Heavy work
            for (int i = 1; i < 1000000000; i++) { }
            progress.Value = 100;
        }
    }
这解决了
系统.invalidoOperationException
问题,但它没有异步运行,因为UI仍然冻结在
for loop


所以问题是:如何运行
aNewMethod()异步且仍然更新并与UI控件交互?

调度程序在UI线程中运行。它处理您的UI,并执行您通过BeginInvoke等传递给它的操作。 但它一次只能处理一件事;当它忙于处理您的操作时,它不会同时更新UI,因此UI会同时冻结

如果您想保持UI的响应性,您需要在一个单独的非UI线程中运行重载函数。在另一个线程上运行的那些函数中,您可以在需要访问UI时调用dispatcher—理想情况下,只是为了更新UI元素而非常简短

换句话说,您希望在单独的线程中运行sleep函数,然后在需要设置进度值时从自己的线程调用调度程序。差不多

private void button_Click(object sender, RoutedEventArgs e)
{
    Task task = Task.Run(() => aNewMethod());  // will call aNewMethod on the thread pool
}

private void aNewMethod()
{
    double progressValue = 0;
    Dispatcher.Invoke(() => progressValue = progress.Value);

    if (progressValue == 0)
    {
        Thread.Sleep(3000); // still executes on the threadpool (see above), so not blocking UI
        Dispatcher.Invoke(() => progress.Value = 100 );  // call the dispatcher to access UI
    }
}

对于当前的实现,不需要使用
Thread.Start
,因为在该方法中,您只需将其休眠一段时间,然后访问那里不允许的UI线程对象 。在您的场景中,更好的方法是不要使用
Thread.Sleep
,而应该使用类似的:

现在您不需要
Dispatcher.Invoke
,而
async
await
关键字,因为await之后的语句将在我们进行异步调用的同一调用同步上下文中执行,在本例中,异步调用是UI线程

单击按钮后,aNewMethod()将异步运行以保持UI响应

实际上,它是在后台线程上同步运行的<代码>任务。运行
非常适合于此

通过谷歌搜索,我了解到我需要一个Dispatcher.BeginInvoke()方法来更新/使用UI控件

不幸的是,这是谷歌肯定会误导你的一个领域<代码>调度程序不是这里的最佳解决方案

相反,您应该使用
IProgress
/
Progress
,如下所示:

private async void button_Click(object sender, RoutedEventArgs e)
{
  var progress = new Progress<int>(value => { this.progress.Value = value; });
  await Task.Run(() => aNewMethod(progress));
}

private void aNewMethod(IProgress<int> progress)
{
  //Heavy work
  for (int i = 1; i < 1000000000; i++) { }
  progress.Report(100);
}
private async void按钮\u单击(对象发送方,路由目标)
{
var progress=newprogress(value=>{this.progress.value=value;});
等待任务。运行(()=>aNewMethod(progress));
}
私有无效方法(IProgress progress)
{
//繁重的工作
对于(int i=1;i<100000000;i++){
进度报告(100);
}

use
Dispatcher.InvokeAsync
Sakura:我认为这实际上与Dispatcher.BeginInvoke是一样的。请注意,您正在尝试访问另一个线程中的UI线程对象,但这并不是全部。您明确要求在UI线程上运行
Sleep
。不确定您还希望看到什么。旁注:您的示例有点误导性-要么一直使用
async
,根本不需要
BeginInvoke
,要么使用线程并使用
BeginInvoke
手动调用UI线程。很公平-如果继续处理工作线程,您可能希望使用BeginInvoke之后,无需等待UI更新。。但是我已经将这个示例修改为对调度程序的同步调用,这可能更清楚。
async
await
的目的是消除这个
调度程序。Invoke
,所以如果我们将它们与
async
await
一起使用,那么它就没有意义了
private async void button_Click(object sender, RoutedEventArgs e)
{
        if (progress.Value == 0)
        {
             await Task.Delay(3000); 
             progress.Value = 100;
        } 


}
private async void button_Click(object sender, RoutedEventArgs e)
{
  var progress = new Progress<int>(value => { this.progress.Value = value; });
  await Task.Run(() => aNewMethod(progress));
}

private void aNewMethod(IProgress<int> progress)
{
  //Heavy work
  for (int i = 1; i < 1000000000; i++) { }
  progress.Report(100);
}