DeutschEnglish

Aug 24

MVVM event to command binding #6: Specifics of the UWP platform

As a follow-up to the series of articles targeting XAML event binding, I promised to give an overview of the new possibilities UWP’s {x:Bind} syntax brings us:

As I’ve mentioned before, the statement that direct binding of event handlers is not possible is not strictly true when using the Universal Windows Platform. Simply using SomeEvent="{Binding MyEventHandler}" still does not work, but instead we can rely on the {x:Bind} syntax. However, a few things are important to notice – especially if you’re used to bind commands in the traditional way:

  • To begin with, {x:Bind} bindings do not target a control’s DataContext (regardless of whether we’re binding to commands, events, or data). Instead, if we do not specify an explicit target, bindings are resolved in the current view’s code-behind. This means if we define an event-handler in code-behind:

    public sealed partial class MainPage : Page
    {
        private void Button_OnTapped(object sender, TappedRoutedEventArgs e)
        {
            // add event handler logic here
        }
    }
    

    …we can bind to it from in XAML:

    <Button Tapped="{x:Bind Button_OnTapped}">tap me</Button>
    

    While this precise example has no advantage over traditional event handler reference (<Button Tapped="Button_OnTapped">), the mechanism of binding to event handlers allows us to use the MVVM pattern: If you define a ViewModel somewhere in your View class (I presented one way of doing so in my blog post MVVM and compiled bindings), you can directly map View events to the ViewModel method:

    <Button Tapped="{x:Bind ViewModel.DoSomething}">tap me</Button>
    
  • The approach of just relocating event handler methods to ViewModels and binding to them will quickly get you into trouble: ViewModels typically reside in some PCL layer in order to be used on different platforms. This means different types of event args that are platform-specific may not be available. Fortunately, {x:Bind} allows us use methods with generalized signatures as binding target – this means, that method parameters can be of a more generic type than originally specified in the event, and the binding algorithm will still find them. For example, compare the following event handler method to the one shown above:

    public class MainViewModel
    {
        public void Button_OnTapped(object sender, RoutedEventArgs e)
        {
            // ...
        }
    }
    

    Alternatively, it’s also possible to use no method parameters at all – in an MVVM context, this might be the most useful approach, since both the event’s sender (which typically is a user control) and the event args are platform-specific and therefore can’t be accessed on the ViewModel layer anyway:

    public class MainViewModel
    {
        public void Button_OnTapped()
        {
            // ...
        }
    }
    
  • One more thing that you should notice is that if you’re binding to methods that are not located in the current View class (meaning, in its code-behind), they need to be declared as public.

  • In addition, it is possible to bind to asynchronous methods: Just add the async keyword to the target method, and you can invoke asynchronous staff using await and still bind to it:

    public async void Button_OnTapped(object sender, RoutedEventArgs e)
    {
        await Task.Delay(TimeSpan.FromSeconds(3));
        // ...
    }
    

    While the above example works, it’s not the best way to implement asynchronous bindings, since asynchronous methods should always have a return type of Task. As mentioned before, {x:Bind} is clever enough to even find methods with slightly different signature. Fortunately, this also applies to the target method’s return type, which means that you can use a clean async Task signature:

    public async Task Button_OnTapped(object sender, RoutedEventArgs e)
    {
        await Task.Delay(TimeSpan.FromSeconds(3));
        // ...
    }
    

    Theoretically, it’s even possible to use other return types (both with synchronous and asynchronous methods), such as public int Button_OnTapped(), public Task<bool> Button_OnTapped(), etc. – The UWP binding algorithm will still find your method and bind to it. However, in practice this won’t be useful since XAML can’t do anything with the return value anyway.

  • With all these nice features at hand, keep one thing in mind: {x:Bind} to methods is not the same thing as binding to Commands, as there are no real commands involved! This means primarily that you’ll need to open up your business logic methods (since they need to be public to be used as binding target), without the additional safety net of a Command wrapped around the actual method.

    In addition, methods in contrast to commands do not provide a CanExecute condition. This means you’ll need to bind the respective control’s IsEnabled, Visibility, etc. properties to some ViewModel flag and / or business logic by hand if you want to ensure that a certain functionality should not be invoked at the moment.

Permanent link to this article: http://www.mobilemotion.eu/?p=1845&lang=en

Jun 23

MVVM event to command binding #5: Custom markup extensions

All the approaches we’ve been looking at so far are not sufficiently convenient in some way. In this artice, I’d like to present a solution that is really elegant – unfortunately, it has one major disadvantage.

Surprise, surprise!

This time, I’d like to start… with the result! Let me explain what we’re aiming at:

We all know the syntax . Unfortunately, as I mentioned earlier, this syntax does not work on event attributes. Technically, the Binding operation is referred to as a markup extension, and it is defined as Binding class somerwhere in the core .NET framework (to be exact, within the System.Windows.Data.Binding namespace).

Why am I telling all this? Well, the cool thing is that .NET allows the creation of custom markup extensions! This means, what we’re about to do is define our own operation – let’s call it EventBinding – that can be used in XAML as follows:

<Button Click="{EventBinding SomeCommand}">click me!</Button>

The code:

Custom markup extensions are defined as classes that should comply with two conditions:

  1. Inherit from the System.Windows.Markup.MarkupExtension class

  2. Have a name that ends with the term Extension (in a similar way as all custom Attributes should be named with the Attribute suffix)

In our case – since we’d like to use the term EventBinding as operation identifier, we call the extension class EventBindingExtension. This class is responsible for the following four tasks:

  1. Retrieve the name of a command that is passed to it via the constructor (since XAML, technically speaking, is only text and does not know different types, the command can only be passed as string, which why we cannot use the ICommand type to pass the Command itself but rather need to work with its name)

  2. Store this command identifier in a global variable to have it available any time

  3. Retrieve the user control’s attribute the extension was applied to (in our case, an event) – this is probably the most tricky part, so let’s postpone it for the moment

  4. Whenever the desired event fires, map the command identifier that has been stored to an actual command, and invoke it – I decided to extract this logic into its own method

public class EventBindingExtension : MarkupExtension
{
	private readonly string _commandName;

	public EventBindingExtension(string command)
	{
		_commandName = command;
	}

	private void InvokeCommand(object sender, EventArgs args)
	{
		if (!String.IsNullOrEmpty(_commandName))
		{
			var control = sender as FrameworkElement;
			if (control != null)
			{
				// Find control's ViewModel
				var viewmodel = control.DataContext;
				if (viewmodel != null)
				{
					// Command must be declared as public property within ViewModel
					var commandProperty = viewmodel.GetType().GetProperty(_commandName);
					if (commandProperty != null)
					{
						var command = commandProperty.GetValue(viewmodel) as ICommand;
						if (command != null)
						{
							// Execute Command and pass event arguments as parameter
							if (command.CanExecute(args))
							{
								command.Execute(args);
							}
						}
					}
				}
			}
		}
	}
}

This code snippet should not be too difficult to grasp. Let’s now add the third of the above-mentioned four tasks: To find out which XML attribute our markup extension has been applied to, we can override the ProvideValue method that is provided by the MarkupExtension class. Within this method, we retrieve the InvokeCommand method we’ve defined before (I decided to do this right at the beginning of the method logic, because if this should fail there’s no point in continuing).

Then, we retrieve the extension’s value target which corresponds to the attribute containing the markup extension – this can be done through the IServiceProvider object that is automatically passed to the method. We assume that the value target is an event, therefore we can retrieve it as either EventInfo or MethodInfo object. In both cases, we need to register our InvokeCommand method as event handler. If anything goes wrong within this method, it is recommended to throw a InvalidOperationException:

public override object ProvideValue(IServiceProvider serviceProvider)
{
	// Retrieve a reference to the InvokeCommand helper method declared below, using reflection
	MethodInfo invokeCommand = GetType().GetMethod("InvokeCommand", BindingFlags.Instance | BindingFlags.NonPublic);
	if (invokeCommand != null)
	{
		// Check if the current context is an event or a method call with two parameters
		var target = serviceProvider.GetService(typeof (IProvideValueTarget)) as IProvideValueTarget;
		if (target != null)
		{
			var property = target.TargetProperty;
			if (property is EventInfo)
			{
				// If the context is an event, simply return the helper method as delegate
				// (this delegate will be invoked when the event fires)
				var eventHandlerType = (property as EventInfo).EventHandlerType;
				return invokeCommand.CreateDelegate(eventHandlerType, this);
			}
			else if (property is MethodInfo)
			{
				// Some events are represented as method calls with 2 parameters:
				// The first parameter is the control that acts as the event's sender,
				// the second parameter is the actual event handler
				var methodParameters = (property as MethodInfo).GetParameters();
				if (methodParameters.Length == 2)
				{
					var eventHandlerType = methodParameters[1].ParameterType;
					return invokeCommand.CreateDelegate(eventHandlerType, this);
				}
			}
		}
	}
	throw new InvalidOperationException("The EventBinding markup extension is valid only in the context of events.");
}

Discussion:

At the first glance, this seems to be the perfect solution to the problem of event-to-command binding: It is short, easy to use, and easily readable (and understandable) by fellow developers. However, there is one major drawback: The WinRT / UWP platforms do not allow defining custom markup extensions, which means our approach only works on WPF, Silverlight, and Xamarin (although the syntax differs a bit on Xamarin, e.g. we need to extend the IMarkupExtension interface instead of the MarkupExtension class), but not in Windows Store Apps.

By the way, if you want to see the full EventBindingExtension class at one glance, note that I published it as GitHub project.

In the sixth and final blog post of this series, I’d like to point out a few specifics of the UWP platform that make event binding easier.

Permanent link to this article: http://www.mobilemotion.eu/?p=1837&lang=en

Jun 12

MVVM event to command binding #4: Predefined event handlers

In the next step, let’s take a look at an approach that eliminates two of the three major disadvantages of the solution using attached properties, namely performance issues and the fact that the event to be captured must be specified as string.

The code:

Even this one relies on attached properties to some extent, although in a much simpler way: In this case, there’s no need for an Event property, and no callback method is needed, all we need to specify in our EventToCommand helper class is one attached property Command:

class EventToCommand : DependencyObject
{
	public static readonly DependencyProperty CommandProperty =
		DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(EventToCommand));

	public static ICommand GetCommand(DependencyObject obj)
	{
		return (ICommand)obj.GetValue(CommandProperty);
	}

	public static void SetCommand(DependencyObject obj, ICommand value)
	{
		obj.SetValue(CommandProperty, value);
	}
}

In addition, it’s easily possible to define a second attached property CommandParameter the value of which can be passed to the Command later on:

public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.RegisterAttached(
	"CommandParameter", 
	typeof (object), 
	typeof (EventToCommand), 
	new PropertyMetadata(default(object)));

public static object GetCommandParameter(UIElement element)
{
	return element.GetValue(CommandParameterProperty);
}

public static void SetCommandParameter(UIElement element, object value)
{
	element.SetValue(CommandParameterProperty, value);
}

The idea is to use any user control’s existing event handler instead of specifying its name as string property. To do so, we need a BaseView class that wraps the respective platform’s View class (Window in WPF, Page in Windows Store Apps, etc.) and adds one additional method. All Views present within the project will then need to be derived from this wrapper class.

As an example, let’s take a look at the BaseView class for the WPF platform:

public class BaseView : Window
{
	protected void EventToCommand(object sender, EventArgs args)
	{
		var element = sender as UIElement;
		if (element != null)
		{
			// Check whether the sender has a Command defined in XAML
			var command = Event.GetCommand(element);
			if (command != null)
			{
				// If yes, check whether the sender has a CommandParameter defined in XAML (otherwise, we pass the event
				// args as parameter)
				object parameter = Event.GetCommandParameter(element);
				if (parameter == default(object))
					parameter = args;

				// Now evaluate this Command's CanExecute condition and, if allowed, invoke the Command
				if (command.CanExecute(parameter))
					command.Execute(parameter);
			}
		}
	}
}

All this event handler does is check wether the attached Command property has been specified for a specific user control, test its CanExecute condition, and invoke the Command. In addition, if the attached CommandParameter property has also been specified, we pass its content to the Command as parameter – if not, we simply pass on the event handlers event arguments, which might contain important information concerning the respective event that has been handled.

Usage of this approach in XAML is similar to the previously suggested solution, but with the improvement that the event name need not be passed as string, since the EventToCommand method is a known event handler within the class that contains our button:

<Button MouseDoubleClick="EventToCommand"
		local:EventToCommand.Command="{Binding SomeCommand}"
		local:EventToCommand.CommandParameter="some parameter value">
	click me
</Button>

Discussion:

The most obvious disadvantage of this solution is that it only bind one Event per user control (of course it would be possible to implement several predefined event handlers EventToCommand1, EventToCommand2, etc. and several attached property pairs, but still the number of event-to-command bindings will be limited).

On the other hand the clear advantage (especially compared to the solution I’ll present in the next article, which eliminates the limitation mentioned above) is that it works on all platforms. However, there are exception which need to be taken into account:

  • On the WinRT and UWP platforms, some user events pass arguments of type RoutedEventArgs. To be able to bind these as well to arbitrary Commands, we need an addition event handler to our View wrapper class which is nearly identical to the one seen above. The full BaseView class for the UWP platform looks as follows:

    public abstract class BaseView : Page
    {
    	protected void EventToCommand(object sender, EventArgs args)
    	{
    		var element = sender as UIElement;
    		if (element != null)
    		{
    			var command = Event.GetCommand(element);
    			if (command != null)
    			{
    				object parameter = Event.GetCommandParameter(element);
    				if (parameter == default(object))
    					parameter = args;
    
    				if (command.CanExecute(parameter))
    					command.Execute(parameter);
    			}
    		}
    	}
    
    	protected void EventToCommand(object sender, RoutedEventArgs args)
    	{
    		var element = sender as UIElement;
    		if (element != null)
    		{
    			var command = Event.GetCommand(element);
    			if (command != null)
    			{
    				object parameter = Event.GetCommandParameter(element);
    				if (parameter == default(object))
    					parameter = args;
    
    				if (command.CanExecute(parameter))
    					command.Execute(parameter);
    			}
    		}
    	}
    }
    
  • Silverlight doesn’t allow event handlers defined in base classes to be referenced directly from within XAML (due to a bug which I reported in a previous blog post). This means that we can attach the Command and CommandParameter properties conveniently in XAML, but need to register the EventToCommand method in a code-behind event handler, unfortunately.

In summary, the solution suggested in the article is not fully satisfying. In the next post, I’ll present a much more elegant approach using custom markup extensions!

Permanent link to this article: http://www.mobilemotion.eu/?p=1828&lang=en

Jun 03

MVVM event to command binding #3: Attached properties

In this article, I’d like to present a rather simple approach towards binding user events to Viewmodel commands in XAML in a shorter way than using behaviors and event triggers: This solution makes use of attached properties for defining both the event to be captured and the command to be invoked. Let’s once again first take a look at the implementation, then discuss its shortcomings.

The code:

First of all, we’ll need a class containing two attached properties. As mentioned before, one resembles the user event to be reacted to, and the other one the Command to be invoked on the event, so let’s call the two properties Event and Command:

class EventToCommand
{
	public static readonly DependencyProperty CommandProperty =
		DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(EventToCommand));

	public static ICommand GetCommand(DependencyObject obj)
	{
		return (ICommand)obj.GetValue(CommandProperty);
	}

	public static void SetCommand(DependencyObject obj, ICommand value)
	{
		obj.SetValue(CommandProperty, value);
	}
	
	public static readonly DependencyProperty EventProperty =
		DependencyProperty.RegisterAttached("Event", typeof(string), typeof(EventToCommand),
			new PropertyMetadata(EventPropertyChangedCallback));

	public static string GetEvent(DependencyObject obj)
	{
		return (string)obj.GetValue(EventProperty);
	}

	public static void SetEvent(DependencyObject obj, string value)
	{
		obj.SetValue(EventProperty, value);
	}
}

The idea is to be able to bind the Command property to some Command defined in the Viewmodel, in the same way as we’re used to from the conventional Command property most user controls provide, and to specify the desired event as string.

You’ll have noticed that the Event property declaration specifies an EventPropertyChangedCallback, which is a method that is invoked each time the Event property’s value changes. This will look as follows:

public static void EventPropertyChangedCallback(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
	string @event = (string)args.NewValue;
	var eventInfo = obj.GetType().GetEvent(@event);
	if (eventInfo != null)
	{
		var methodInfo = typeof(EventToCommand).GetMethod("OnEvent", BindingFlags.Static | BindingFlags.NonPublic);
		eventInfo.GetAddMethod().Invoke(obj,
			new object[] { Delegate.CreateDelegate(eventInfo.EventHandlerType, methodInfo) });
	}
}

So, each time an event is specified to be bound to, the Event property’s content is evaluated, the according event is found on the respective user control, and it is instructed to call the static OnEvent method whenever this event is fired. This method is still missing from our code sample, so here we go:

private static void OnEvent(object sender, RoutedEventArgs e)
{
	UIElement element = (UIElement)sender;
	if (element != null)
	{
		ICommand command = element.GetValue(CommandProperty) as ICommand;
		if (command != null && command.CanExecute(null))
		{
			command.Execute(null);
		}
	}
}

This one’s easily explained: The Viewmodel Command bound to is located, its CanExecute condition is evaluated, and then it is executed. Note that I’ve passed null to both the CanExecute and Execute methods, since in a typical ICommand they expect a command parameter to be passed. Of course, it would easily be possible to define a third attached property CommandParameter, and pass its value at this point.

How is this solution used in practice, e.g. if binding to a button’s MouseDoubleClick event?

<Button
		local:EventToCommand.Command="{Binding SomeCommand}"
		local:EventToCommand.Event="MouseDoubleClick">
	click me
</Button>

Discussion:

The clear advantage of this solution is that it’s short (only two additional properties are necessary on each user control) while still being verbose and self-explanatory. On the other hand, there are three major drawbacks:

  1. Since our two attached properties Command and Event can only be attached once to each user control, it’s only possible to capture one user event.
  2. The desired event is passed as string, which may easily lead to runtime errors due to simple XAML typos. This is a major decline in comfort especially when compared to conventional event handlers, which can be chosen from a list proposed by Intellisense.
  3. The performance issue: Since reflection is used to detect the desired event and attach a delegate to it, the solution might be slightly slower than comparable approached. However, this is not a severe handicap as the reflection logic is only executed once when specifying the event and the Command, not each time the Command is invoked.

In the following blog post, we’ll take a look at an alternative solution which can eliminate at least two of the disadvantages listed above!

Permanent link to this article: http://www.mobilemotion.eu/?p=1822&lang=en

May 25

MVVM event to command binding #2: Behaviors and event triggers

The recommended way of coupling user control events and Viewmodel Commands is the use of behaviors or event triggers. This approach is available for most platforms and XAML dialects, although detailed implementations differ. Let’s take a look at how to use this approach, and then discuss its benefits and drawbacks!

Windows Store / Phone / Universal Apps:

In Windows 8 / Windows Phone 8 App projects, we first need to reference the Behavior SDK which is available as an extension to the WinRT framework: Right click References in the Solution Explorer, choose Windows > Extensions in the Reference Manager window, and select the Behaviors SDK (XAML) entry:

Add a reference to the Behaviors SDK 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

In contrast, on the Windows 10 UWP platform it’s recommended to reference the XAML Behaviors NuGet package (search for Microsoft.Xaml.Behaviors.Uwp.Managed in the NuGet package manager and install the latest version).

In addition, on both platform we need to declare two namespaces in the header of each View that will contain an event-to-command binding:

<Page
	xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
    xmlns:core="using:Microsoft.Xaml.Interactions.Core"
	... >

Now we’re able to attach an EventTriggerBehavior to any user control’s event:

<Button>
	<interactivity:Interaction.Behaviors>
		<core:EventTriggerBehavior EventName="DoubleTapped">
			<!-- TODO -->
		</core:EventTriggerBehavior>
	</interactivity:Interaction.Behaviors>
</Button>

The EventTriggerBehavior can be passed an Action (or, in more complex scenarios, a collection of several actions) to be executed when the event is fired. We’re using the predefined InvokeCommandAction that allows us binding to a Command present within the Viewmodel:

<Button>
	<interactivity:Interaction.Behaviors>
		<core:EventTriggerBehavior EventName="DoubleTapped">
			<core:InvokeCommandAction Command="{Binding SomeCommand}" />
		</core:EventTriggerBehavior>
	</interactivity:Interaction.Behaviors>
</Button>

WPF & Silverlight platforms:

On the WPF and Silverlight platforms (this even includes Windows Phone Silverlight projects!), we’re working with event triggers. Using the Reference Manager window, add System.Windows.Interactivity to the project’s references, and declare the following namespace in each View’s header:

<Window
	xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
	... >

Add reference to System.Windows.Interactivity 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

We can now add event triggers to any control:

<Button>
	<i:Interaction.Triggers>
		<i:EventTrigger EventName="MouseDoubleClick">
			<!-- TODO -->
		</i:EventTrigger>
	</i:Interaction.Triggers>
</Button>

Inside the trigger follows an instance of the InvokeCommandAction class we know already:

<Button>
	<i:Interaction.Triggers>
		<i:EventTrigger EventName="MouseDoubleClick">
			<i:InvokeCommandAction Command="{Binding SomeCommand}"/>
		</i:EventTrigger>
	</i:Interaction.Triggers>
</Button>

Discussion:

The main advantage of this approach is that it is available for all platforms (although realized in different ways, using either triggers or beahviors). An additional benefit is its flexibility: There exist additional predefined Actions in addition to the InvokeCommandAction that allow various actions to be carried out without writing one single line of C# code, and custom actions may be defined and then referenced in XAML code. Moreover, all those actions (predefined as well as custom-made) can be combined, since both EventTriggers and EventTriggerBehaviors accept collections of actions, all of which are executed when the specified event is triggered.

On the other hand, this approach is rather verbose. This need not be a disadvantage as it makes the code self-explanatory, but especially in simple cases as the one shown above (simple event-to-command binding without additional actions), I find it unnecessarily lengthy – the full Button declaration now takes 7 lines of XAML code, making the View code unnecessarily complex and more difficult to read. Especially beginners might be tempted to fall back to the use of traditional event handlers, taking into account that these can be desclared with only a few characters of XAML code (compared to the above-mentioned 7 lines).

In summary, the behavior / event based approach is the perfect solution for complex scenarios that combine multiple actions to be triggered for the same event. However, for simple event-to-command binding, there must be a shorter way. Let’s take a look at another approach in part #3 of this series of articles!

Permanent link to this article: http://www.mobilemotion.eu/?p=1808&lang=en

May 19

MVVM event to command binding #1

One of the core features of XAML is Data Binding. The {Binding ...} syntax helps us enforcing the MVVM pattern in that it allows displaying data stored in a Viewmodel to the user, and writing back data which was input by the user to the Viewmodel.

What about reacting to user-triggered events in contrast to data input? Traditionally, we’d subscribe to one of the events each user control offers, create an event handler method in code-behind, and process the desired logic in there. How does that comply with MVVM?

Let’s take a look at a few different cases of how to handle user events:

  1. User actions that shall have only visual effects can often be handled purely within XAML, e.g. through the element’s VisualStateManager. For example, to change a button’s inner color on the MouseEnter event, use its MouseOver visual state:
    <Style x:Key="MyButton" TargetType="{x:Type Button}">
    	<Setter Property="Template">
    		<Setter.Value>
    			<ControlTemplate TargetType="{x:Type Button}">
    				<Grid>
    					<Ellipse x:Name="ellipse" Fill="Yellow"/>
    					<ContentPresenter
    						HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
    						VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
    					<VisualStateManager.VisualStateGroups>
    						<VisualStateGroup x:Name="CommonStates">
    							<VisualState x:Name="Normal"/>
    							<VisualState x:Name="MouseOver">
    								<Storyboard>
    									<ColorAnimation
    										To="Red"
    										Duration="0"
    										Storyboard.TargetName="ellipse"
    										Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"/>
    								</Storyboard>
    							</VisualState>
    							<VisualState x:Name="Pressed" />
    							<VisualState x:Name="Disabled"/>
    						</VisualStateGroup>
    					</VisualStateManager.VisualStateGroups>
    				</Grid>
    			</ControlTemplate>
    		</Setter.Value>
    	</Setter>
    </Style>
    
  2. A similar result can be achieved using Triggers. Also this approach needs no code-behind:
    <ControlTemplate TargetType="{x:Type Button}">
    	<Grid>
    		<Ellipse x:Name="ellipse">
    			<Ellipse.Style>
    				<Style TargetType="Ellipse">
    					<Setter Property="Fill" Value="Yellow"/>
    					<Style.Triggers>
    						<Trigger Property="IsMouseOver" Value="True">
    							<Setter Property="Fill" Value="Red"/>
    						</Trigger>
    					</Style.Triggers>
    				</Style>
    			</Ellipse.Style>
    		</Ellipse>
    	</Grid>
    </ControlTemplate>
    
  3. In more complex settings, it might be simpler to rely to a code-behind event handler. This can be the case when handling two separate elements:
    <StackPanel>
    	<Button MouseMove="Button_MouseMove">click me</Button>
    	<TextBlock x:Name="text">watch me</TextBlock>
    </StackPanel>
    
    private void Button_MouseMove(object sender, MouseEventArgs e)
    {
    	text.Visibility = Visibility.Hidden;
    }
    

    If the event has only visual effects, this still does not break the MVVM pattern, since everything within the event handler is View logic – no need to bother the Viewmodel with it!

  4. What if the Viewmodel shall be notified about a user event, e.g. to trigger some business logic function? Fortunately, most user controls offer a Command property which we can bind to:
    <Button Command="{Binding SomeCommand}">click me</Button>
    

    A big advantage of this approach is that MVVM Commands even allow disabling user controls from within Viewmodel logic through defining a CanExecute condition (just a side note – we won’t go into detail about this mechanism this time).

  5. The problem of the Command-binding approach is that each of the default user controls provides only one Command property, which resembles the most commonly used event. What if we need to react to any other event? It’s not even mandatory to offer a Command property, so 3rd party controls (which, for example, were not designed to be used with MVVM) might not support Command binding at all.

    In some cases, Viewmodels can still be notified about user events. For example, to react to the SelectionChanged event of a list control, we could bind a Viewmodel property to the list’s SelectedIndex property, and trigger our custom logic in the property’s setter:

    private int _selectedIndex;
    public int SelectedIndex
    {
    	get { return _selectedIndex; }
    	set
    	{
    		if (!_selectedIndex.Equals(value))
    		{
    			_selectedIndex = value;
    			SelectionHasChanged();
    		}
    	}
    }
    
  6. After all, there are still cases which are not covered by the approaches listed above – one example might be a drag and drop operation, which typically includes several events some of which might trigger some business logic. The following line of code won’t work, since we can’t use the Binding markup extension on events (an exception is UWP’s x:Bind syntax, but we’ll come to the in a later part of this article):
    <ListBox Drop="{Binding DropCommand}"/>
    

    In those cases, we typically create an event handler method in code-behind, and execute a Viewmodel Command from there:

    private void ListBox_Drop(object sender, DragEventArgs e)
    {
    	var vm = DataContext as MainViewmodel;
    	if (vm != null)
    	{
    		if (vm.DropCommand.CanExecute())
    		{
    			vm.DropCommand.Execute();
    		}
    	}
    }
    

There exist several problems with the last approach listed above: First of all, we need to access the control’s Viewmodel somehow (e.g., through its DataContext property). In addition, the fact that the event handler is hidden in code-behind makes our code less readable (compared to code purely written in XAML). Finally, if we are forced to switch to C# code anyway, we might easily be tempted to handle the desired business logic in there, instead of tediously referencing the Viewmodel – and this finally breaks the MVVM pattern.

So, there must be another way of coupling user control events and Viewmodel actions – in fact, there are several ways of doing so, each of which I’d like to discuss in one of the following blog posts. Let’s start with the universal but rather lengthy behavior / trigger based approach!

Permanent link to this article: http://www.mobilemotion.eu/?p=1806&lang=en

Apr 09

Template 10 vs. MVVMbasics: The best of both worlds #2

In the first part of this article, I presented a few ways for integrating MVVMbasics converters, commands, and data-binding mechanisms into Template 10 projects. However, what about the other features offered by the MVVMbasics framework?

Two approaches towards page navigation:

