Search code examples
c#asp.netwpfrelaycommandrouted-commands

Log events on RelayCommand vs RoutedCommand


I have the following problem:

I need to be able to log commands bound to the buttons in my code. The system that I am working on has all it's buttons as RelayCommand. I have found a website that explains how to do this, but with RoutedCommands. The link is a the button of the post. Here is an example of how it works with RoutedCommands:

public partial class Window1 : System.Windows.Window
            {
                public Window1()
                {
                    InitializeComponent();

                    CommandManager.AddPreviewExecutedHandler(this, this.OnPreviewCommandExecuted);

                    CommandManager.AddCanExecuteHandler(this, this.OnCommandCanExecute);
                }

                void OnPreviewCommandExecuted(object sender, ExecutedRoutedEventArgs e)
                {
                    StringBuilder msg = new StringBuilder();
                    msg.AppendLine();

                    RoutedCommand cmd = e.Command as RoutedCommand;
                    string name = cmd == null ? "n/a" : cmd.Name;

                    msg.AppendFormat("  Name={0}; Parameter={1}; Source={2}", name, e.Parameter, e.Source);
                    msg.AppendLine();

                    Logger.Log(msg.ToString());
                }

                void OnCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
                {
                    // For the sake of this demo, just allow all
                    // commands to be executed.
                    e.CanExecute = true;
                }
            }
        }

My problem is this doesn't work with RelayCommands and I can't afford to change all the RelayCommands to RoutedCommands.

Does anybody know how this can be implemented with RelayCommands?

Here is a example of a RelayCommand in my code:

            private RelayCommand _closePopupCommand = new RelayCommand(() => Window.PopUpViewModel = null);
            public RelayCommand ClosePopupCommand
            {
                get => _closePopupCommand;
                set
                {
                    _closePopupCommand = value;
                    RaisePropertyChanged();
                }
            }

And a the codebehind to route events:

            public readonly RoutedEvent ConditionalClickEvent = EventManager.RegisterRoutedEvent("test", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(Button));

Link to the website that implements RoutedCommands: https://joshsmithonwpf.wordpress.com/2007/10/25/logging-routed-commands/

I have tried with RelayCommands but they don't seem to have the same functionality as RoutedCommands I think it has to do with the RoutedEvents, that RoutedCommands binds. From what I see, there are 3 options:

  1. Can't be done
  2. I will have to change the RelayCommands to RoutedCommands
  3. Use something like RegisterEventHandlers

Solution

  • Perhaps listening to the Click event will suit you?

            public MainWindow()
            {
                InitializeComponent();
    
                AddHandler(ButtonBase.ClickEvent, (RoutedEventHandler)OnClickLoger, true);
    
            }
    
            private void OnClickLoger(object sender, RoutedEventArgs e)
            {
                if (e.Source is ButtonBase button && button.Command is ICommand command)
                {
                    if (command is RoutedCommand routedCommand)
                    {
                        Debug.WriteLine($"Button: Name=\"{button.Name}\"; RoutedCommand=\"{routedCommand.Name}\"; CommandParameter={button.CommandParameter} ");
                    }
                    else
                    {
                        var be = button.GetBindingExpression(ButtonBase.CommandProperty);
                        if (be is null)
                        {
                            Debug.WriteLine($"Button: Name=\"{button.Name}\"; Command=\"{command}\"; CommandParameter={button.CommandParameter} ");
                        }
                        else
                        {
                            Debug.WriteLine($"Button: Name=\"{button.Name}\"; Command Path=\"{be.ParentBinding.Path.Path}\"; CommandParameter={button.CommandParameter} ");
                        }
                    }
                }
            }