Saturday, May 27, 2017

Interactive Command: How can i pass Event Argument to a command in the View Model from XAML

For Interactivity we have to use System.Windows.Interactivity dll , it is to make a command respond when WPF controls event raised without using any code behind.(This article not for how we can use Interactivity , it is for how we can send the event argument in the view model), many time we need the event argument of particular event for that control for some process, but in the MVVM we can not get the event argument directly.
lets start with a example, we have a textbox and we want to get the "TextChangedEventArgs" of method that is bind with command that we will hook with Textbox via Interactivity as the text change.

Code Download

Add the reference of  System.Windows.Interactivity.dll in the application.
Step1: The XAML is as follows, it has simply a textbox. as TextChanged event of textbox fire, we want to execute the command in view model.

<Window x:Class="Interactivity1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        xmlns:IntractComm="clr-namespace:InteractivityHelper">
    <Grid>
        <TextBox Height="23" HorizontalAlignment="Left" Margin="124,63,0,0" Name="TextBox1"
                 Text="" VerticalAlignment="Top" Width="200">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="TextChanged">
                    <IntractComm:InteractiveCommand Command="{Binding CommandWithEventArgs}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </TextBox>
    </Grid>
</Window>


Step 2: In the view model we define the command that will execute as text changed.
using System.Windows.Controls;
using System.Windows.Input;
using Microsoft.Practices.Prism.Commands;

namespace Interactivity1
{
    public class MainWindowVM
    {
        #region CommandWithEventArgs
        DelegateCommand<TextChangedEventArgs> _CommandWithEventArgs;
        /// <summary>
        /// Exposes <see cref="CommandWithEventArgs(MouseEventArgs)"/>.
        /// </summary>
        public DelegateCommand<TextChangedEventArgs> CommandWithEventArgs
        {
            get { return _CommandWithEventArgs ?? (_CommandWithEventArgs = new DelegateCommand<TextChangedEventArgs>(TextBoxTextChanged)); }
        }
        #endregion


        private void TextBoxTextChanged(TextChangedEventArgs e)
        {
            //some processimg
        }
    }
}


Step 3: Add the following class that inherit TriggerAction class

using System;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace InteractivityHelper
{
    public class InteractiveCommand : TriggerAction<DependencyObject>
    {
        protected override void Invoke(object parameter)
        {
            if (base.AssociatedObject != null)
            {
                ICommand command = this.ResolveCommand();
                if ((command != null) && command.CanExecute(parameter))
                {
                    command.Execute(parameter);
                }
            }
        }

        private ICommand ResolveCommand()
        {
            ICommand command = null;
            if (this.Command != null)
            {
                return this.Command;
            }
            if (base.AssociatedObject != null)
            {
                foreach (PropertyInfo info in base.AssociatedObject.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
                {
                    if (typeof(ICommand).IsAssignableFrom(info.PropertyType) && string.Equals(info.Name, this.CommandName, StringComparison.Ordinal))
                    {
                        command = (ICommand)info.GetValue(base.AssociatedObject, null);
                    }
                }
            }
            return command;
        }

        private string commandName;
        public string CommandName
        {
            get
            {
                base.ReadPreamble();
                return this.commandName;
            }
            set
            {
                if (this.CommandName != value)
                {
                    base.WritePreamble();
                    this.commandName = value;
                    base.WritePostscript();
                }
            }
        }

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

        // Using a DependencyProperty as the backing store for Command.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.Register("Command", typeof(ICommand), typeof(InteractiveCommand), new UIPropertyMetadata(null));
        #endregion
    }
}



This article explain how we get the event argument in viewmodel of an event generate by a WPF control.