【问题标题】:ICommand implementation throws COM Exception regularlyICommand 实现定期抛出 COM Exception
【发布时间】:2015-11-15 20:26:08
【问题描述】:

我正在使用 MVVM 模式来构建 UWP 应用程序。我已经实现了书中提到的 ICommand 接口:“Microsoft Visual C# 2013 - Step-by-step”。

ICommand 实现:

public class Command : ICommand
    {
        private Action _methodToExecute;
        private Func<bool> _methodCanExecute;

        public Command(Action methodToExecute) : this(methodToExecute, null)
        {
        }

        public Command(Action methodToExecute, Func<bool> methodCanExecute)
        {
            _methodToExecute = methodToExecute;
            _methodCanExecute = methodCanExecute;

            var dt=new DispatcherTimer();
            dt.Tick += (s, e) => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
            dt.Interval = new TimeSpan(0, 0, 1);
            dt.Start();
        }

        public bool CanExecute(object parameter) => _methodCanExecute == null ? true : _methodCanExecute();

        public void Execute(object parameter) => _methodToExecute();

        public event EventHandler CanExecuteChanged;
    }

应用程序每运行 3-4 分钟就会崩溃并出现 COM 异常。

    System.Runtime.InteropServices.COMException was unhandled by user code
  ErrorCode=-2147467259
  HResult=-2147467259
  Message=Error HRESULT E_FAIL has been returned from a call to a COM component.
  Source=mscorlib
  StackTrace:
       at System.EventHandler`1.Invoke(Object sender, TEventArgs e)
       at System.Runtime.InteropServices.WindowsRuntime.ICommandAdapterHelpers.<>c__DisplayClass2.<CreateWrapperHandler>b__3(Object sender, EventArgs e)
       at FavQuotesMain.ViewModels.Command.<.ctor>b__3_0(Object s, Object e)
  InnerException: 

在构建 Win 8.1 应用程序时未发生此异常。 请提出删除此异常的建议。

【问题讨论】:

  • CanExecuteChanged 事件发送垃圾邮件不是一个好主意。也许有一个替代DispatcherTimer
  • 您意识到 DispatcherTimer 在 Command 方法完成后立即被 GC,对吧?无论你在这里做什么,你都做错了。 您想通过使用 DispatcherTimer 来完成什么?将有关此问题的详细信息添加到 edit,我们可以告诉您您应该做什么。
  • @Will Timer 每 1 秒触发一次事件,以查看是否可以执行命令(如上述书中所述)。
  • @MikeEason 是的。我正在考虑使用 Xaml Behavior 将事件直接绑定到使用 CallMethodAction 的方法,而不是使用 Command。
  • 不,这是个糟糕的主意。只需在它已更改 时引发 CanExecuteChanged。例如,如果属性 X 依赖于属性 Y 的状态,则在 Y 更改时为 X 触发 CanExecuteChanged。而且,同样,在发布模式应用程序中,您的 DispatcherTimer 几乎永远不会触发,因为在方法退出后它将符合 GC 条件。

标签: c# mvvm uwp icommand


【解决方案1】:
dt.Tick += (s, e) => CanExecuteChanged?.Invoke(this, EventArgs.Empty);

这很可能是导致您的问题的原因。我不确定您为什么要向 CanExecuteChanged 发送垃圾邮件,但也许您想重新考虑您的执行模型。

此外,我们不知道您的委托正在调用什么方法。所以它失败的原因可能有很多。

【讨论】:

【解决方案2】:

我猜你的问题是计时器。

我总是像这样实现 ICommand:

public class Command : ICommand
{
    private readonly Action<object> execute;
    private readonly Predicate<object> canExecute;

    public Command(Action<object> execute, Predicate<object> canExecute = null)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");
        this.execute = execute;
        this.canExecute = canExecute;
    }

    public void Execute(object parameter)
    {
        execute(parameter);
    }

    public bool CanExecute(object parameter)
    {
        return canExecute == null || canExecute(parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
}

【讨论】:

    【解决方案3】:

    @Water 解决方案是在我们希望 View 知道 Control 的更改状态时手动提高 CanExecuteChanged

    步骤:

    1. 将 CanExecuteChanged 包装成类似OnCanExecuteChanged () 的方法
    2. 从相关的 ViewModel 属性设置器中调用此方法。

    【讨论】:

      猜你喜欢
      • 2012-06-12
      • 2010-11-30
      • 2017-07-31
      • 2011-01-09
      • 1970-01-01
      • 2021-08-02
      • 2018-03-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多