【问题标题】:UWP - I can't edit a field on the Application class from the UI threadUWP - 我无法从 UI 线程编辑 Application 类上的字段
【发布时间】:2021-01-29 11:22:39
【问题描述】:

我的Application 类中有一个ObservableCollection<Element> 类型的属性Files

public sealed partial class App : Application
{
    public string CurrentPath;

    public ObservableCollection<Element> Files;

    public async void RefreshFilesAsync()
    {
        Files.Clear();

        var folder = await StorageFolder.GetFolderFromPathAsync(CurrentPath);
        var foldersRequest = folder.GetFoldersAsync();
        var filesRequest = folder.GetFilesAsync();

        var folders = await foldersRequest;
        var files = await filesRequest;

        foreach (StorageFolder directory in folders)
        {
            Files.Add(new FolderElement(directory));
        }

        foreach (StorageFile file in files)
        {
            Files.Add(new FileElement(file));
        }
    }

    // ...

}

Element 是我的 StorageFile 对象的包装类。创建此类以便为 Name 属性设置新值调用 API 以重命名实际文件。

public class Element
{
    public string Name
    {
        get => StorageFile.Name;
        set =>
        {
            StorageFolder.RenameAsync(value, NameCollisionOption.GenerateUniqueName).Completed = (IAsyncAction act, AsyncStatus status) =>
            {
                (App.Current as App).RefreshFilesAsync();
            };
        }
    }

    public StorageFile StorageFile { get; }

    //...

}

我有一个DataGrid 链接到应用程序属性Files,因此您可以推断,每当我为文件名重命名列时,都会调用API 来执行真正的重命名。

这是我的问题发生的时候。 API调用成功,文件被重命名,但是在RefreshFilesAsync()内部,当Files.Clear();被调用时,我得到一个异常The application called an interface that was marshalled for a different thread

我做错了什么?

【问题讨论】:

  • 您正在从 Lamba 内部调用异步 void 方法。那就是把它扔回线程池。使您从应用程序调用的方法成为常规方法。或者至少使用调度程序返回到 Files.Clear 的窗口线程
  • 我没有看到你现在在任何地方使用调度程序。
  • 是的,很抱歉,我弄错了文件,我在另一个文件中使用调度程序,看起来很像这个文件。我修复了最初的帖子并为未来的读者添加了解决方案。无论如何,谢谢。

标签: c# .net uwp ui-thread storagefile


【解决方案1】:

为了使用 UI 线程运行代码,我使用了Window.Current.Dispatcher.RunAsync(),并将其放在单独的异步方法中。该异常不再出现。

public string Name
{
    get => StorageFolder.Name;
    set => RenameAsync(value);
}

private async void RenameAsync(string newName)
{
    await StorageFolder.RenameAsync(newName, NameCollisionOption.GenerateUniqueName);
    await Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => (App.Current as App).RefreshFilesAsync());
}

【讨论】:

    猜你喜欢
    • 2018-02-17
    • 2019-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    • 2012-04-01
    相关资源
    最近更新 更多