简体   繁体   English

WPF 中的调度程序和异步等待

[英]Dispatcher and async await in WPF

I am trying to learn asynchronous programming in WPF/C# and I am stuck on asynchronous programming and using Dispatchers.我正在尝试在 WPF/C# 中学习异步编程,但我一直坚持异步编程和使用 Dispatchers。 Are they both different or are they or are to be used in the same scenario?它们是不同的还是它们或将在同一场景中使用? I am willing keeping this question short as to not be vague because I understand that I am messing up between a concept and a function in WPF, but not enough to functionally use it correctly.我愿意保持这个问题简短,以免含糊不清,因为我知道我在 WPF 中混淆了一个概念和一个函数,但还不足以在功能上正确使用它。

My doubt arises after I asked a question here, This is my question , I was told to use Dispatcher for this problem and that WPF runs on a single thread and you need to use BeginInvoke , here was where I first heard Dispatcher and before that I just user async and await with Task.Run these 3 keywords only.我在这里问了一个问题后出现了我的疑问, 这是我的问题,有人告诉我使用Dispatcher解决这个问题,WPF 在单线程上运行,你需要使用BeginInvoke ,这是我第一次听到Dispatcher ,在此之前我只是用户 async 并等待Task.Run仅使用这 3 个关键字。

But then this article is Asynchronous programming in C# with WPF .但是这篇文章是使用 WPF 在 C# 中进行异步编程

All I need to do is load a few pages into a Grid and this happens at the start of the application (this part I think deals with Dispatcher as it is a part of the UI), and then CRUD to a Database.我需要做的就是将几页加载到Grid ,这发生在应用程序的开始(我认为这部分处理Dispatcher因为它是 UI 的一部分),然后 CRUD 到数据库。

You should not use Dispatcher .你不应该使用Dispatcher Instead, you can use await or IProgress<T> to delegate work back to the UI thread.相反,您可以使用awaitIProgress<T>将工作委托回 UI 线程。

Eg:例如:

private async void b1_Click(object sender, RoutedEventArgs e)
{
  // We are starting on the UI thread here.
  txtb1.Text = "";
  var watch = System.Diagnostics.Stopwatch.StartNew();

  await writeintxtbx();

  // After the await completes, we return to the UI thread because await captured the UI context.

  watch.Stop();
  var elapsedtm = watch.ElapsedMilliseconds;

  // Since we're on the UI thread, we can update UI elements.
  txtb1.Text += $"TOTAL TIME {elapsedtm} \n\n\n";
}

If you need to update UI elements with progress updates, then use IProgress<T> :如果您需要使用进度更新来更新 UI 元素,请使用IProgress<T>

private async Task writeintxtbx()
{
  var progress = new Progress<string>(x => txtb1.Text += x);
  await Task.Run(() => Task1(progress));
  await Task.Run(() => Task2(progress));
}

private void Task1(IProgress<string> progress)
{
  progress?.Report($"Task 01 Done \n\n");
}

private void Task2() 
{
  progress?.Report($"Task 2 done \n\n");
}

I will explain in general terms, not exactly.我会笼统地解释,而不是完全解释。

When you want to execute a method asynchronously, you create a task.当你想异步执行一个方法时,你创建了一个任务。 This task is performed by an arbitrary thread from the thread pool.该任务由线程池中的任意线程执行。

But what if you need to make the method execute in a specific thread?但是,如果您需要使该方法在特定线程中执行怎么办?
This is a common task for UI elements - they should always only run on the main thread of the application.这是 UI 元素的常见任务 - 它们应该始终只在应用程序的主线程上运行。

To solve this problem, Dispatchers for threads were created.为了解决这个问题,创建了线程调度程序。
Each thread can only have one dispatcher.每个线程只能有一个调度程序。
It is created the first time you access it.它是在您第一次访问时创建的。
Using the Thread Dispatcher, you can execute your asynchronous method on this thread.使用线程调度器,您可以在该线程上执行异步方法。

Invoke - Executes a method synchronously on the Dispatcher thread. Invoke - 在 Dispatcher 线程上同步执行一个方法。
It's like just calling a regular synchronous method.这就像调用一个常规的同步方法。
Execution of the main method (in which Invoke was called) will not continue until the method passed to Invoke is executed.在执行传递给 Invoke 的方法之前,不会继续执行 main 方法(在其中调用 Invoke)。
The thread in which the main method is executed also stops.执行 main 方法的线程也会停止。
Invoke used extremely rarely.极少使用的调用。

InvokeAsync and BeginInvoke are asynchronous execution. InvokeAsync 和 BeginInvoke 是异步执行。
They differ in small details - I will not go into their explanation now.他们在小细节上有所不同——我现在不会去解释他们。
These methods return a DispatcherOperation object.这些方法返回一个 DispatcherOperation 对象。
With which you can interact with the task executing your method.您可以使用它与执行您的方法的任务进行交互。
The most common use is BeginInvoke without receiving a DispatcherOperation.最常见的用途是 BeginInvoke 而不接收 DispatcherOperation。

The best way to load data is to create a Model with asynchronous methods (async-await).加载数据的最佳方式是使用异步方法(async-await)创建模型。 After loading the data, the ViewModel will receive this data and provide it in its properties.加载数据后,ViewModel 将接收此数据并在其属性中提供它。 When the ViewModel property changes its value, you need to raise the PropertyChanged event (the ViewModel must necessarily implement INotifyPropertyChanged).当 ViewModel 属性更改其值时,您需要引发 PropertyChanged 事件(ViewModel 必须实现 INotifyPropertyChanged)。 In what streams this happens - it does not matter.在什么流中会发生这种情况 - 没关系。

UI elements (WPF View) will receive this data through bindings of the ViewModel properties . UI 元素(WPF 视图)将通过 ViewModel 属性的绑定接收此数据。 The mechanism of bindings is designed in such a way that regardless of the thread in which the property has changed, the binding will update the UI element always in their Dispatcher.绑定机制的设计方式是,无论属性在哪个线程中发生更改,绑定都将始终在其 Dispatcher 中更新 UI 元素。

With such an implementation, you do not need to worry about the streams in which data is received from the database or other work with data occurs.通过这样的实现,您无需担心从数据库接收数据的流或其他处理数据的工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM