Dec 102013
 
 December 10, 2013  Posted by at 8:11 am WinRT  Add comments
InputConverter6

I learned something pretty cool a few days ago after a two day mission looking over all the different ways that you can work with the events provided by the control with a strict MVVM pattern. That is a longer blog post coming soon, talking about attached dependency properties, dependency properties, behaviors and attached behavior and more. I wanted to double check that I indeed had covered the topic well with reasonable good implementations, and since there is so much to XAML and its hard to know it all I relied on some valuable feedback from two friends of mine, Oren Novotny and Laurent Bugnion.

The first thing that came to mind when wanting to route  events to commands as you usually do with MVVM and XAML was to either create a dependency property or use behaviors and pass the event args. Out of the two behaviors would be a better way to go, allowing us to keep the UI logic in the XAML and also not having to wire up unnecessary dependency properties. Save those for special occasions. The question was however, how to I pass event args with InvokeCommandAction when the attribute for passing event args is missing in Windows Store Apps. I could pass in a property, such as the QueryText of the SearchBox (see my last blog post on implementing Search in Windows Store Apps), but not the event args which would let us access the object that we append search suggestions to as the user is typing.

This is where Laurent told me something rather cool that I didn’t know about, an attribute called InpuConverter found on the InvokeCommandAction (Windows Store only I believe). Here you can provide a converter which will get the event args as its value. You can then grab whatever you need and pass it to the command. And as Laurent said, its best to not pass in the arguments object as this gives us an undesired direct interaction with the ViewModel from the View.

Here is the code sample for this blog post that I made, on MSDN

Download from my blog

Or grab it from GitHub

The converter is, if you haven’t made a converter before (if you haven’t then start using them, they are pretty handy!) you simply create a class that inherits from the IValueConverter, and implement the two convert methods that converts the object to and from.

InputConverter6

if you get this when running the sample:

InputConverter00

Then you forgot to add a reference to the Behavior SDK 🙂

InputConverter0

I’ve been unable to find any documentation on the new attributes, but they are rather straight forward to use once you know how to use them. The three attributes are (one the InvokeCommand):

InputConverter

This one gets or sets the converter used for the command. The command has to be of type ICommand, and the converter of the type IValueConverter.

InputConverterLanguage

Gets or sets the language that is passed into the converter as a string

InputConverterParameter

Sets or gets the parameter passed into the converter. Notice that its passed to the converter not the command. So use this one when you need to convert the parameter. Otherwise, just use the CommandParameter.

Here is an MVVM implementation where I’m using the converter to pass in the objects I need in my command. The Delegate command is generic so I can create commands that know what type to expect.

I’ve provided images as well, in case the code snippets are broken in the future 🙂 Keen to know your thoughts!

Mainpage XAML

[sourcecode language=”XML”]
<Page
x:Class="InputConverterExample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:InputConverterExample"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
mc:Ignorable="d">

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<SearchBox SearchHistoryEnabled="False" x:Name="SearchBox" Width="500" Height="50">
<SearchBox.Resources>
<local:SearchArgsConverter x:Name="ArgsConverter"/>
</SearchBox.Resources>
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="SuggestionsRequested">
<core:InvokeCommandAction
Command="{Binding SuggestionRequest}"
InputConverter="{StaticResource ArgsConverter}"
InputConverterLanguage="en-US"
InputConverterParameter="{Binding ElementName=SearchBox, Path=SearchHistoryEnabled}"/>
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</SearchBox>
</Grid>
</Page>
[/sourcecode]

Mainpage codebehind (pull this out to a viewmodel)

[sourcecode language=”csharp”]
using System;
using System.Collections.Generic;
using System.Linq;

namespace InputConverterExample
{
public sealed partial class MainPage
{
public DelegateCommand<string> Search { get; set; }
public DelegateCommand<ISuggestionQuery> SuggestionRequest { get; set; }

public MainPage()
{
InitializeComponent();
Search = new DelegateCommand<string>(SearchedFor, o => true);
SuggestionRequest = new DelegateCommand<ISuggestionQuery>(SuggestionRequestFor, o => true);

DataContext = this;
}

private void SuggestionRequestFor(ISuggestionQuery query)
{
IEnumerable<string> filteredQuery = _data
.Where(suggestion => suggestion.StartsWith(query.QueryText,
StringComparison.CurrentCultureIgnoreCase));
query.Request.SearchSuggestionCollection.AppendQuerySuggestions(filteredQuery);
}

private readonly string[] _data = { "Banana", "Apple", "Meat", "Ham" };

private void SearchedFor(string queryText)
{
}
}
}

[/sourcecode]

converter

[sourcecode language=”csharp”]
using System;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;

namespace InputConverterExample
{
public sealed class SearchArgsConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var args = (SearchBoxSuggestionsRequestedEventArgs)value;
var displayHistory = (bool)parameter;

if (args == null) return value;
ISuggestionQuery item = new SuggestionQuery(args.Request, args.QueryText)
{
DisplayHistory = displayHistory
};
return item;
}

public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return value;
}
}
}

[/sourcecode]

Data interface

[sourcecode language=”csharp”]
using Windows.ApplicationModel.Search;

namespace InputConverterExample
{
public interface ISuggestionQuery
{
SearchSuggestionsRequest Request { get; }
string QueryText { get; }
bool DisplayHistory { get; set; }
}
}

[/sourcecode]

Data model

[sourcecode language=”csharp”]
using Windows.ApplicationModel.Search;

namespace InputConverterExample
{

public class SuggestionQuery : ISuggestionQuery
{
public SuggestionQuery(SearchSuggestionsRequest request, string queryText)
{
Request = request;
QueryText = queryText;
}

public SearchSuggestionsRequest Request { get; private set; }
public string QueryText { get; private set; }
public bool DisplayHistory { get; set; }
}
}

[/sourcecode]

delegatecommand

[sourcecode language=”csharp”]
using System;
using System.Windows.Input;

namespace InputConverterExample
{
public class DelegateCommand<T> : ICommand
{
private readonly Predicate<object> _canExecute;
private Action<T> _handler { get; set; }
public event EventHandler CanExecuteChanged;

public DelegateCommand(Action<T> handler, Predicate<object> canExecute)
{
this._handler = handler;
_canExecute = canExecute;
}

public void RaiseCanExecuteChanged()
{
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}

public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);
}

public void Execute(object parameter)
{
_handler((T)parameter);
}
}
[/sourcecode]

IMAGES 🙂 Click for larger size

InputConverter5 InputConverter4 InputConverter3 InputConverter2 InputConverter

  3 Responses to “Passing event arguments from XAML in Windows Store Apps (InputConverter, InputConverterParameter etc.)”

  1. Thank you very much for this post, im currently developing an app using mvvm light and i couldnt get any useful examples on how to manage events between the xaml and the viewmodel.
    Kisses from Spain!

    • Talking about MVVM light, it was actually Laurent (creator of MVVM light) that told me about these properties 😀 If you need help don’t hesitate to contact me, or Laurent! I’m @IrisClasson on twitter and Laurent is @LBugnion

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(required)

(required)

What is 3 + 10 ?
Please leave these two fields as-is:
IMPORTANT! To be able to proceed, you need to solve the following simple math (so we know that you are a human) :-)