在Ui线程上执行同步操作

我正在尝试开发Windows应用程序并遇到问题。 我有一个MainPage.xaml和另外两个StartScreen.xaml和Player.xaml。 如果某些条件为真,我正在切换MainPage的内容。 所以我在StartScreen中有一个事件,它检查目录是否存在,但每次出错时它都会抛出我。

private void GoToPlayer_Click(object sender, RoutedEventArgs e) { if (Directory.Exists(this.main.workingDir + "/" + IDText.Text + "/Tracks")) // Error occurs here { this.main.Content = this.main.player; //here i switch between different ui forms } else { MessageBox.Text = "CD not found"; IDText.Text = ""; } } 

当它到达else分支时一切都很好但是当dir可用时我收到以下错误消息:

 An exception of type 'System.InvalidOperationException' occurred in System.IO.FileSystem.dll but was not handled in user code 

附加信息:不应在UI线程上执行同步操作。 考虑在Task.Run中包装此方法。

即使我在if分支中注释代码,错误仍然存​​在。

我试过这个:

 private async void GoToPlayer_Click(object sender, RoutedEventArgs e) { await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { if (Directory.Exists(this.main.workingDir + "/" + IDText.Text + "/Tracks")) // Error occurs here { this.main.Content = this.main.player; //here i switch between different ui forms } else { MessageBox.Text = "CD not found"; IDText.Text = ""; } }); } 

仍然是同样的错误,因为我理解这应该是异步运行并等到代码完成,但它似乎不是这样。 我也试过其他东西,但仍然得到错误。 我不知道如何解决这个问题,有人可以解释为什么会发生这种情况以及如何解决这个问题。

例外情况说,您不允许在UI线程中同步调用Directory.Exists 。 将整个代码块放在Dispatcher操作中仍然在UI线程中调用它。

在UWP应用程序中,您通常使用StorageFolder.TryGetItemAsync方法来检查文件或文件夹是否存在:

 private async void GoToPlayer_Click(object sender, RoutedEventArgs e) { var folder = await StorageFolder.GetFolderFromPathAsync(main.workingDir); if ((folder = await folder.TryGetItemAsync(IDText.Text) as StorageFolder) != null && (folder = await folder.TryGetItemAsync("Tracks") as StorageFolder) != null) { ... } } 

请注意,当不允许应用程序访问main.workingDir时,您可能仍会收到UnauthorizedAccessException

[更新2018年7月22日举例]

错误消息告诉您需要知道的一切:

考虑在Task.Run中包装此方法

您应该在调用Task.Run包装代码。 这将确保它在后台线程上运行。

这是一个简单的例子:

 var picker = new FolderPicker(); picker.SuggestedStartLocation = PickerLocationId.MusicLibrary; picker.FileTypeFilter.Add(".mp3"); var folder = await picker.PickSingleFolderAsync(); var result = await Task.Run(() => Directory.Exists(Path.Combine(folder.Path, "foobar"))); if (result) { Debug.WriteLine("Yes"); } else { Debug.WriteLine("No"); } 

有关人员关心的背景信息:

根据您的示例代码,我假设您正在阅读音乐库。 在这种情况下,.NET文件API通过WinRT API下载,因为它是一个代理位置。 由于底层的WinRT API是异步的,因此.NET必须能够为您提供同步行为的假象,并且他们不希望在UI线程上执行此操作。

如果您只处理自己的本地数据文件夹,.NET API将使用底层的Win32 API(已经是同步的),因此可以在没有任何后台线程要求的情况下工作。

请注意,在我的计算机上,这似乎甚至可以在UI线程上运行,因此它可能取决于您要定位的Windows版本。