在 Ui 线程上执行同步操作

本文关键字:执行 同步操作 线程 Ui | 更新日期: 2023-09-27 18:36:59

我正在尝试开发Windows应用程序并遇到问题。我有一个 MainPage.xaml 和其他 2 个 StartScreen.xaml 和 Player.xaml。如果某些条件为真,我将切换主页的内容。所以我在 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 分支时,一切都很好,但是当目录可用时,我收到以下错误消息:

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 线程上执行同步操作

正如异常所述,不允许在 UI 线程中同步调用Directory.Exists。将整个代码块放在调度程序操作中仍会在 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

[更新 July 22 2018 示例]

错误消息告诉您需要了解的所有信息:

考虑将此方法包装在 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 版本。