In theory, it is possible to completely replace Template 10’s navigation paradigm with MVVMbasicsNavigatorService, including all its features such as automatic binding of Viewmodels to Views, and Viewmodel navigation (instead of page navigation). The goal of such an approach might be to benefit from the full MVVMbasics features (meaning the cross-platform compatibility, in the first place), while additional controls and services defined by Template 10 are still available. However, as the term in theory shows, this approach proves impractical in real-life projects, due to several reasons.

Let’s once again take the Template 10 Minimal template as example, and walk through the basic steps of turning it into an MVVMbasics project. We’ll soon notice the most prominent problems this approach brings about. (Since the whole thing is experimental and not intended for use in production environments, please note that I’ll use the simplest – and not always cleanest – way of writing code, and only show the most relevant code snippets.)

Create a new project based on the Template 10 Minimal template, and reference the MVVMbasics NuGet package.

  • We’ll start by creating our own ViewModel base class that is based on the MVVMbasics BaseViewmodel class, and contains one member of type NavigatorService (since this service is needed in all the actual Viewmodels):

    using MVVMbasics.Services;
    using MVVMbasics.Viewmodels;
    
    namespace Template10App.ViewModels
    {
    	public class BaseVm : BaseViewmodel
    	{
    		protected INavigatorService NavigationService;
    
    		public BaseVm(INavigatorService navigationService)
    		{
    			NavigationService = navigationService;
    		}
    	}
    }
    
  • Now we can derive the three page Viewmodels (MainPageViewModel, DetailPageViewModel, and SettingsPageViewModel) from this new base class, instead of the ViewModelBase class provided by Template 10. For example:

    public class MainPageViewModel : BaseVm
    {
    	public MainPageViewModel(INavigatorService navigationService) : base(navigationService)
    	{
    		...
    	}
    }
    

    This also implies that the page navigation event handlers need to be adapted: Template 10 uses async method and its own enumeration of the current navigation mode, while MVVMbasics navigation methods are synchronous, use the ViewState enumeration, and allow passing several parameters. In case of the DetailPageViewModel, this looks as follows:

    //public override async Task OnNavigatedToAsync(object parameter, NavigationMode mode, IDictionary<string, object> suspensionState)
    //{
    //	Value = (suspensionState.ContainsKey(nameof(Value))) ? suspensionState[nameof(Value)]?.ToString() : parameter?.ToString();
    //	await Task.CompletedTask;
    //}
    
    public override void OnNavigatedTo(ParameterList uriParameters, ParameterList parameters, ViewState viewState)
    {
    	if (viewState == ViewState.Activated)
    		Value = parameters.Get<string>("Value");
    
    	base.OnNavigatedTo(uriParameters, parameters, viewState);
    }
    

    Note that I omit retrieving parameter values from suspension state to simplify things. It should be possible to make use of Template 10’s ISettingsService to implement our own suspension state handling mechanism.

    Finally, since we’ve replaced the navigation service, we need to adapt its calls: MVVMbasics‘ navigator service provides similar methods, but with slightly different names and arguments. In addition, MVVMbasics allows passing Viewmodels to the navigation methods, while Template 10 requires a separate call to resolve the View for a given Viewmodel, which can then be navigated to. For example, we adapt the MainPageViewModel‘s navigation methods as follows:

    public void GotoDetailsPage() =>
    	NavigationService.NavigateTo<DetailPageViewModel>("Value", Value);
    
    public void GotoSettings() =>
    	NavigationService.NavigateTo<SettingsPageViewModel>("SubPage", 0);
    
    public void GotoPrivacy() =>
    	NavigationService.NavigateTo<SettingsPageViewModel>("SubPage", 1);
    
    public void GotoAbout() =>
    	NavigationService.NavigateTo<SettingsPageViewModel>("SubPage", 2);
    
  • In MVVMbasics, Views need to inherit the BaseView class. In UWP, it’s recommended to also implement the IBindableView interface since this automatically binds the View to its corresponding Viewmodel. In case of the main page, this means the following adaptations:

    <mvvm:BaseView x:Class="Template10App.Views.MainPage"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:mvvm="using:MVVMbasics.Views"
    	  ...
    
    using Template10App.ViewModels;
    using MVVMbasics.Views;
    
    namespace Template10App.Views
    {
    	public sealed partial class MainPage : BaseView, IBindableView<MainPageViewModel>
    	{
    		public MainPage()
    		{
    			InitializeComponent();
    			// NavigationCacheMode = Windows.UI.Xaml.Navigation.NavigationCacheMode.Enabled;
    		}
    
    		public MainPageViewModel Vm { get; set; }
    	}
    }
    

    MVVMbasics Viewmodels are automatically cached, therefore page caching need not (and should not) be activated.

    Since Views and Viewmodels are paired automatically, we should also remove the explicitly set DataContext definition from all three pages’ XAML code.

    In addition, we must adapt all x:Bind data bindings in XAML to let them point to the Vm property (instead of the previously set ViewModel reference which we’ve just eliminated). For example, this applies to the following three lines in the main page:

    <AppBarButton Click="{x:Bind Vm.GotoSettings}" Label="Settings" />
    <AppBarButton Click="{x:Bind Vm.GotoPrivacy}" Label="Privacy" />
    <AppBarButton Click="{x:Bind Vm.GotoAbout}" Label="About" />
    
  • The SettingsPage‘s C# code-behind overrides the OnNavigatedTo method to retrieve a navigation parameter and show the correct pivot page. We remove this method completely and move the logic to the Viewmodel: Override its OnNavigatedTo method, in there retrieve the "SubPage" parameter, store it in some bindable property, and bind the pivot control to this property:

    public class SettingsPageViewModel : BaseVm
    {
    	[MvvmBindable]
    	public int SubPage { get; set; }
    
    	public override void OnNavigatedTo(ParameterList uriParameters, ParameterList parameters, ViewState viewState)
    	{
    		SubPage = parameters.Get<int>("SubPage");
    
    		base.OnNavigatedTo(uriParameters, parameters, viewState);
    	}
    	
    	...
    }
    
    <Pivot x:Name="MyPivot" Grid.Row="1"
    	   SelectedIndex="{Binding SubPage}" ...>
    
  • The final step is to replace Template 10’s bootstrapper by the MVVMbasics BaseApplication. For the moment, let’s ignore the splash screen and the app settings and simply comment these lines out. The only things absolutely necessary for our solution to build are:

    1. Instantiate MVVMbasicsNavigatorService, let it pair Viewmodels and Views, and register it to any IoC container (in this example, I’ll use the built-in Service property)
    2. Ensure that MainPage is loaded when starting up the App
    sealed partial class App : BaseApplication
    {
    	public App()
    	{
    		InitializeComponent();
    
    		NavigatorService navigatorService = new NavigatorService();
    		navigatorService.RegisterAll("Template10App.Views.*");
    		Services.Register(navigatorService);
    
    		// SplashFactory = (e) => new Views.Splash(e);
    
    		// #region App settings
    		// var _settings = SettingsService.Instance;
    		// RequestedTheme = _settings.AppTheme;
    		// CacheMaxDuration = _settings.CacheMaxDuration;
    		// ShowShellBackButton = _settings.UseShellBackButton;
    		// #endregion
    	}
    	protected override void OnLaunched(LaunchActivatedEventArgs e)
    	{
    		Frame rootFrame = Window.Current.Content as Frame;
    		if (rootFrame == null)
    		{
    			rootFrame = new Frame();
    			Window.Current.Content = rootFrame;
    		}
    
    		if (rootFrame.Content == null)
    		{
    			rootFrame.Navigate(typeof(MainPage), e.Arguments);
    		}
    
    		Window.Current.Activate();
    	}
    }
    

