2 Handling Events

So you have got the Basics down (basically you know about using databinding to pass data around). Well next up we look at Events. There are two ways to go about it depending on the circumstance:
  • Most controls provide a command property that you can set to an instance of an object that implements an ICommand.
  • In case you want to handle events (e.g. SelectionChanged on a ListBox) directly and transfer them to ICommand instance you can use EventToCommand.
Both are explained below. Also note that we set Commands the same way as we move data around. Using databinding!
The project we are using for this tutorial is called BasicEvents.

The application functional description: 

Its dead simple really. You have a listbox and a button. You select items in the list box or click a button. The number of times you do this is counted and displayed: 

The xaml is even simpler: 

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Class="BasicEvents.MainWindow"
        Title="MainWindow" Height="350" Width="525"
        xmlns:CinchV2="clr-namespace:Cinch;assembly=Cinch.WPF"
        xmlns:meffed="http:\\www.codeplex.com\MEFedMVVM"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"         
        meffed:ViewModelLocator.ViewModel="MainWindowViewModel">
    <StackPanel>
        <ListBox ItemsSource="{Binding ItemsAvailable}">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="SelectionChanged">
                    <CinchV2:EventToCommandTrigger Command="{Binding ListBoxCommand}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </ListBox>
        <Button Content="Click Me!" 
                Command="{Binding ButtonCommand}"/>
        <TextBlock Text="{Binding Path=CountOfButtonClicks, StringFormat=Button Clicked \{0:d\} times}"/>
        <TextBlock Text="{Binding CountOfSelectionClicks, StringFormat=Selection Changed \{0:d\} times}"/>
    </StackPanel>
</Window>
The items in bold are what you should understand. The namespaces / ViewModelLocator should be commonplace now.  
Next up there:
  • A ListBox 
  • A Button
  • TwoTextBlock's Keeping count of Button clicks and selection changed count by binding to datacontext properties. 

The ViewModel is where the meat is and where it should be

Lets look at the ViewModel now. Collapsed it looks like so: 
Three properties (added with cinch snippets) . Two (CountOfSelectionClicks and CountOfButtonClicks) are simple snippets of value types (int is a value type) as shown: 


And the final is a "INotifyPropertyChanged for collections"
This snippet is simply awesome and its expansion is presented here: 
 #region Property ItemsAvailable
        /// <summary>
        /// ItemsAvailable
        /// </summary>
        static PropertyChangedEventArgs _ItemsAvailableChangeArgs =
            ObservableHelper.CreateArgs<MainWindowViewModel>(x => x.ItemsAvailable);
        private DispatcherNotifiedObservableCollection<string> _ItemsAvailable = new DispatcherNotifiedObservableCollection<string>();
        public DispatcherNotifiedObservableCollection<string> ItemsAvailable
        {
            get { return _ItemsAvailable; }
            set
            {
                _ItemsAvailable = value;
                NotifyPropertyChanged(_ItemsAvailableChangeArgs);
                HasItemsAvailables = _ItemsAvailable.Count > 0;
            }
        }


        /// <summary>
        /// HasItemsAvailables
        /// </summary>
        static readonly PropertyChangedEventArgs hasItemsAvailablesChangeArgs = ObservableHelper.CreateArgs<MainWindowViewModel>(x => x.HasItemsAvailables);
        private Boolean hasItemsAvailables;
        public Boolean HasItemsAvailables
        {
            get { return hasItemsAvailables; }
            set
            {
                hasItemsAvailables = value;
                NotifyPropertyChanged(hasItemsAvailablesChangeArgs);
            }
        }
        #endregion

Notice that with one snippet you got a full implementation of HasItemsAvailables (checking if count of items is zero) as well. But more importantly notice "DispatcherNotifiedObservableCollection" . This class is a ThreadSafe! implementation of a collection that you can bind with Cinch. (AWESOME!) 

So that was about simple INotifyPropertyChanged properties. Next up the Events: 

Notice SimpleCommand<T1,T2>. Since we are not going to bind to its changes in commands it can be a simple .NET property (with a private setter for safety). 

T1 and T2 are the arguments of the event handler. T1 is (optionally) used to determine if the event can take place and T2 is what gets passed into function that gets executed when the event / command occurs.  Here are the two constructors : 

   public SimpleCommand(Action<T2> executeMethod);
   public SimpleCommand(Func<T1, bool> canExecuteMethod, Action<T2> executeMethod);

Notice T1 and T2. Good. 

Now lets see how to bind them to events or commands of a View item (which is declared in xaml)

Controls that provide a Command

e.g. Button. Really simple. Just bind the command property of the item to the Command exposed by the ViewModel: 
<Button Content="Click Me!" 
                Command="{Binding ButtonCommand}"/>
That was simple! Now when you click the Button the following code in the ViewModel is executed: 

(a) => CountOfButtonClicks++

Using an anonymous delegate you setup here in your ViewModel: 

When you want to turn an event occurring into a command execution

Cinch provides a blend behavior for this. Open the solution in expression blend. Goto Assets -> Behaviors and you will see the EventToCommandTrigger in there: 


What I did is dragged and dropped this behavior onto the Listbox in the main window. If done right you will see this behavior under ListBox in "Objects and Timeline" 
Next you need to set the Event and then the command (could it be any simpler!) 
Set the Event to SelectionChanged (using blend properties window. EventToCommandTrigger in "Objects and Timeline" is selected): 

And next set the Command using DataBinding : 


To "ListBoxCommand" as shown: 
All set. This just created the following xaml (bold section): 
        <ListBox ItemsSource="{Binding ItemsAvailable}">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="SelectionChanged">
                    <CinchV2:EventToCommandTrigger Command="{Binding ListBoxCommand}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </ListBox>
Addtional Note about Binding Formatting
It is always best for your ViewModel to contain as little presentation logic as possible. In that I view String formatting to be a GUI thing and WPF databinding makes it possible to specify it using string formatting. Here is the xaml (in bold): 
        <TextBlock Text="{Binding Path=CountOfButtonClicks, StringFormat=Button Clicked \{0:d\} times}"/>
And here is the Visual Studio interface to set it: 
Enjoy!  Remember to check out the BasicEvents project from here: 


Comments