6

Is there any way to stop the Button command execution based on some condition on its click event?

Actually I want to have confirmation popup on some of the button click in our application. To make it a general solution, I have done the following:

  1. I have extension of WPF button class call AppBarButton which already contains some dependency properties.
  2. I have 2 more properties for this as below: IsActionConfirmationRequired and ConfirmationActionCommand.

If IsActionConfirmationRequired then on left button cick event I am opening the confirmation popup.

Is there any way to avoid creating new ConfirmationActionCommand, and use the same Command property of the Button? The problem I am getting if I set Command, then on Button click even if user not confirmed the action still button command execute.

C#:

public class AppBarButton : Button
{
    public AppBarButton()
    {
        this.Click += AppBarButton_Click;
    }

    private void AppBarButton_Click(object sender, RoutedEventArgs e)
    {
        Button button = sender as Button;
        if (button == null || IsActionConfirmationRequired == false || ConfirmationActionCommand == null)
            return;

        const string defaultMessage = "Do you really want to {0}";

        string confirmationPopUpMessage = string.IsNullOrEmpty(ActionConfirmationMessage)
          ? DebugFormat.Format(defaultMessage, button.Content)
          : ActionConfirmationMessage;

        ConfirmationDailogDetails confirmationDailogDetails = new ConfirmationDailogDetails
        {
            Message = confirmationPopUpMessage,
            ActionName = button.Content.ToString(),
            Template = button.Template,
            ActionCommand = ConfirmationActionCommand
        };

        //instead of ConfirmationActionCommand want to use base.Command
        ConfirmationDailog dialog = new ConfirmationDailog(confirmationDailogDetails)
        {
            PlacementTarget = button,
            IsOpen = true
        };
    }

    public static readonly DependencyProperty IsActionConfirmationRequiredProperty =
        DependencyProperty.Register("IsActionConfirmationRequired", typeof(bool), typeof(AppBarButton));

    public static readonly DependencyProperty ActionConfirmationMessageProperty =
        DependencyProperty.Register("ActionConfirmationMessage", typeof(string), typeof(AppBarButton));

    public static readonly DependencyProperty ConfirmationActionCommandProperty =
       DependencyProperty.Register("ConfirmationActionCommand", typeof(ICommand), typeof(AppBarButton));

    /// <summary>
    /// Gets or sets the flag to show the confirmation popup on before taking any action on App Bar button click.
    /// Also its required to set the command in Tag Property of the App Bar button not in the Command Property, then only required command will fire only when user
    /// confirms and click on the action button on confirmation popup.
    /// </summary>
    public bool IsActionConfirmationRequired
    {
        get { return (bool)GetValue(IsActionConfirmationRequiredProperty); }
        set { SetValue(IsActionConfirmationRequiredProperty, value); }
    }

    /// <summary>
    /// Gets or sets the confirmation message in confirmation popup  before taking any action on App Bar button click.
    /// </summary>
    public ICommand ConfirmationActionCommand
    {
        get { return (ICommand)GetValue(ConfirmationActionCommandProperty); }
        set { SetValue(ConfirmationActionCommandProperty, value); }
    }
}

XAML:

<controls:AppBarButton x:Key="WithdrawAll"
                       AppBarOrder="1"
                       PageIndex="1"
                       AppBarOrientation="Left"
                       Content="Withdraw" IsActionConfirmationRequired="True"
                       ConfirmationActionCommand="{Binding WithdrawAllCommand}"
                       Template="{StaticResource DeleteCircleIcon}" />

Please suggest something. I am not able to find anything. Already tried CanExecute to false, but its make button disable so no use. I just simple dont want make another command, and developer who will use this AppBarButton need to set ConfirmationActionCommand not normal Command.

Yoh Deadfall
  • 2,711
  • 7
  • 28
  • 32
Neha
  • 103
  • 2
  • 8
  • Hi, have you tried binding the click event into your xaml.cs, from their you can check the properties on the button and call the base click event. – Chris Oct 22 '15 at 14:37
  • 1
    Do you want to show the `ConfirmationDailog` and execute `Button.Command` only if the dialog returns `true`? – Yoh Deadfall Oct 22 '15 at 15:00

2 Answers2

3

Instead of the click event, handle the PreviewMouseLeftButtonDown event. This occurs before the command executes. In the handler ask for confirmation and set the Handled property of the event to true or false.
If you set it to true, the command will not be executed.

private void btn_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    var confirmed = true;   //use your confirmation instead
    e.Handled = confirmed;
}