At this point, the solution should build successfully, but when starting the App, we’re running into problems which arise in the form of a NullReferenceException somewhere in Template 10’s helper library. The main reason is that the page header’s back button references some behavior defined by Template 10, and this relies on some dispatcher wrapping helper class, also defined somewhere in the helper library.

As a quick-and-dirty solution we can reference the Template 10 library’s sources and replace the dispatcher reference by CoreApplication.MainView.CoreWindow.Dispatcher, as this will at least allow the App to start up and display the first page. There might also be a way to solve the problem in a more robust way, by somehow referencing MVVMbasics‘ own DispatcherHelper instance that it keeps in each Viewmodel.

However, this problem is only the first example of a series of pitfalls we’ll most likely encounter when further refactoring the project. The Template 10 controls, behaviors, and services heavily rely on its own navigation pardigm (very similar to MVVMbasics Viewmodels relying on their own NavigatorService implementation).

Another legitimate doubt on this approach is that, at this point, we’ve got a pure MVVMbasics project – there is not much Template 10 left in it. So why bother starting from a template at all, instead of building a new MVVMbasics solution from scratch?

Conclusion:

After two blog posts full of analysis and comparison, the core question still remain: Which framework / template to use, and how to combine the best of both worlds? As I stated right at the beginning, it depends on what you’re up to:

  • If you do Windows 10 and know that this won’t change (and you’ll never like to add support for additional platforms), stick with Template 10. I’ve shown easy it is to reference MVVMbasics converters, and how advanced delegate commands can be used.

    We’ve also seen how MVVMbasics‘ advanced binding mechanisms can be integrated, although this deserves another short discussion: The main reason of using BaseModel over BindableBase will be that it allows data binding to auto-properties using the [MvvmBindable] etc. attributes, rather than the option of using advanced Set method overloads. To benefit from auto-property bindings, there are two alternatives to the approach shown in part #1 that don’t require changes in Template 10’s source code:

    • Several third-party components are available, some free to use and open-source, that solve the problem in a similar way by providing their own set of attributes – most of them will even work in combination with Template 10 ViewModels.
    • If you like the MVVMbasics way more than other libraries, its still possible to extract the NotifyPropertyChangedInjection project (it’s located in the MVVMbasics.CilInjection namespace), and adapt it to accept additional types of Viewmodel classes.
  • If you want to profit from the freedom MVVMbasics‘ cross-platform orientation provides (or if you simply like its NavigatorService functionalities), download the MVVMbasics project templates and use them to create a UWP project from stack. This has the additional advantage of automatically putting Viewmodels in a separate PCL project, which will be necessary anyway as soon as you want to target additional platforms. In this case, you can still extract certain controls or services from the Template 10 sources and adapt them specifically to MVVMbasics, instead of being forced to adapt all of them although you only need one or two.

Permanent link to this article: http://www.mobilemotion.eu/?p=1788&lang=en

Apr 08

Template 10 vs. MVVMbasics: The best of both worlds #1

Recently, I’ve been asked how the MVVMbasics framework can be integrated with the new Template 10 app templates. I played around a bit to analyze this in detail, and it turns out that it’s an interesting question with several potential answers, always depending on what you’re up to.

Templates and libraries:

But let’s start with the basics: Template 10 is an open source project driven by the community which aims at providing project templates for Windows 10 / UWP (Universal Windows Platform) apps. From a technical point of view, it basically consists of a VS project template package available from Visual Studio Gallery, and a library hosted on NuGet which is automatically referenced by the above-mentioned templates.

The templates contain sample files (pages, view models, etc.) as well as the directory structure for different types of projects, and these sample classes reference helper classes (controls, services, MVVM base classes etc.) which are packed into the NuGet library. Template 10 focuses on the project structure and wants to reduce the boilerplate code that need to be written in every app project. Although it does not intend to be a new MVVM framework, it contains some basic MVVM helpers, such as a simple delegate command, or a ViewModel base class implementing INotifyPropertyChanged, containing the typical Set method for shortening bindable property declaration.

On the other hand, MVVMbasics is an MVVM framework that also heavily relies on a template-like approach: While autonomous parts such as commands and converters can easily be referenced by any .NET project, to make use of advanced functions such as ViewModel navigation it’s necessary to implement View, ViewModel, and Application base classes.

The two projects being rather similar can be both a benefit or a disadvantage, depending on what you’re aiming at: The similar structure of projects realized using Template 10 or MVVM means a low entry threshold to Template 10 projects for developers who are used to MVVMbasics projects. At the same time, adapting the templates to fully integrate MVVMbasics can be a hard task.

Integrating converters:

One of the easiest tasks is to make use of one of the XAML value converters shipped with MVVMbasics. For example, we could force the busy text on the Template 10 Minimal template’s settings page to wrap after each word, by referencing MVVMbasicsTextWrapConverter:

Install the latest MVVMbasics NuGet package into the template project, and reference the TextWrapConverter class in the Busy view’s resources:

<UserControl x:Class="WindowsApp1.Views.Busy"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mvvm="using:MVVMbasics.Converters"
             xmlns:local="using:WindowsApp1.Views"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             d:DesignHeight="300" d:DesignWidth="400" mc:Ignorable="d">

	<UserControl.Resources>
		<mvvm:TextWrapConverter x:Key="TextWrapConverter"/>
	</UserControl.Resources>

Now let the converter change the text that this control shall display:

<TextBlock Text="{x:Bind BusyText, Mode=OneWay, FallbackValue='BusyText', 
                         Converter={StaticResource TextWrapConverter}, ConverterParameter=3}" />

When running the app and testing the busy display by tapping the Show Busy button on the Settings page, you’ll notice that the Please wait… text (or whichever text you entered on the settings page) is split into several lines.

Improved commanding:

Template 10 includes a simple delegate command which can easily be replaced by MVVMbasicsBaseCommand to benefit from its automatic CanExecute-update mechanism. Let’s take a look at the Show Busy button on the Template 10 Minimal template’s Settings page: It’s bound to the ShowBusyCommand defined in the SettingsPageViewModel. This command has an action assigned (show the busy screen, wait for 5 seconds, then hide it), as well as a CanExecute condition: The latter instructs the button to only execute the command, if the BusyText property contains some text. For this to work, the BusyText property’s setter method needs to raise the command’s RaiseCanExecuteChanged method each time the property’s content has changed.

Let’s convert this command (which, in the original template, is of the Template10-internal type DelegateCommand) to a BaseCommand – the delegate command base class provided by the MVVMbasics framework!

Again, the first step (if not done already) is to include the MVVMbasics library from NuGet. Then, replace the _ShowBusyCommand and ShowBusyCommand field’s / property’s type from DelegateCommand to BaseCommand. In addition, the command’s constructor expects a reference to the ViewModel as its third parameter:

BaseCommand _ShowBusyCommand;
public BaseCommand ShowBusyCommand 
	=> _ShowBusyCommand ?? (_ShowBusyCommand = new BaseCommand(
		async () => {
			Views.Busy.SetBusy(true, _BusyText);
			await Task.Delay(5000);
			Views.Busy.SetBusy(false);
		}, 
		() => !string.IsNullOrEmpty(BusyText), 
		this));

