C# 使用异步和等待
我想让这两个方法(1.DomainModel.Load(),2.UpdateEstate())一个接一个地运行在同一个线程上。不在UI线程上C# 使用异步和等待,c#,multithreading,asynchronous,task-parallel-library,C#,Multithreading,Asynchronous,Task Parallel Library,我想让这两个方法(1.DomainModel.Load(),2.UpdateEstate())一个接一个地运行在同一个线程上。不在UI线程上 如何执行此操作?请考虑以下代码: public async override void InitData() { _domainModel = new DomainModel() ProgressIndicatorViewModel.Start(); _State = Getstate();
如何执行此操作?请考虑以下代码:
public async override void InitData()
{
_domainModel = new DomainModel()
ProgressIndicatorViewModel.Start();
_State = Getstate();
await _domainModel.Load(_State, ProgressIndicatorViewModel); //returns a task
ImageSelectionViewModel.UpdateState(_State); //returns void not a task!
ProgressIndicatorViewModel.Stop();
DispatcherHelper.UIDispatcher.Invoke(() => ImageSelectionViewModel.RefreshImages(_imageList));
}
DoOne不会在UI线程中执行
在客户端的大多数情况下,调用方线程是UI线程,因为大多数代码都是由用户操作(如鼠标单击)调用的,但这不是固定的行为
DoTwo将在一个单独的线程中执行,显然它不会在调用线程中执行
DoThree将在调用线程中执行
并且,DoFour将在UI线程上执行,调用线程是什么并不重要
所以@usr的评论是完全错误的
要实现目标,请按以下方式更改代码:
public async void Sample()
{
DoOne();
await DoTwo();
DoThree();
Dispather.BeginInvoke(() => DoFour());
}
我想使用这两种方法(1.domaminModel.Load(),2。
UpdateEstate())在同一线程上逐个运行。不在
用户界面线程
已更新,如果您只需要\u domainModel.Load
和ImageSelectionViewModel.UpdateState
在单独的非UI线程上运行,则只需执行以下操作:
public async override void InitData()
{
_domainModel = new DomainModel()
ProgressIndicatorViewModel.Start();
_State = Getstate();
await Task.Factory.StartNew(() => {
_domainModel.Load(_State, ProgressIndicatorViewModel).ContinueWith(() => {
ImageSelectionViewModel.UpdateState(_State); });
};
ProgressIndicatorViewModel.Stop();
DispatcherHelper.UIDispatcher.Invoke(() => ImageSelectionViewModel.RefreshImages(_imageList));
}
注意,您不需要DispatcherHelper.UIDispatcher.Invoke()
wrapper
如果希望
\u domainModel.Load
之后的InitData
的其余部分在单独的线程上运行:
public async override void InitData()
{
_domainModel = new DomainModel()
ProgressIndicatorViewModel.Start();
_State = Getstate();
await Task.Run(async () =>
{
await _domainModel.Load(_State, ProgressIndicatorViewModel))
ImageSelectionViewModel.UpdateState(_State); //returns void not a task!
});
ProgressIndicatorViewModel.Stop();
ImageSelectionViewModel.RefreshImages(_imageList);
}
请注意,Task.Run
将在此处自动为您的用户打开嵌套任务(属于Task
)。另外,您可能需要在Dispatcher.Invoke
中移动ProgressIndicatorViewModel.Stop()
根据\u domainModel.Load中的内容,您甚至可能不需要任务。运行:
public async override void InitData()
{
_domainModel = new DomainModel()
ProgressIndicatorViewModel.Start();
_State = Getstate();
await Task.Run(() => _domainModel.Load(_State,
ProgressIndicatorViewModel)).ConfigureAwait(false);
ImageSelectionViewModel.UpdateState(_State); //returns void not a task!
DispatcherHelper.UIDispatcher.Invoke(() =>
{
ProgressIndicatorViewModel.Stop();
ImageSelectionViewModel.RefreshImages(_imageList)
});
}
另一方面,您可能应该在async void InitData
方法中处理异常。您将无法在it之外处理它们。这不是问题的关键,但是DispatcherHelper.UIDispatcher.Invoke
不是必需的,因为您已经在UI线程上。我很惊讶它居然会运行。需要它来刷新可观察的集合。别担心。运行perfactlyIsUpdateState
也async void
,与InitData
相同?你有没有理由不使用异步任务
?我已经编辑了你的标题。请参阅“”,其中一致意见是“不,他们不应该”。@nosestate不是异步的。只是一个更新不同ViewModel属性的函数我认为您的答案是错误的,因为您在同一个线程中执行以下行,[\u domainModel.Load]&[ImageSelectionViewModel.UpdateEstate]&[ProgressIndicatorViewModel.Stop],但他希望在同一个线程中有[\u domainModel.Load]&[ImageSelectionViewModel.UpdateEstate]。和ProgressIndicatorViewModel.Stop();应在调用方线程中调用。例如,如果UI线程是调用线程,而ProgressIndicatorViewModel.Stop()更改了UI,那么您的代码将无法成功执行。@YasserMoradi,您可能是对的,尽管我不明白为什么@Gilad需要DispatcherHelper.UIDispatcher.Invoke
。我认为他希望在非UI线程上运行该方法的其余部分。我更新了答案以解决这两种情况。注意,Task.Run将自动为您的此处展开嵌套的任务。
这是什么意思?这意味着如果lambda返回任务,它将调用Task.unwrap()
。您可以阅读有关它的内容。要使它按预期工作,您需要调用Task.Factory.StartNew
的结果Unwrap
。这是因为ContinueWith
返回Task
,因此Task.Factory.StartNew
将返回Task
,并且在当前版本中,您不必等待内部任务。@谢谢您的回复,请注意,我的答案是概念性的,它甚至不会生成!(:从概念上讲,我认为您需要在此处使用await-await
或单个await
和Unwrap
,否则await
之后的代码可能会在另一个线程上完成UpdateState
之前继续。
await _domainModel.Load(_State,
ProgressIndicatorViewModel).ConfigureAwait(false);