Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.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
Wpf 异步等待似乎使用UI线程_Wpf_Async Await - Fatal编程技术网

Wpf 异步等待似乎使用UI线程

Wpf 异步等待似乎使用UI线程,wpf,async-await,Wpf,Async Await,在视图模型中,我使用工厂: private async Task<BaseData> InitializeAsync() { await InstancesAsync(); await ProjectsAsync(); await AdminAsync(); return this; } public static async Task<BaseData> CreateAsync() { var ret = new BaseData

在视图模型中,我使用工厂:

private async Task<BaseData> InitializeAsync()
{
    await InstancesAsync();
    await ProjectsAsync();
    await AdminAsync();
    return this;
}
public static async Task<BaseData> CreateAsync()
{
    var ret = new BaseData();
    return await ret.InitializeAsync();
}
虽然它可以工作,但我感到相当不舒服,因为UI线程到处都在使用,而且在等待完成的回调之后也是如此。我错过了什么

另外,我不知道如何使用工厂模式来处理
DataContext
,因为如果没有上面的
Invoke
,我会得到一个错误,即不同的线程拥有该对象

编辑:利用克利里先生的想法,我得到:

Loaded += async (object sender, RoutedEventArgs e) =>
          { DataContext = await BaseData.CreateAsync(); };
public static Task<BaseData> CreateAsync()
{
    var ret = new BaseData();
    return ret.InitializeAsync();
}
private async Task<BaseData> InitializeAsync()
{
    // UI thread here
    await InstancesAsync().ConfigureAwait(false);
    // thread 'a' here
    await ProjectsAsync().ConfigureAwait(false);
    // thread 'a' sometimes 'b' here
    await AdminAsync().ConfigureAwait(false);
    // thread 'a' or 'b' here
    return this;
}
Loaded+=async(对象发送方,RoutedEventArgs e)=>
{DataContext=wait BaseData.CreateAsync();};
公共静态任务CreateAsync()
{
var ret=新的BaseData();
返回ret.InitializeAsync();
}
专用异步任务InitializeAsync()
{
//UI线程在这里
await InstanceAsync().ConfigureAwait(false);
//在这里穿“a”
wait ProjectsAsync().configurewait(false);
//在此处线程“a”有时为“b”
await AdminAsync().ConfigureAwait(false);
//在此处插入“a”或“b”
归还这个;
}
这可以正常工作,但我无法理解
ConfigureAwait(false)
是如何工作的。
在方法
instanceAsync()
中,我有一个等待的任务:
var instances=wait TaskEx.Run(new Func(()=>Agent.GetInstances())
在等待repsonse之后,我返回UI线程-我从未预料到会发生这种情况
请注意,
ProjectsAsync()
adminancy()
的行为相同,尽管它们是从工作线程(或后台线程)开始的
我认为
ConfigureAwait(true)
具有在调用线程(在我的例子中是UI线程)中返回的效果。我对此进行了测试,结果就是这样。

为什么我在
ConfigureAwait(false)
中也会看到这一点:由于嵌套的await,请参见注释。

我发现将ViewModel视为具有UI线程关联性最有用。将其视为逻辑用户界面,即使它不是实际的用户界面。因此,ViewModel类上的所有属性和可观察集合更新都应该在UI线程上完成

async
方法中,如果不需要返回UI线程,则可以使用
ConfigureAwait(false)
避免在UI线程上恢复。例如,如果您的各种初始化方法是独立的,则可以执行以下操作:

private async Task<BaseData> InitializeAsync()
{
  // Start all methods on the UI thread.
  var instancesTask = InstancesAsync();
  var projectsTask = ProjectsAsync();
  var adminTask = AdminAsync();

  // Await for them all to complete, and resume this method on a background thread.
  await Task.WhenAll(instancesTask, projectsTask, adminTask).ConfigureAwait(false);

  return this;
}
最后,您应该极力避免使用
调度程序
。您加载的
事件可以简化为:

Loaded += async ()
{
  DataContext = await BasisGegevens.CreateAsync();
};

您显示的代码中加载的
事件的来源是什么?如果这是一个常规事件,则应在UI线程上激发它。是否在单独的线程上创建视图?这可能是因为您正在非UI池线程上调用
Agent.GetInstances()
?加载的事件是一个常规的FrameworkElement.Loaded事件。我打算在UI线程上创建视图,这显然是错误的。Agent.GetInstances()在等待的任务中运行,我希望它在非UI池线程上运行,但事实并非如此。
TaskEx.Run
确实使用单独的池线程来运行
Func
委托,这就是执行
Agent.GetInstances()
的地方。我建议您遵循Stephen的答案,并确保WPF UI元素和ViewModel对象都是在同一个-UI-线程上创建的。添加一些日志(
System.Threading.Thread.CurrentThread.ManagedThreadId
)以查看您所在的线程和位置。
ConfigureAwait(false)
只影响特定的
await
,它对它“内部”的
await
没有影响。@svick:当然,谢谢,我还检查了它。我从您位于“”的工厂模式中派生了
return await
任务。所有
时:任务必须按确定的顺序运行。加载的委托我必须以
异步(对象发送方,RoutedEventArgs e)
的形式编写,才能编译。
private async Task<BaseData> InitializeAsync()
{
  // Start all methods on the UI thread.
  var instancesTask = InstancesAsync();
  var projectsTask = ProjectsAsync();
  var adminTask = AdminAsync();

  // Await for them all to complete, and resume this method on a background thread.
  await Task.WhenAll(instancesTask, projectsTask, adminTask).ConfigureAwait(false);

  return this;
}
public static Task<BaseData> CreateAsync()
{
  var ret = new BaseData();
  return ret.InitializeAsync();
}
Loaded += async ()
{
  DataContext = await BasisGegevens.CreateAsync();
};