As a consequence, we can now remove the call to the command’s RaiseCanExecuteChanged method from the BusyText property’s setter:

public string BusyText
{
	get { return _BusyText; }
	set
	{
		Set(ref _BusyText, value);
		//_ShowBusyCommand.RaiseCanExecuteChanged();
	}
}

When running the App, you’ll see that the button is still disabled when clearing the text box, and enabled again when re-entering some text. The difference is that this is done automatically by the BaseCommand class.

Advanced binding:

As mentioned before, Template 10 includes ViewModelBase and BindableBase classes, which help implementing the INotifyPropertyChanged interface, by offering a Set method to be used by property setters that automatically fires the PropertyChanged event. All bindable properties in the template need to be declared as full properties, calling this Set method in their setter methods.

MVVMbasics‘s BaseViewmodel and BaseModel classes provide a similar method (also called Set), which includes a few convenient overloads that allow specifying delegates to be automatically invoked before or after the property update. In addition, the framework includes (among others) the [MvvmBindable] attribute that can be used to declare bindable properties as auto-properties. In MVVMbasics projects, bindable properties are generally declared as auto-properties and marked with this attribute, and full properties are only necessary when using one of the Set method overloads, thus shortening the overall amount of code lines.

Unfortunately, making use of these advanced binding mechanisms in Template 10 project is not as straightforward as, for example, using MVVMbasics‘ commanding mechanism. The reason for this is that we don’t want to completely replace Template 10’s ViewModelBase inheritance, since this class also includes service references and navigation event handlers.

Probably the best approach of combining both worlds is to check out the Template 10 library’s code and make a few minor adaptations in there: First, we need to add the MVVMbasics framework to the Template 10 library’s references (Note that MVVMbasics actually consists of two libraries: MVVMbasics and MVVMbasicsUWP – the former contains the core MVVM classes, while the latter provides extensions specific to the UWP platform. In our case, it’s sufficient to reference the core MVVMbasics.dll library, since all base classes we’ll need are located in there).

Now, find the BindableBase class (it’s located in the Template10.Mvvm namespace), remove the two Set method overloads, and inherit from MVVMbasics.Models.BaseModel such that the Set method defined in there replaces the old, deleted one. In addition, the two RaisePropertyChanged method overloads can also be simplified: All they need to do is invoke their BaseModel counterparts:

public abstract class BindableBase : BaseModel, IBindable
{
	public virtual void RaisePropertyChanged([CallerMemberName]string propertyName = null)
	{
		if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
			return;

		base.NotifyPropertyChanged(propertyName);
	}

	public virtual void RaisePropertyChanged<T>(Expression<Func<T>> propertyExpression)
	{
		if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
			return;

		base.NotifyPropertyChanged(propertyExpression);
	}
}

(Note that I used BaseModel as base class, instead of BaseViewmodel, as you might expect from any MVVMbasics project you’ve already seen! The reason is that the basic PropertyChanged event handling is defined within BaseModel. The BaseViewmodel class is derived from BaseModel and adds supplemental functionality that is needed only when used in combination with the MVVMbasics navigator service.)

With this adaptations in place, we are able to make use of the advanced binding options MVVMbasics offers. To test this, we can adapt the behavior of the Submit button in the Template 10 Minimal template’s main page, so that it changes the Value property’s content instead of navigating to the detail page! In the MainPageViewModel, simply change the GotoDetailsPage method’s body:

public void GotoDetailsPage() =>
	Value = "Test";
	// NavigationService.Navigate(typeof(Views.DetailPage), Value);

Now, when tapping that button, the content of the text box to its left is changed. If we replace the Value property by an auto-property and remove its backing field:

public string Value { get; set; }

…the button will do nothing (at least nothing visible, the Value property’s content is actually changed but not propagated to the View, since the PropertyChanged event is not raised any more). To change this, we can flag the Value property with the MvvmBindable attribute defined by the MVVMbasics framework to re-enable automatic property change propagation to the View:

[MvvmBindable]
public string Value { get; set; }

So far, we’ve seen a few ways of referencing MVVMbasics components in Template 10 projects. What if we want to go one step further, and replace Template 10’s navigation service with the one provided in MVVMbasics? I’ll discuss that in part #2 of this article!

Permanent link to this article: http://www.mobilemotion.eu/?p=1786&lang=en

Mar 31

INotifyPropertyChanged via post production #7

Finally, let’s look at a few improvements for the MSBuild task we’ve crated in part #6 of this article!

A parameterized build task:

The most obvious flaw in our design probably is the fact that the assembly path is hardcoded into the CIL injector program:

private const string AssemblyPath = @"C:\Documents\WpfApplication1\WpfApplication1\bin\Debug\WpfApplication1.exe";

Unfortunately, MSBuild tasks do not allow passing parameters directly to the Execute method. However, it is possible to set all public properties that are present in the class which contains the Execute method when calling the task. In our case, this means we can define the AssemblyPath from within the WpfApplication1.csproj‘s XML code:

<Target Name="AfterBuild">
	<PropertyChangedInjectorTask AssemblyPath="C:\Documents\WpfApplication1\WpfApplication1\bin\Debug\WpfApplication1.exe" />
</Target>

For this to work, the AssemblyPath field must be converter to a public property. In addition, we can flag it with the Required attribute. This way, the property must be specified in XML, otherwise the task won’t run (and the build won’t complete successfully):

[Required]
public string AssemblyPath { get; set; }

You can try this by re-opening the WpfApplication1 solution in Visual Studio and building it.

This is a slight improvement already, as the assembly path is not hardcoded into the CIL injector project anymore. Instead, it is hardcoded into the WpfApplication1 project, which is not the cleanest solution either. Fortunately, we can use Visual Studio macros within the project XML file. Take a look at the Macros for Build Commands and Properties page on MSDN: It contains a list of variable which may be used in VS project files, and which will be replaced before the actual build starts.

The $(TargetPath) macro looks promising: According to MSDN, it will be replaced by the absolute path name of the primary output file for the build (defined as drive + path + base name + file extension). Let’s try to use this as content of the AssemblyPath property, and see what happens:

<Target Name="AfterBuild">
	<PropertyChangedInjectorTask
			AssemblyPath="$(TargetPath)" />
</Target>

Since the macro is replaced before the build process starts, the CIL injector Library doesn’t need to worry about VS macros – instead, it is passed a string that contains the target assembly’s path and file name! Re-load and build WpfApplication1, and check if that works for you!

A more verbose build task:

As mentioned before, if the CIL injector fails, we see the error message in Visual Studio’s Error List and Output windows. Wouldn’t it be nice to get notified about successful build tasks also?

The Microsoft.Build.Utilities.Task class provides a Log property of type TaskLoggingHelper. Since our PropertyChangedInjectorTask class is derived from Task, we can simply access this Log property and use its member functions LogMessage(), LogWarning(), and LogError() (among other).

This allows us to report the build task’s current status, as well as errors back to the hosting Visual Studio solution. For example, the start of the Execute method could look like:

