Search code examples
c#.netwpfpostsharp

Triggering "CanExecute" on postsharp [Command] when a document changes?


I am currently migrating a project to PostSharp to remove a lot of boilerplate code, most of it is going very smoothly but I'm left confused about how to force a command to recheck if it CanExecute. I expected PostSharp would inspect the command like it does properties to check for dependencies, here is a minimalist sample

[NotifyPropertyChanged]
public class MyWindowViewModel
{
    /// Anything bound to this refreshes just fine as expected
    public ObservableCollection<SomeType> Documents = new ObservableCollection<SomeType>();

   [Command]
   public ICommand AddDocumentCommand { get; set; }
   public void ExecuteAddDocument () { Documents.Add(new SomeType()); }

   [Command]
   public ICommand CloseDocumentCommand { get; set; }
   public bool CanExecuteCloseDocument () => Documents.Any(); 
   public void ExecuteCloseDocument () { Documents.Remove(Documents.Last()); }        
}

At start the collection is empty and the button attached to the close command is greyed as expected, however adding a document through the button attached to AddDocument doesn't activate the close document button, what is the appropriate way to accomplish what I need? Is PostSharp only considering assignments and not method calls as changes or is it something else entirely?


Solution

  • According to their Command documentation

    CanExecuteCloseDocument should be a property

    public bool CanExecuteCloseDocument => Documents.Any();
    

    The method option is used when the command requires parameters,

    The command availability check that depends on the input argument can be implemented as a method.

    for example

    public bool CanExecuteCloseDocument (int blah) => Documents.Any(); 
    public void ExecuteCloseDocument (int blah) { Documents.Remove(Documents.Last()); }
    

    That aside the main issue here is that the view is unaware of the changes to the collection to know to refresh property changes.

    Refer to this http://www.postsharp.net/blog/post/Announcing-PostSharp-42-RC

    Dependencies to collections

    When you add the [AggregateAllChanges] attribute to a field or automatic property, any change to a property of the object assigned to this field/property will be interpreted as a change to the field/property itself. The attribute now works only for collections.

    [NotifyPropertyChanged]
    public class MyWindowViewModel {
    
        /// Anything bound to this refreshes just fine as expected
        [AggregateAllChanges] // <-- when the collection changes to cause notification
        public ObservableCollection<SomeType> Documents { get; } = new ObservableCollection<SomeType>();
    
       [Command]
       public ICommand AddDocumentCommand { get; set; }
       public void ExecuteAddDocument () { Documents.Add(new SomeType()); }
    
       [Command]
       public ICommand CloseDocumentCommand { get; set; }
       public bool CanExecuteCloseDocument => Documents.Any(); 
       public void ExecuteCloseDocument () { Documents.Remove(Documents.Last()); }        
    }