DelegateCommand in Prism loses eventhandler and CanExecute never gets called

I beat my head against the all for half a day wondering why the DelegateCommand doesn’t work in my Silverlight application. Very frustrating. I traced the code in and somehow the event handler loses its reference. I am guessing it something to do with the WeakReference being used to store the event reference.

Anyway, after wasting entirely too much time with it, I just said screw it and went to using the RelayCommand class I  found. It works great and all the problems I had went away. When I have free time, I will go back and see what the true cause for the reference drops were.

Here is the RelayCommand code, if you need it. I got it from an MSDN article a while back for MVVM.
Interface

using System.Windows.Input;
namespace Seekford.Infrastructure.Commanding
{
 /// <summary>
 /// Support for commanding.
 /// </summary>
 public interface IRelayCommand : ICommand
 {
 /// <summary>
 /// Raises the can execute changed.
 /// </summary>
 void RaiseCanExecuteChanged();
 /// <summary>
 /// Determines whether this instance can execute the specified parameter.
 /// </summary>
 /// <param name="parameter">The parameter.</param>
 /// <returns>
 ///     <c>true</c> if this instance can execute the specified parameter; otherwise, <c>false</c>.
 /// </returns>
 bool CanExecute(object parameter);
 /// <summary>
 /// Executes the specified parameter.
 /// </summary>
 /// <param name="parameter">The parameter.</param>
 void Execute(object parameter);
 }
}

Class Definition

using System;
using System.Windows.Input;
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics;

namespace Seekford.Infrastructure.Commanding
{

 /// <summary>
 /// A command whose sole purpose is to relay its functionality to other
 /// objects by invoking delegates. The default return value for the CanExecute
 /// method is 'true'.  This class does not allow you to accept command parameters in the
 /// Execute and CanExecute callback methods.
 /// </summary>
 public class RelayCommand :  IRelayCommand
 {
 private readonly Action _execute;
 private readonly Func<bool> _canExecute;

 /// <summary>
 /// Initializes a new instance of the RelayCommand class that
 /// can always execute.
 /// </summary>
 /// <param name="execute">The execution logic.</param>
 /// <exception cref="ArgumentNullException">If the execute argument is null.</exception>
 public RelayCommand(Action execute)
 : this(execute, null)
 {
 }

 /// <summary>
 /// Initializes a new instance of the RelayCommand class.
 /// </summary>
 /// <param name="execute">The execution logic.</param>
 /// <param name="canExecute">The execution status logic.</param>
 /// <exception cref="ArgumentNullException">If the execute argument is null.</exception>
 public RelayCommand(Action execute, Func<bool> canExecute)
 {
 if (execute == null)
 {
 throw new ArgumentNullException("execute");
 }

 _execute = execute;
 _canExecute = canExecute;
 }

#if SILVERLIGHT
 /// <summary>
 /// Occurs when changes occur that affect whether the command should execute.
 /// </summary>
 public event EventHandler CanExecuteChanged;
#else
 /// <summary>
 /// Occurs when changes occur that affect whether the command should execute.
 /// </summary>
 public event EventHandler CanExecuteChanged
 {
 add
 {
 if (_canExecute != null)
 {
 CommandManager.RequerySuggested += value;
 }
 }

 remove
 {
 if (_canExecute != null)
 {
 CommandManager.RequerySuggested -= value;
 }
 }
 }
#endif

 /// <summary>
 /// Raises the <see cref="CanExecuteChanged" /> event.
 /// </summary>
 [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic",
 Justification = "The this keyword is used in the Silverlight version")]
 [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate",
 Justification = "This cannot be an event")]
 public void RaiseCanExecuteChanged()
 {
#if SILVERLIGHT
 var handler = CanExecuteChanged;
 if (handler != null)
 {
 handler(this, EventArgs.Empty);
 }
#else
 CommandManager.InvalidateRequerySuggested();
#endif
 }

 /// <summary>
 /// Defines the method that determines whether the command can execute in its current state.
 /// </summary>
 /// <param name="parameter">This parameter will always be ignored.</param>
 /// <returns>true if this command can be executed; otherwise, false.</returns>
 [DebuggerStepThrough]
 public bool CanExecute(object parameter)
 {
 return _canExecute == null ? true : _canExecute();
 }

 /// <summary>
 /// Defines the method to be called when the command is invoked.
 /// </summary>
 /// <param name="parameter">This parameter will always be ignored.</param>
 public void Execute(object parameter)
 {
 _execute();
 }
 }
}

0 Replies to “DelegateCommand in Prism loses eventhandler and CanExecute never gets called”

  1. So I’m not going crazy! This strange behaviour has been bugging me for a while and I never bothered to look into it until now. It’s very intermittent, I guess it’s based on when the garbage collector runs and deletes the WeakEvents up.

Leave a Reply

Your email address will not be published. Required fields are marked *