2
votes

I'm new to WPF. Currently, I want to allow my Add button to add item by using either single click or double click. However, when I try to double click, it ends up fire single click event twice. Code in XAML as below:

<Button.InputBindings>
    <MouseBinding Command="{Binding Path=AddCommand}" CommandParameter="{Binding}" MouseAction="LeftClick" />
    <MouseBinding Command="{Binding Path=AddCommand}" CommandParameter="{Binding}" MouseAction="LeftDoubleClick" />

I found solution online which is to use DispatcherTimer in order to solve the problem. I have inserted these in code behind:

private static DispatcherTimer myClickWaitTimer =
    new DispatcherTimer(
        new TimeSpan(0, 0, 0, 1),
        DispatcherPriority.Background,
        mouseWaitTimer_Tick,
        Dispatcher.CurrentDispatcher);

private void btnAdd_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
        // Stop the timer from ticking.
        myClickWaitTimer.Stop();

        // Handle Double Click Actions
}

private void btnAdd_Click(object sender, RoutedEventArgs e)
{
        myClickWaitTimer.Start();
}

private static void mouseWaitTimer_Tick(object sender, EventArgs e)
{
        myClickWaitTimer.Stop();

        // Handle Single Click Actions
}

So here comes my question. I've removed the MouseBinding in XAML and want to call for AddCommand in code behind but I'm having problem to do so due to the PrismEventAggregator. The AddCommand in .cs as below:

private void AddCommandExecute(Object commandArg)
{
     // Broadcast Prism event for adding item
     this.PrismEventAggregator.GetEvent<AddItemEvent>().Publish(
     new AddItemPayload()
       {
          BlockType = this.BlockType
       }
     );
}

Hence would like to know how to call for the AddCommand (which is a Prism Event in .cs) in Code behind?

Note: The button is inside resource dictionary thus I failed to use the button name to call for the command.

2

2 Answers

0
votes

You need to create a class which will subscribe to the event you are publishing and then execute the logic you want.

For example:

public class AddItemViewModel : INotifyPropertyChanged
{
    private IEventAggregator _eventAggregator;

    public AddItemViewModel(IEventAggregator eventAggregator)
    {
        _eventAggregator = eventAggregator;
        _eventAggregator.GetEvent<AddItemEvent>().Subscribe(AddItem);
    }

    private void AddItem(AddItemPayload payload)
    {
        // Your logic here
    }
}

Then when you publish the event it will trigger the subscriber and execute.

0
votes

Using Expression Blend SDK, you can create a Behavior that encapsulates all your custom logic. This behavior will offer two dependency properties for your command and its parameter, so you can easily create Bindings for them, exactly as you do this for your InputBindings.

Move your event handlers and DispatcherTimer logic into this behavior:

using System.Windows.Interactivity;

class ClickBehavior : Behavior<Button>
{
    // a dependency property for the command
    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.Register("Command", typeof(ICommand), 
            typeof(ClickBehavior), new PropertyMetadata(null));

    // a dependency property for the command's parameter        
    public static readonly DependencyProperty CommandParameterProperty =
        DependencyProperty.Register("CommandParameter", typeof(object), 
            typeof(ClickBehavior), new PropertyMetadata(null));

    public ICommand Command
    {
        get { return (ICommand)this.GetValue(CommandProperty); }
        set { this.SetValue(CommandProperty, value); }
    }

    public object CommandParameter
    {
        get { return this.GetValue(CommandParameterProperty); }
        set { this.SetValue(CommandParameterProperty, value); }
    }

    // on attaching to a button, subscribe to its Click and MouseDoubleClick events
    protected override void OnAttached()
    {
        this.AssociatedObject.Click += this.AssociatedObject_Click;
        this.AssociatedObject.MouseDoubleClick += this.AssociatedObject_MouseDoubleClick;
    }

    // on detaching, unsubscribe to prevent memory leaks
    protected override void OnDetaching()
    {
        this.AssociatedObject.Click -= this.AssociatedObject_Click;
        this.AssociatedObject.MouseDoubleClick -= this.AssociatedObject_MouseDoubleClick;
    }        

    // move your event handlers here        
    private void AssociatedObject_Click(object sender, RoutedEventArgs e)
    { //... }        

    private void AssociatedObject_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    { //... }

    // call this method in your event handlers to execute the command
    private void ExecuteCommand()
    {
        if (this.Command != null && this.Command.CanExecute(this.CommandParameter))
        {
            this.Command.Execute(this.CommandParameter);
        }
    }

The usage is very simple. You need to declare your additional namespaces:

<Window
    xmlns:local="Your.Behavior.Namespace"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    ...

Finally, attach the behavior to the button:

<Button>
    <i:Interaction.Behaviors>
        <local:ClickBehavior Command="{Binding AddCommand}" CommandParameter="{Binding}"/>
    </i:Interaction.Behaviors>
</Button>