首页 > 解决方案 > 当 Interaction.Handle 接收到重复值时,命令引发异常

问题描述

我在我的视图模型中实现了以下方法

private async Task OpenAudioFileImpl ()
{
    await OpenFileInteraction.Handle(FileTypes.Audio)
        .Where(fp => !string.IsNullOrWhiteSpace(fp))
        .Where(fp => fp != AudioFilePath)
        .Where(fp => File.Exists(fp))
        .Log(this, $"New audio file path selected")
        .Select(x => AudioFilePath = x);
}

它通过以下命令调用:OpenAudioFile = ReactiveCommand.CreateFromTask(async _ => await OpenAudioFileImpl());

在我的视图中注册的处理程序打开一个Microsoft.Win32.OpenFileDialog,所以我可以选择我想要的文件。

我的目标是仅在AudioFilePath选择新文件并且该文件实际存在时才具有更新值。当我单击按钮时,对话框会正确打开。只要我每次选择不同的文件,我就不会收到错误并AudioFilePath正确更新。但是,如果我再次选择相同的文件或取消对话框,该命令将引发异常。我做了一些控制台输出,我很确定问题出在这个方法上,我只是不知道它是什么。

因为它是引发错误的 ReactiveCommand,所以我知道处理它的唯一方法是:

OpenAudioFile.ThrownExceptions.Subscribe(ex =>
{
    this.Log().Error("OpenAudioFile failed to execute.", ex);
});

我得到的输出是

Exception thrown: 'System.InvalidOperationException' in System.Reactive.dll
Exception thrown: 'System.InvalidOperationException' in System.Private.CoreLib.dll
MainWindowViewModel: OpenAudioFile failed to execute.

这并没有给我太多信息。

标签: c#wpfreactiveuireactivex

解决方案


在这些情况下出现异常的原因是因为您使用的是异步等待。等待 observable 的行为是返回最后一个元素(在 OnCompleted 之前),或者抛出观察到的 OnError。但是,如果序列不包含任何元素,您将收到 InvalidOperationException。所以那些 Where 语句正在过滤掉唯一发出的元素。

在使用 Rx 时,我更喜欢尽可能避免 asnyc/await。但是如果你想坚持使用 async/await,你只需要稍微修改一下你的逻辑。例如,可能会删除 Where 语句并在 Select 中进行条件赋值并在其他地方进行验证。不确定您的整体设置,所以也许您可以想出更好的方法。


推荐阅读