public override bool Execute()
{
	Log.LogMessage(MessageImportance.High, "Started PropertyChangedInjector build task!");
	
	// Read assembly
	Log.LogWarning("Reading target assembly...");
	try
	{
		var assembly = AssemblyDefinition.ReadAssembly(AssemblyPath);
	}
	catch (Exception e)
	{
		Log.LogError("Error while reading assembly: " + e.Message);
		return false;
	}

There are several overloads of each Log... method. For example, I used one to specify the log message’s importance in line 3 of the code snippet above. Note that, in contrast to warnings and errors, messages are not always visible in the Error List window, but if specifying a high importance they should at least appear in the Output window – play around with different MessageImportance settings to find out which works best for you!

When switching back to the WpfApplication1 project and building it, the warnings, errors and messages should be displayed (note that in this case I passed a wrong assembly path on purpose, to ensure that the error message is shown):

Visual Studio's Error List window 
 
 
 
 
 
 
 
 

1>  WpfApplication1 -> C:\Documents\WpfApplication1\WpfApplication1\bin\Debug\WpfApplication1.exe
1>  Started PropertyChangedInjector build task!
1>C:\Documents\WpfApplication1\WpfApplication1\WpfApplication1.csproj(103,2): warning : Reading target assembly...
1>C:\Documents\WpfApplication1\WpfApplication1\WpfApplication1.csproj(103,2): error : Error while reading assembly: Could not find file '...'.
1>C:\Documents\WpfApplication1\WpfApplication1\WpfApplication1.csproj(103,2): error MSB4018: The "PropertyChangedInjectorTask" task failed unexpectedly.

Further improvements:

As mentioned in one of the previous blog posts, our current CIL injection code lacks null checks and error handling – the above section about status reporting might give an idea of how exceptions can be filtered and reported back to the hosting Visual Studio instance.

Another problem you might come across is that at the moment it’s not possible to debug applications that have been manipulated by our post-build task. If you define a breakpoint anywhere in the WpfApplication1 code and run the application, you’ll see that the breakpoint can not be hit:

The breakpoint will not currently be hit. 
 
 
 
 
 
 

This can be solved by telling the CIL injector to read debug symbols while loading the assembly, and including them when writing back the manipulated assembly. I won’t go into detail about this, but you can find examples of how to do this on the web.

I hope these items provide you with ideas for adapting the CIL injector – feel free to play with it and find out what’s possible!

Permanent link to this article: http://www.mobilemotion.eu/?p=1772&lang=en

Mar 25

INotifyPropertyChanged via post production #6

To conclude this series of articles, I’d like to add two final blog posts that show what we can do to run our PropertyChanged injector we’ve built in part #5 automatically after each build:

The simplest post-build step:

Since our injector solution is a stand-alone .exe program, there is a really simple way of running it after each build: Open the WpfApplication1‘s properties (right-click the project in Solution Explorer and choose Properties), and switch to the Build Events tab. This window allows you to run custom commands before or after each build. Simply insert path and file name of the PropertyChangedInjector program as post-build event:

Defining a simple post-build action 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

With this set up, the specified task is run after every build. You can even start the WpfApplication1 from within Visual Studio (by clicking the Start debugging button or pressing F5), to check if the two labels are propertly updated.

A more sophisticated approach:

A more elegant solution is to register the injector as MSBuild task. To do so, a few adaptations in the PropertyChangedInjector‘s code are necessary:

First of all, an MSBuild task is registered as .dll file (in contrast to the stand-alone .exe we’ve been using as injector so far). Therefore, open the project’s properties and change its Output type from “Windows Application” to “Class library”:

Setting a project's output type to Class Library 
 
 
 
 
 

In addition, we need to reference some more libraries to be able to use the MSBuild Task Utilities. Right click the project’s References section in Solution Explorer and choose Add Reference… to open the Reference Manager windows. From the Framework section select the following libraries:

  • Microsoft.Build
  • Microsoft.Build.Framework
  • Microsoft.Build.Utilities.v4.0

References necessary for MSBuild tasks 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Now we rename the class Program to PropertyChangedInjector and make it inherit the Microsoft.Build.Utilities.Task class. For this we need to add two namespaces:

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace PropertyChangedInjector
{
	public class PropertyChangedInjectorTask : Task
	{

Since the project is no stand-alone application any more, we can also get rid of the static void Main() entry point. Instead, MSBuild tasks must provide an Execute that return a success flag:

public override bool Execute()
{
	// Include the old Main() method's contents here
	
	return true;
}

For this sample, I simply hard-code a return value of true. In real-life build tasks you’d need to add proper error handling and return false in case of an exception or an unexpected behavior. Why is this return value important at all? It decides on the overall success of the target project’s (e.g., our WpfApplication1) compilation – if your build task returns false, Visual Studio will mark the whole build as not successful.

At this point, you can build the PropertyChangedInjector project and ensure that it outputs a .dll file instead of the old .exe. Copy this PropertyChangedInjector.dll file’s full path to the clipboard, we’ll need it in a minute! (Of course, in production environments, you’d deploy it to some share that all Visual Studio projects can access, but for now it should be sufficient to leave it in its output folder and make all references point there.)

How do we use this custom build task? Obviously, it needs to be referenced somewhere in the WpfApplication1 project. First make sure to delete the post-build event from the Build Events tab – the PropertyChangedInjector.exe doesn’t exist any more, anyway. Then, close Visual Studio, look for the WpfApplication1.csproj file in Windows Explorer (this is the core project file), and open it in any notepad editor.

The XML structure you’ll see represents the whole C# project – here, all files and external libraries our project uses are referenced. Scroll down to the end of the file, there should be a section that looks somewhat like the following:

<!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
   Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->

The AfterBuild target that is referenced here is exactly what we need: We can add an arbitrary number of custom commands as XML nodes inside the Target Name="AfterBuild" tag, and they will be executed after each successful build! Uncomment these two XML tags, and add one simple task between them:

<Target Name="AfterBuild">
	<PropertyChangedInjectorTask />
</Target>

In addition, we’ll need to specify this task somewhere. This specification must include the file that includes the task (here, we paste the path that points to our PropertyChangedInjector.dll file), and the full namespace of the class that contains the public override bool Execute() method:

<UsingTask TaskName="PropertyChangedInjector.PropertyChangedInjectorTask"
	AssemblyFile="C:\Documents\PropertyChangedInjector\PropertyChangedInjector\bin\Debug\PropertyChangedInjector.dll" />

<Target Name="AfterBuild">
	<PropertyChangedInjectorTask />
</Target>

Now you can re-open the project in Visual Studio, and rebuild the whole solution. As a big advantage compared to the simple post-build event solution presented in the beginning of this article, the MSBuild task approach will provide us with feedback directly within Visual Studio’s Output and Error List windows: If something went wrong, you’ll see The "PropertyChangedInjectorTask" task failed unexpectedly. followed by the complete stack trace, which simplifies debugging the post-build task a lot.

Nevertheless, let’s hope that everything works out well and the build completes without errors. In this case, you should be able to verify the result by starting the WpfApplication1 application, and check if the labels are updated properly!

At this stage, there are only a few steps necessary to make our CIL injector fully versatile. To find out about these, I’ll ask you to switch to the final part of this article where we’ll look at these final improvements in detail!

Permanent link to this article: http://www.mobilemotion.eu/?p=1764&lang=en

Older posts «