简体   繁体   中英

ICommand implementation throws COM Exception regularly

I'm using MVVM pattern to build UWP app. I have implemented ICommand interface as mentioned in book: "Microsoft Visual C# 2013 - Step-by-step".

ICommand implementation:

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;
    }

App crashes with COM exception after every 3-4 mins of running.

    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: 

This exception didn't occur while building Win 8.1 apps. Please give suggestions to remove this exception.

dt.Tick += (s, e) => CanExecuteChanged?.Invoke(this, EventArgs.Empty);

That's most likely what's causing your issue. I'm not sure why you're spamming your CanExecuteChanged, but maybe you want to re-think your execution model.

Also we don't know what methods your delegate is calling. So there could be a plethora of reasons it's failing.

I guess your problem is the timer.

I always implement the ICommand like:

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; }
    }
}

@Water Solution is to manually raise CanExecuteChanged whenever we want View to know about Control's changed status.

Steps:

  1. Wrap CanExecuteChanged into a method like OnCanExecuteChanged ()
  2. Call this method form relevant ViewModel Property Setters.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM