CompositeCommand for ANY registered DelegateCommand that CanExecute

Topics: Prism v2 - WPF 4, Prism v4 - WPF 4
Aug 24, 2010 at 10:04 PM

Hi,

I'm guessing this probably isn't possible but I'd really like to be able to use the CompositeCommand to trigger ANY of it's child commands that can be executed rather than only triggering ALL child commands once ALL can execute.

E.g.

CompositeCommand parentCommand has two children, command1 and command2. Consider the following scenarios:

command1.CanExecute() is false

command2.CanExecute() is false

so parentCommand cannot execute.

command1.CanExecute() is false

command2.CanExecute() is true

I would like to be able to trigger parentCommand at this point and fire only command2 in doing so.

 

A scenario that I would like to use this for is the classic "Save All" scenario. However I have parts of my application that need saving when others do not need saving but I'd still like to have just one button trigger all of it.

Regards,

Neil

 

 

Developer
Aug 25, 2010 at 8:03 PM

Neil,

If the underlying ICommands registered with CompositeCommand implement the IActiveAware interface, then CompositeCommand will only use those commands that are 'active' for purposes of CanExecute() and Execute().  DelegateCommand implements IActiveAware, so if you are using that for your commands registered with CompositeCommand, you can set IsActive=false for those commands you don't wish to participate.

HTH,

-b

Aug 26, 2010 at 8:30 AM
brumfb wrote:

Neil,

If the underlying ICommands registered with CompositeCommand implement the IActiveAware interface, then CompositeCommand will only use those commands that are 'active' for purposes of CanExecute() and Execute().  DelegateCommand implements IActiveAware, so if you are using that for your commands registered with CompositeCommand, you can set IsActive=false for those commands you don't wish to participate.

HTH,

-b

Ok I think I see what you are saying, So I have made the following changes:

I have the static global command:

    public static class GlobalCommands
    {
        public static CompositeCommand SaveAllCommand = new CompositeCommand(true);
    }

And then a child command in two seperate ViewModels:

// ViewModel 1:

            SaveVolunteerCommand = new DelegateCommand<object>(SaveVolunteer, CanSaveVolunteer);
            GlobalCommands.SaveAllCommand.RegisterCommand(SaveVolunteerCommand);

        private bool CanSaveVolunteer(object args)
        {
            // Can save if Current Volunteer has been edited
            bool canSave = (this.UpdatedVolunteers != null && this.UpdatedVolunteers.Count > 0) ||
                           (this.DeletedVolunteers != null && this.DeletedVolunteers.Count > 0);
            this.SaveVolunteerCommand.IsActive = canSave;
            return canSave;
        }

// ViewModel 2:

            this.SaveGroupCommand = new DelegateCommand<object>(SaveGroup, CanSaveGroup);
            GlobalCommands.SaveAllCommand.RegisterCommand(this.SaveGroupCommand);

        public bool CanSaveGroup(object state)
        {
            bool canSave = (this.UpdatedGroups != null && this.UpdatedGroups.Count > 0) ||
                           (this.DeletedGroups != null && this.DeletedGroups.Count > 0);
            this.SaveGroupCommand.IsActive = canSave;
            return canSave;
        }

When I call SaveGroupCommand.RaiseCanExecuteChanged I get a call to CanSaveGroup and the CompositeCommand becomes enabled which is want I want. But for some reason calling SaveVolunteerCommand.RaiseCanExecuteChanged is NOT calling CanSaveVolunteer so I can never get the SaveAllCommand to enable if I'm only dealing with ViewModel1. I find this a bit strange that one works but the other doesn't? Am I missing something obvious?

Thanks,

Neil

Aug 26, 2010 at 10:09 AM

Ok I'm an idiot. I got this working now. Basically my solution above wouldn't work because CompositeCommand checks if the child command IsActive before firing the CanExecute delegate therefore CanSaveVolunteers is never called and IsActive can never be set to true!

My revised solution works like a charm:

        public bool CanSaveVolunteers(object args)
        {
            return (this.UpdatedVolunteers != null && this.UpdatedVolunteers.Count > 0) ||
                   (this.DeletedVolunteers != null && this.DeletedVolunteers.Count > 0);
        }

        private void RaiseCanSaveVolunteer()
        {
            this.SaveVolunteersCommand.IsActive = CanSaveVolunteers(null);
            this.SaveVolunteersCommand.RaiseCanExecuteChanged();
        }

Instead of calling DelegateCommand.RaiseCanExecuteChanged() I have to call RaiseCanSaveVolunteer for this to work. So far its working perfectly for anyone else wanting to achieve the same kind of Save All function.

Regards,

Neil

Developer
Apr 25, 2012 at 8:19 PM

Hi,

For those interested in this subject, I believe you could also find the following blog post interesting:

Regards,

Agustin Adami
http://blogs.southworks.net/aadami