Here is how your code could look like (I dont know exactly because I dont have the code for ConfirmationDailog:

public class AppBarButton : Button
{
    public AppBarButton()
    {
        this.PreviewMouseLeftButtonDown += AppBarButton_PreviewMouseLeftButtonDown; ;
    }

    private void AppBarButton_PreviewMouseLeftButtonDown(object sender, RoutedEventArgs e)
    {
        Button button = sender as Button;
        if (button == null || IsActionConfirmationRequired == false || ConfirmationActionCommand == null)
            return;

        const string defaultMessage = "Do you really want to {0}";

        string confirmationPopUpMessage = string.IsNullOrEmpty(ActionConfirmationMessage)
          ? DebugFormat.Format(defaultMessage, button.Content)
          : ActionConfirmationMessage;

        ConfirmationDailogDetails confirmationDailogDetails = new ConfirmationDailogDetails
        {
            Message = confirmationPopUpMessage,
            ActionName = button.Content.ToString(),
            Template = button.Template,
            ActionCommand = ConfirmationActionCommand
        };
        **//instead of ConfirmationActionCommand want to use base.Command**
       ConfirmationDailog dialog = new ConfirmationDailog(confirmationDailogDetails)
       {
           PlacementTarget = button,
           IsOpen = true
       };
        //validation here
        dialog.ShowDialog();
        var confirmed = dialog.IsConfirmed;
        e.Handled = confirmed;
    }
    ...
Domysee
  • 12,718
  • 10
  • 53
  • 84
  • 2
    Not good. This is not a click but a button down. Click only occurs when the button was released. The user knows that and expects it. – ygoe Sep 20 '16 at 09:09
  • Can you fix up your answer to use `PreviewMouseLeftButtonUp` instead of `PreviewMouseLeftButtonDown`? Actually in your first example you're already using the UP event, but the rest of your code is not; a user click should be validated at an UP event only, because clicking, holding and moving the mouse away from the button then releasing it would cancel the click, many users are aware of it, so DOWN events should not be used in this context. – Simple Apr 25 '22 at 13:15
3

If I correctly understand, you want to confirm user's action and execute a command which is stored in the ButtonBase.Command property.

To achieve that remove the ConfirmationActionCommand property and use the OnClick method instead of the Click event. In the overriden OnClick method call the base method which will execute a command from the Command property if an user confirmed an action or there is no confirmation required.

public class AppBarButton : Button
{
    public static readonly DependencyProperty IsActionConfirmationRequiredProperty =
        DependencyProperty.Register("IsActionConfirmationRequired", typeof(bool), typeof(AppBarButton));

    public static readonly DependencyProperty ActionConfirmationMessageProperty =
        DependencyProperty.Register("ActionConfirmationMessage", typeof(string), typeof(AppBarButton));

    public bool IsActionConfirmationRequired
    {
        get { return (bool)GetValue(IsActionConfirmationRequiredProperty); }
        set { SetValue(IsActionConfirmationRequiredProperty, value); }
    }

    public string ActionConfirmationMessage
    {
        get { return (string)GetValue(ActionConfirmationMessageProperty ); }
        set { SetValue(ActionConfirmationMessageProperty , value); }
    }

    protected override void OnClick()
    {
        bool confirmed = true;

        if (IsActionConfirmationRequired)
        {
            ConfirmationDailogDetails confirmationDailogDetails = new ConfirmationDailogDetails
            {
                Message = confirmationPopUpMessage,
                ActionName = button.Content.ToString(),
                Template = button.Template,
                ActionCommand = ConfirmationActionCommand
            };

            ConfirmationDailog dialog = new ConfirmationDailog(confirmationDailogDetails)
            {
                PlacementTarget = button,
                IsOpen = true
            };

            // Set confirmed here

            // If you set the DialogResult property in the ConfirmationDailog class then
            // confirmed = dialog.ShowDialog().Value;
        }

        // If there is no confirmation requred or if an user have confirmed an action
        // then call base method which will execute a command if it exists.
        if (confirmed)
        {
            base.OnClick();
        }
    }
}
Yoh Deadfall
  • 2,711
  • 7
  • 28
  • 32
  • Thank you so much Yoh.. Its works perfectly fine... Solved my problem...I dont know why I have not thought in this direction... :P Superlike for solution... I dont know how can I vote you for this solution.... thank you so much.... – Neha Oct 23 '15 at 12:48
  • You can vote up or vote down by clicking on one of two arrows to the left of a post. Also you can accept answers on your questions. To know more take a [Tour](http://stackoverflow.com/tour) and visit the [Help Center](http://stackoverflow.com/help). – Yoh Deadfall Oct 23 '15 at 12:57
  • Cool.. done.. thank you so much once again.. for your your quick reply and posting the such a nice solution... :) :) – Neha Oct 23 '15 at 13:16
  • @YohDeadfall: HOw about using this for a `RadListBox` `SelectionChanged` event? It asks for the parameter. `base.OnSelectionChanged(//parameter here)`. Any ideas? – A Coder Jan 04 '16 at 12:17
  • @SanthoshKumar I've never worked with Telerik controls, but probably you should pass the `e` argument of your `OnSelectionChanged` override to the base method. – Yoh Deadfall Jan 04 '16 at 19:35