【问题标题】:RelayCommand and async method resulting: "'System.Reflection.TargetInvocationException' occurred in mscorlib.dll"RelayCommand 和异步方法导致:“‘System.Reflection.TargetInvocationException’发生在 mscorlib.dll 中”
【发布时间】:2017-02-21 05:42:59
【问题描述】:

Mvvm light RelayCommand 让我对 async 方法有些头疼。 WPF 按钮与以下 relayCommand 绑定:

    private RelayCommand _importDeviceCommand;
    /// <summary>
    /// Import device button for SelectDeviceView.
    /// </summary>
    public RelayCommand ImportDeviceCommand
    {
        get
        {
            return _importDeviceCommand
                   ?? (_importDeviceCommand = new RelayCommand(async () => await AddDeviceClickExecute(),
                       () => _selectedCableType != null
                             && _selectedAddDevice != null
                             && _selectedPointNames != null 
                             && _selectedPointNames.Any()));
        }
    }

我可能以某种形式滥用它,因为在方法 AddDeviceClickExecute 完成时总是偶尔遇到以下异常。

未处理的类型异常 mscorlib.dll 中发生“System.Reflection.TargetInvocationException”

  • 有哪些可能的解决方案?
  • 会不会与 lambda 方法调用有关?
  • 因此,我如何重构 relayCommand 以使 没有使用 lambda?

编辑 1

调用的异步方法,try/catch 是不是很遗憾没有什么区别?

private async Task AddDeviceClickExecute()
        {
            _linkTheSocket = true;

            var deviceImporter = new DeviceImporterAsync2(_projectContext, _deviceContext);

            var progress = new Progress<string>(status =>
            {
                _importDeviceProgress = status;
                RaisePropertyChanged("ImportDeviceProgress");
            });

            try
            {
                await deviceImporter.InvokeSimpleDeviceImport(UserSelectedSockets, progress);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "Exception during simple device import", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

编辑 2

AddDeviceClickExecute 退出后立即发生以下异常。

编辑 3

原来我使用 async 和 relayCommand 的方式有 与我的例外无关。问题已解决。

【问题讨论】:

  • 如果不检查 TargetInvocationException,很少有任何关于 TargetInvocationException 的有意义的言论。
  • InnerException 是空的或者我不知道怎么看。在异常设置上,我启用了(公共语言运行时执行)我正在使用 Visual Studio 2015。
  • 只要抛出异常就让 Visual Studio 中断调试器,您可能会遇到实际错误。您可以从异常窗口执行此操作,只需检查“公共语言运行时”,然后使错误发生。但是,请务必在完成后将其关闭,这种行为会变得非常烦人。 blogs.msdn.microsoft.com/visualstudioalm/2015/02/23/…
  • 不幸的是,我已经检查了链接中提到的Common Language Runtime Exceptions 下的所有内容。感谢您的提示!

标签: c# async-await mvvm-light mscorlib


【解决方案1】:

只要有异常转义 async void 方法(即,您传递给 RelayCommand 的 lambda),您就会看到未处理的异常。

这是正常的预期行为;除了 TargetInvocationException 包装器之外,这与您在同步 RelayCommand lambda 中看到的行为相同。正如其他人所指出的,只需检查 InnerException 即可查看实际的底层异常。

如果您想捕获这些异常,您应该将async void 方法的整个主体包装在try/catch 中。这是可能的,但在 lambda 中有点尴尬:

return _importDeviceCommand
    ?? (_importDeviceCommand = new RelayCommand(async () =>
        { try { await AddDeviceClickExecute(); } catch (Exception ex) { ... } },
      () => _selectedCableType != null
         && _selectedAddDevice != null
         && _selectedPointNames != null 
         && _selectedPointNames.Any()));

但这让 IMO 变得非常尴尬。最好将其拆分为另一种方法:

private async void ImportDevice()
{
  try
  {
    await AddDeviceClickExecute();
  }
  catch (Exception ex)
  {
    ...
  }
}

return _importDeviceCommand
    ?? (_importDeviceCommand = new RelayCommand(ImportDevice,
      () => _selectedCableType != null
         && _selectedAddDevice != null
         && _selectedPointNames != null 
         && _selectedPointNames.Any()));

【讨论】:

  • 很遗憾,即使是这样的修改也没有捕捉到异常。代码很好地退出了try/catch 块,我在relayCommand 之后遇到了TargetInvocationException,它调用了AddDeviceClickExecute 退出。有关信息,此异常并不总是发生。
  • @ajr:请减少复制问题所需的最少代码量。
  • 其实我能找到异常的来源,它与ICollectionView LiveFiltering功能有关。不知道为什么会这样,但回滚到使用常规的 collection.Filter = FilterIfConnected; 方法,目前一切似乎都比较好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-04
相关资源
最近更新 更多