【问题标题】:Perform synchronous operation on Ui thread对 Ui 线程执行同步操作
【发布时间】:2016-03-02 12:45:48
【问题描述】:

我正在尝试开发 Windows 应用程序并遇到问题。 我有一个 MainPage.xaml 和另外 2 个 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 分支时,一切都很好,但是当目录可用时,我收到以下错误消息:

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 = "";
            }
        });
    }

仍然是同样的错误,据我了解,这应该异步运行并等待代码完成,但似乎并非如此。我还尝试了其他一些东西,但仍然出现错误。 我不知道如何解决这个问题,谁能解释一下为什么会发生这种情况以及如何解决这个问题。

【问题讨论】:

    标签: c# xaml asynchronous async-await win-universal-app


    【解决方案1】:

    正如例外所说,您不允许在 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

    【讨论】:

      【解决方案2】:

      [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 版本。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-19
        • 2020-10-13
        相关资源
        最近更新 更多