DelegateCommand<T> & CanExecute delegate...

Topics: Prism v2 - WPF 3.5
Nov 6, 2009 at 9:37 PM
Edited Nov 6, 2009 at 10:06 PM

Hi,

I'm not sure how the DelegateCommand<T> works but my CanExecute delegate only fires once, which is when my command gets databound at initialization.

I'd like it to track the System.Windows.Input.CommandManager's RequerySuggested, so that my buttons that are bound to my commands continually gets Enabled/Disabled via calling the CanExecute delegate. However the CommandManager's RequerySuggested doesn't even fire when I'm only using DelegateCommand<T>s. But If I somewhere bind a good old RoutedUICommand, CommandManager starts firing RequerySuggested events. Why could that be? In fact CommandManager doesn't even fire RequerySuggested events when I try to force it by calling "InvalidateRequerySuggested()" on it. Really odd. I'm probably doing something wrong... But back to my question, is the CanExecute delegate even supposed to influence the "IsEnabled" state of the control it's bound to? And how am I supposed to use it? Any hints? Thanks!

Cheers!

Update:
I tried hooking up the CommandManager's event like this:

System.Windows.Input.CommandManager.RequerySuggested += (sender, args) => {
	ApplyCommand.RaiseCanExecuteChanged();
};
but to no avail... modifying the source of Prism's DelegateCommand<T> to what I would belive would accomplish the same thing, from:
public event EventHandler CanExecuteChanged
{
    add
    {
        WeakEventHandlerManager.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2);
    }
    remove
    {
        WeakEventHandlerManager.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value);
    }
}

to:
public event EventHandler CanExecuteChanged
{
    add
    {
        CommandManager.RequerySuggested += value;
    }
    remove
    {
        CommandManager.RequerySuggested -= value;
    }
}
And THEN everything works as I was expecting... I must be missing something...
Nov 9, 2009 at 5:27 PM

Hi

Julian Dominguez, Prism developer, talks about why DelegateCommands are implemented like this in Prism in this thread and explains a possible workaround. You might find it useful.

Please let me know if this helps.

Damian Schenkelman
http://blogs.southworks.net/dschenkelman

Nov 10, 2009 at 7:42 AM

Hi Damian,

Thanks for your reply. I read the thread your pointed to, but and I can totally understand why you did choose to implement it like this, the problem is that I have already tried doing what was suggested in that thread, but the problem is that the CommandManager never fires any RequerySuggested events when hooked up like this (see the beginning of my previous message that I already mentioned that I had tried this venue. I guess maybe I should take this question to a WPF forum, as the real question is why the CommandManager never fires any events when connected like this. Thanks Damian!

Cheers,
Ted

Nov 19, 2009 at 1:53 PM

Neo,

I had the same problem as you with using the DelegateCommand<> provided with c/WPF. My CanExecute delegates were only being called the first time and any usage of CommandManager.RequerySuggested() was making no difference whatsoever.

There is a DelegateCommand class with a different implementation that is provided as part of VS project template from the WPF Model-View-ViewModel Toolkit 0.1 (part of the WPF Futures project).

After running some tests using that version as opposed to the PRISM v2 one, I noticed that my CanExecute delegates were being called (as expected).

Hope that helps.

 

Regards,

Richard

Mar 31, 2011 at 3:55 PM

This is my solution. This code write my ViewModelBase class.

       // EventHandler reference list
       private ICollection<EventHandler> eventHandlers = new List<EventHandler>();

        private void InitializeCommandProperties()
        {
            var commands = this.GetType().GetProperties()
                .Where(p => typeof(DelegateCommandBase).IsAssignableFrom(p.PropertyType))
                .Select(p => p.GetValue(this, null) as DelegateCommandBase);

            foreach (var command in commands)
            {
                EventHandler eventHandler = this.MakeEventHandler(command);
                CommandManager.RequerySuggested += eventHandler;
                this.eventHandlers.Add(eventHandler);
            }
        }

        private EventHandler MakeEventHandler(DelegateCommandBase command)
        {
            return (sender, e) => command.RaiseCanExecuteChanged();
        }