Is there a way to get a callback when a Button completes execution of ICommand?

2.1k views Asked by At

Is there a way I can attach a handler (callback) in buttons of my control (which eventually execute the ICommand) so that my control knows when a command execution is completed?

1

There are 1 answers

1
Ivan Bianko On BEST ANSWER

You can create abstract CallbackableCommand that would raise callback method.

abstract class CallbackableCommand : ICommand
  {
    private IInputElement getRaisedElement()
    {
      return Keyboard.FocusedElement;      
    }

    public void Execute(object parameter)
    {
      ExecuteImpl(parameter);
      var element = getRaisedElement();
      if(element == null) return;

      //var ci = typeof(ExecutedRoutedEventArgs).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0];
      //var routedEventArgs = (RoutedEventArgs)ci.Invoke(new object[] { this, parameter });
      var routedEventArgs = new RoutedEventArgs();
      //routedEventArgs.RoutedEvent = CommandManager.ExecutedEvent;
      routedEventArgs.RoutedEvent = Callbackable.CommandExecutedEvent;
      routedEventArgs.Source = element;
      routedEventArgs.Handled = false;

      element.RaiseEvent(routedEventArgs);            
    }    

    public abstract void ExecuteImpl(object parameter);

    abstract public bool CanExecute(object parameter);

    abstract public event EventHandler CanExecuteChanged;
  }

Inherit your command from CallbackableCommand and override CanExecute, CanExecuteChanged and ExecuteImpl(instead of Execute)

  class SimpleCommand : CallbackableCommand
  {
    public override void ExecuteImpl(object parameter)
    {
      MessageBox.Show("Simple command execute with parameter: " 
        + parameter ?? "null");
    }

    public override bool CanExecute(object parameter)
    {
      return true;
    }

    public override event EventHandler CanExecuteChanged;
  }

Own element to specify CommandExecuted event:

  public class Callbackable : ContentControl
  {
    public static readonly RoutedEvent CommandExecutedEvent = EventManager.RegisterRoutedEvent(
        "CommandExecuted", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Callbackable));

    // Provide CLR accessors for the event
    public event RoutedEventHandler CommandExecuted
    {
      add { AddHandler(CommandExecutedEvent, value); }
      remove { RemoveHandler(CommandExecutedEvent, value); }
    }
  }

Edit: In your control specify Callbackable.CommandExecuted event

<Grid>
    <Grid.Resources>
        <local:SimpleCommand x:Key="btnCommand" />            
    </Grid.Resources>
    <local:Callbackable>
        <Button Command="{StaticResource btnCommand}"   
                CommandParameter="param"                
                local:Callbackable.CommandExecuted="Button_Executed" >
            Click me
        </Button>
    </local:Callbackable>
</Grid>

Executed event handler:

private void Button_Executed(object sender, ExecutedRoutedEventArgs e)
{
  MessageBox.Show("Executed");
}