DeutschEnglish

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

Mar 18

INotifyPropertyChanged via post production #5

CIL manipulation in action:

To test the PropertyChanged injector we’ve built in part #4, I suggest the following scenario: Build WpfApplication1 and view it in ILSpy. No surprises so far: the set_name () method contains only instructions for overriding the (automatically generated) backing field 'k__BackingField', and the Name property (shown at be end of the class) is flagged with the BindablePropertyAttribute attribute. Now run PropertyChangedInjector once, and refresh ILSpy‘s view: The set_Name () method has grown a little longer, the following three instructions have been added:

IL_0000: ldarg.0
IL_0001: ldarg.1
IL_0002: stfld string WpfApplication1.MainViewmodel::'<Name>k__BackingField'
IL_0007: ldarg.0
IL_0008: ldstr "Name"
IL_000d: call instance void WpfApplication1.MainViewmodel::RaisePropertyChanged(string)
IL_0012: ret

Now run WpfApplication1.exe by double-clicking it (not start debugging from Visual Studio, as this might trigger a rebuild step which will override the changes we’ve made from within the PropertyChangedInjector program!). You’ll notice that the name is refreshed on every button click, but not the sentence! Why is this? Well, our CIL manipulation step only includes code for raising the PropertyChanged event once (for the property itself), but in this case it needs to be fired a second time to indicate that also the Sentence property has changed.

Considering dependent properties:

A first approach towards firing several events to indicate that multiple properties have changed is as follows: In WpfApplication1, define an additional attribute that takes one (or several) arguments of type string:

[AttributeUsage(AttributeTargets.Property)]
public class UpdateAlsoAttribute : Attribute
{
	public UpdateAlsoAttribute(params string[] dependentProperties)
	{
	}
}

… and apply this to the Name property (in addition to the existing BindableProperty attribute, telling it that it should also raise the Sentence property’s changed event:

[BindableProperty, UpdateAlso("Sentence")]
public string Name { get; set; }

public string Sentence
{
	get { return String.Format("Hello, my name is {0}.", Name); }
}

Now we need to consider this newly defined attribute in the injector program. The desired goal is to inject several groups of CIL instructions (one for each PropertyChanged event), so I’d suggest to extract the code lines for creating and injecting CIL instructions to a separate method:

private static void InjectRaiseInstructions(ref ILProcessor processor, 
	Instruction insertBefore, MethodReference raiseMethod, string propertyName)
{
	// Create instructions that call the RaisePropertyChanged with the property's name as argument
	var raiseInstruction1 = processor.Create(OpCodes.Ldarg_0);
	var raiseInstruction2 = processor.Create(OpCodes.Ldstr, propertyName);
	var raiseInstruction3 = processor.Create(OpCodes.Call, raiseMethod);

	// Inject these instructions before the return call
	processor.InsertBefore(insertBefore, raiseInstruction1);
	processor.InsertBefore(insertBefore, raiseInstruction2);
	processor.InsertBefore(insertBefore, raiseInstruction3);
}

Obviously, the six lines for creating and injecting the CIL instructions can now be replaced by this new method:

// Extract the current property's name
string propertyName = property.Name;
var processor = property.SetMethod.Body.GetILProcessor();
// Find the last instruction in the current property's setter method (the return call)
var returnInstruction = property.SetMethod.Body.Instructions.LastOrDefault(i => i.OpCode.Code == Code.Ret);
// Inject the RaisePropertyChanged call
InjectRaiseInstructions(ref processor, returnInstruction, raiseMethod, propertyName);

In addition, we can now take into consideration the second attribute: For each property that is flagged with the BindableProperty attribute (and that will therefore be enhanced with the RaisePropertyChanged call), we check whether it is also flagged with the UpdateAlso attribute:

var updateAlsoAttribute = property.CustomAttributes.FirstOrDefault(a => a.AttributeType.Name.Equals("UpdateAlsoAttribute"));
if (updateAlsoAttribute != null)
{
	//TODO
}

If this is the case, we retrieve the UpdateAlso attribute’s arguments, which represent the names of those properties that depend on the current one:

foreach (var arguments in updateAlsoAttribute.ConstructorArguments)
{
	var dependentProperties = (CustomAttributeArgument[])arguments.Value;
	foreach (var dependentProperty in dependentProperties)
	{
		//TODO
	}
}

…and finally, for each of these dependent properties, we add a call to the RaisePropertyChanged method in CIL:

var dependentPropertyName = (string)dependentProperty.Value;
InjectRaiseInstructions(ref processor, returnInstruction, raiseMethod, dependentPropertyName);

The full injector program:

In total, the PropertyChanged injector’s Main method looks like this:

// Read assembly
var assembly = AssemblyDefinition.ReadAssembly(AssemblyPath);
foreach (var type in assembly.MainModule.Types)
{
	// Find all classes that inherit from INotifyPropertyChanged
	if (type.Interfaces.Any(i => i.FullName.Equals("System.ComponentModel.INotifyPropertyChanged")))
	{
		// Find the RaisePropertyChanged method within this class
		MethodReference raiseMethod = type.Methods.FirstOrDefault(m =>
			m.Name.Equals("RaisePropertyChanged") &&
			m.Parameters.Count == 1 &&
			m.Parameters[0].ParameterType.MetadataType == MetadataType.String);
		if (raiseMethod != null)
		{
			foreach (var property in type.Properties)
			{
				if (property.SetMethod != null)
				{
					// Find all properties that are marked with the BindableProperty attribute
					if (property.CustomAttributes.Any(a => a.AttributeType.Name.Equals("BindablePropertyAttribute")))
					{
						// Extract the current property's name
						string propertyName = property.Name;
						var processor = property.SetMethod.Body.GetILProcessor();
						// Find the last instruction in the current property's setter method (the return call)
						var returnInstruction = property.SetMethod.Body.Instructions
							.LastOrDefault(i => i.OpCode.Code == Code.Ret);
						// Inject the RaisePropertyChanged call
						InjectRaiseInstructions(ref processor, returnInstruction, raiseMethod, propertyName);

						var updateAlsoAttribute = property.CustomAttributes
							.FirstOrDefault(a => a.AttributeType.Name.Equals("UpdateAlsoAttribute"));
						// If the current property is also marked with the UpdateAlso attribute, parse this
						// attribute's parameters
						if (updateAlsoAttribute != null)
						{
							foreach (var arguments in updateAlsoAttribute.ConstructorArguments)
							{
								var dependentProperties = (CustomAttributeArgument[])arguments.Value;
								foreach (var dependentProperty in dependentProperties)
								{
									// Each of the UpdateAlso attribute's parameters corresponds to one property name, for
									// which the RaisePropertyChanged should be called
									var dependentPropertyName = (string)dependentProperty.Value;
									InjectRaiseInstructions(ref processor, returnInstruction, 
										raiseMethod, dependentPropertyName);
								}
							}
						}
					}
				}
			}
		}
	}
}
// Store the assembly
assembly.Write(AssemblyPath);

By now, it’s time for a disclaimer: Please note that this is far from production-ready code! For exampe, we’d need to add a few null checks and other handling for erroneous cases. In addition, it’s not sufficient to inject instructions that raise the PropertyChanged event – in contrast, we’d need an equality check which ensures that the property is only fired if old and new property value are different. Moreover, the two attributes could be combined into one, the RaisePropertyChanged and the two attributes’ declaration (which, at the moment, need to be present in each Viewmodel class) could be extracted, and many more improvements are possible.

If you’re interested in a working example, check out any of the existing projects that make use of the Mono.Cecil library! For example, my own MVVMbasics library contains a complete though rather simple implementation.

What’s more to do?

From the point of view of coding, this is all I’ll show you. I hope this series of articles provided you with a basic inside into CIL manipulation – if you want to dive deeper into the topic, the above-mentioned list of potential improvements should provide a starting point…

However, from an organizational point of view we’re not done yet. Wouldn’t it be nice if the injector was started automatically after each build, instead of invoking it manually? Continue to part #6 where I’ll discuss two aproaches for making that happen!

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

Mar 15

INotifyPropertyChanged via post production #4

In the previous blog post, we learned how to load compiled .NET applications into a C# project and read its CIL code. In this article, we’ll try to actively manipulate these CIL instructions!

Attribute-based property flagging

Let’s start with the WpfApplication1 program we implemented as test application: Introduce a new class BindablePropertyAttribute that is derived from Attribute – this class represents an attribute that will be used to flag those MVVM properties that should raise the PropertyChanged event. Therefore, we add the AttributeUsage attribute to specify that it may only be used to flag properties:

[AttributeUsage(AttributeTargets.Property)]
public class BindablePropertyAttribute : Attribute
{
}

Note that our attribute class has no content, not even a custom constructor, and it does nothing – its only purpose is to flag those properties that we want to manipulate after compilation!

Open the MainViewmodel class, and navigate to the Name property declaration. Replace the long custom property with a simple auto-property, and add the newly defined BindableProperty attribute:

[BindableProperty]
public string Name { get; set; }

Run the application, click the Change Name button… and don’t be disappointed if nothing happens! The Name property’s setter method does not raise the PropertyChanged event any more, so it’s not surprising that the UI does not reload the changed property’s content. Just aplying the BindableProperty attribute to the property declaraion doesn’t make the property bindable – we need to take care of that within our PropertyChangedInjector project.

Let’s get active!

This is the interesting part of not only reading, but actually manipulating the contents of a compiled .NET application! In the PropertyChangedInjector program, we need to add the following steps:

  1. Find all properties within each Viewmodel, which have a setter method defined (ok, we’ve done that already…) and which are flagged with the BindableProperty attribute:

    foreach (var property in type.Properties)
    {
    	if (property.SetMethod != null)
    	{
    		if (property.CustomAttributes.Any(a => a.AttributeType.Name.Equals("BindablePropertyAttribute")))
    		{
    			//TODO
    		}
    	}
    }
    
  2. Find a reference to the RaisePropertyChanged method (since we’ll need to call that method in a moment). This is done by filtering all methods defined in the Viewmodel itself or in its parent classes by name, parameter count, and parameter type:

    MethodReference raiseMethod = type.Methods.FirstOrDefault(m =>
    	m.Name.Equals("RaisePropertyChanged") &&
    	m.Parameters.Count == 1 &&
    	m.Parameters[0].ParameterType.MetadataType == MetadataType.String);
    
  3. For each of the detected properties (which fulfil the requirements defined above), retrieve their setter method’s CIL instructions, and add instructions which call the RaisePropertyChanged method and pass the property’s name to it as argument!

    This is done through the following operations:

    • Retrieve the property’s name and store it in a local variable (we’ll need it later to pass it to the RaisePropertyChanged method as argument):

      string propertyName = property.Name;
      
    • Among the property’s setter method’s CIL instructions, find the last one (this is the one that ends the method – CIL-code ret):

      var returnInstruction = property.SetMethod.Body.Instructions.LastOrDefault(i => i.OpCode.Code == Code.Ret);
      

      Apart from that, an auto-property’s setter method only contains instructions for storing a new value into the backing field. Between these and the ret instruction, we’ll inject our additional instructions for raising the PropertyChanged event!

    • Create three new CIL instructions that load the property’s name (remember, we stored it locally for this purpose) onto the stack, and call the RaisePropertyChanged (remember, we’ve searched for it!):

      var processor = property.SetMethod.Body.GetILProcessor();
      var raiseInstruction1 = processor.Create(OpCodes.Ldarg_0);
      var raiseInstruction2 = processor.Create(OpCodes.Ldstr, propertyName);
      var raiseInstruction3 = processor.Create(OpCodes.Call, raiseMethod);
      
    • Finally, inject these three instructions right before the ret instruction:

      processor.InsertBefore(returnInstruction, raiseInstruction1);
      processor.InsertBefore(returnInstruction, raiseInstruction2);
      processor.InsertBefore(returnInstruction, raiseInstruction3);
      
  4. Write back the changed CIL instructions to the target assembly:

    assembly.Write(AssemblyPath);
    

A summary of all code fragments:

In total, the PropertyChangedInjector program code looks like this:

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

static void Main()
{
	// Read assembly
	var assembly = AssemblyDefinition.ReadAssembly(AssemblyPath);
	foreach (var type in assembly.MainModule.Types)
	{
		// Find all classes that inherit from INotifyPropertyChanged
		if (type.Interfaces.Any(i => i.FullName.Equals("System.ComponentModel.INotifyPropertyChanged")))
		{
			// Find the RaisePropertyChanged method within this class
			MethodReference raiseMethod = type.Methods.FirstOrDefault(m =>
				m.Name.Equals("RaisePropertyChanged") &&
				m.Parameters.Count == 1 &&
				m.Parameters[0].ParameterType.MetadataType == MetadataType.String);
			if (raiseMethod != null)
			{
				foreach (var property in type.Properties)
				{
					if (property.SetMethod != null)
					{
						// Find all properties that are marked with the BindableProperty attribute
						if (property.CustomAttributes.Any(a => a.AttributeType.Name.Equals("BindablePropertyAttribute")))
						{
							// Extract the current property's name
							string propertyName = property.Name;
							var processor = property.SetMethod.Body.GetILProcessor();
							// Find the last instruction in the current property's setter method (the return call)
							var returnInstruction = property.SetMethod.Body.Instructions
								.LastOrDefault(i => i.OpCode.Code == Code.Ret);

							// Create instructions that call the RaisePropertyChanged with the property's name as argument
							var raiseInstruction1 = processor.Create(OpCodes.Ldarg_0);
							var raiseInstruction2 = processor.Create(OpCodes.Ldstr, propertyName);
							var raiseInstruction3 = processor.Create(OpCodes.Call, raiseMethod);

							// Inject these instructions before the return call
							processor.InsertBefore(returnInstruction, raiseInstruction1);
							processor.InsertBefore(returnInstruction, raiseInstruction2);
							processor.InsertBefore(returnInstruction, raiseInstruction3);
						}
					}
				}
			}
		}
	}
	// Store the assembly
	assembly.Write(AssemblyPath);
}

After you’ve included all the changes into your sources, follow me to INotifyPropertyChanged via post production #5 to see what we can do with this PropertyChanged injector!

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

Mar 07

INotifyPropertyChanged via post production #3

In the previous blog post, we found out how a custom property’s setter method (which raises the PropertyChanged event) looks like in CIL code compared to an auto-property. Before we can actually manipulate these CIL instructions, we need to know how to access them from C# code – that’s what this article is about to show!

Let’s get back to coding…

…and create a separate Visual Studio solution containing a new .NET project from stack. For testing CIL access, we choose a simple Console Application (I called it PropertyChangedInjector, because we’ll use this project throughout the following parts of this article to actually inject CIL code into existing applications). Our console application only contains one class Program with a typical entry point:

namespace PropertyChangedInjector
{
	class Program
	{
        static void Main()
		{
			// TODO
		}
	}
}

This program will take care of accessing (and, in the future, even manipulating) our WpfApplication1.exe assembly’s CIL code.

For reading and writing CIL code, we will use the Mono.Cecil library. I’ll show you how it can be used to access compiled .NET applications in a moment, first we need to install it. Fortunately, Mono.Cecil is available as NuGet package:

Installing the Mono.Cecil Nuget package 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Since we’re still testing, I suggest to store the target assembly’s file name (the path to the WpfApplication1.exe file) in a global constant variable – this way, it can be changed quickly, and we can still replace it with a configurable parameter later on:

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

The Main method is reponsible for the following steps:

  1. Load the target assembly into memory:

    var assembly = AssemblyDefinition.ReadAssembly(AssemblyPath);
    
  2. Loop through all classes found in that assembly:

    foreach (var type in assembly.MainModule.Types)
    {
    	//TODO
    }
    
  3. Find all Viewmodels, by looking for classes that implement the INotifyPropertyChanged interface (in our case, only one such class will be found):

    if (type.Interfaces.Any(i => i.FullName.Equals("System.ComponentModel.INotifyPropertyChanged")))
    {
    	//TODO
    }
    
  4. Loop through all properties within the current Viewmodel that define a setter method (again, in our case only one such property will be found – the Name property):

    foreach (var property in type.Properties)
    {
    	if (property.SetMethod != null)
    	{
    		//TODO
    	}
    }
    
  5. Retrieve this setter method’s CIL instructions:

    var instructions = property.SetMethod.Body.Instructions;
    

Once again, please…

We could now try to manipulate this set of CIL instructions – but for the moment, I decided to just print them to the console window. Let’s take a look at the full Main method:

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

static void Main()
{
	// Read assembly
	var assembly = AssemblyDefinition.ReadAssembly(AssemblyPath);
	foreach (var type in assembly.MainModule.Types)
	{
		// Find all classes that inherit from INotifyPropertyChanged
		if (type.Interfaces.Any(i => i.FullName.Equals("System.ComponentModel.INotifyPropertyChanged")))
		{
			foreach (var property in type.Properties)
			{
				if (property.SetMethod != null)
				{
					// List the instructions contained in the setter method of each property
					var instructions = property.SetMethod.Body.Instructions;
					foreach (var instruction in instructions)
					{
						Console.WriteLine(instruction.ToString());
					}
				}
			}
		}
	}
}

If you run the program, it should display the Name property’s getter method in CIL code. Alternatively, you can of course just set a breakpoint on line 17 and manually inspect the set of CIL instructions contained in the setter method. Both ways should result in the same set of instructions as seen in ILSpy.

The following screenshot shows part of the CIL instructions of the extended property setter (the one that raises the PropertyChanged event twice). I’ve marked the sections that call the RaisePropertyChanged method, since those are the ones we’ll be injecting manually in a later step:

A custom property's setter methods in Mono.Cecile 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

In the next blog post, it’s getting interesting – we’ll try to actually manipulate the CIL instructions we’ve retrieved by now!

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

Mar 04

INotifyPropertyChanged via post production #2

As mentioned in the first part, the ultimate goal of this article is to find a way for adapting .NET programs after their compilation. In a first approach, we’ll analyze the random name generator we created in part #1 of this article, to see what it looks like after compiling the C# code.

Some background knowledge:

In general, .NET code is not compiled into machine code directly. Instead, the C# compiler generates CIL (Common Intermediate Language) code which is interpreted by a virtual machine at runtime. One of the most convenient ways of analyzing CIL code is the ILSpy application which is open-source and can be downloaded for free from ilspy.net. This nice little tool can even decompile CIL code to C#, but for this project we’ll be satisfied by viewing CIL code.

Download, unpack and start ILSpy (it doesn’t need to be installed), and load the WpfApplication1.exe file that we’ve created in part #1 through the File | Open… menu. You’ll notice that the WpfApplication1 namespace appears in the list on the left border of the ILSpy application. Make sure that decompilation to C# or VB is deactivated by setting the drop-down box that is located in the menu bar to IL:

Deactivate decompilation in ILSpy 
 
 
 
 

Manual analysis:

Unfold the WpfApplication1 namespace, navigate to MainViewmodel and click it! In the main panel, the MainViewmodel class’ code should be displayed. The CIL code might look confusing at first sight, but the class is structured in a familiar way using { ... } blocks , // comments etc. All instructions within one block (e.g. within a method) are numbered consecutively in hexadecimal numbers. For a full list of CIL instructions see , I’ll explain the ones we’ll be using down the line.

Properties are decoded as a backing field as well as a getter and a setter method. For example, the Name property in our sample project can be displayed in two different ways:

When declaring Name as auto-property, the compiler automatically generates a backing field:

.field private string '<Name>k__BackingField'

… and two methods get_Name () and set_Name (string 'value') which contain a very simple logic: The getter loads the content of the backing field and returns it, while the setter expects a parameter value and sets that as the backing field’s value:

An auto-property's getter and setter methods in CIL 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

In contrast, if we specify Name as custom property including two calls to RaisePropertyChanged, there is no need in automatically creating a backing field since the _name can be used:

.field private string _name

The setter method set_Name (string 'value') is a bit longer in this case:

A custom property's setter methods in CIL 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Let’s analyze the most important instructions in detail (when reproducing on your machine, the numbers might be different but the sequence of instructions should look similar):

  • IL_0001 to IL_0003: Load both the value argument as well as the _name field onto the stack.
  • IL_0008: Compare the two values. The ceq instructions pushes 1 or 0 onto the stack, depending whether the two values are equal or not.
  • IL_000a and IL_000b: Load 0 onto the stack, and compare with the result of the previous ceq comparison.
  • IL_000f: Jump to the end of the method, if the previous comparison resulted false (meaning that the argument and the _name field contain equal values – in this case, we don’t need to update the backing field, and since there is no change in data we don’t need to raise the PropertyChanged event).
  • IL_0013 and IL_0014: Store the value argument’s content to the _name field.
  • IL_001a and IL_001f: Load the string "Name" onto the stack, call the RaisePropertyChanged method and pass the string to it as argument.
  • IL_0026 and IL_002b: Finally, do the same for the string "Sentence". Internally, the RaisePropertyChanged that is called twice will raise the PropertyChanged event.

Let’s get back to coding!

I hope it this manual inspection of CIL code helped you in getting a basic understanding of what our .NET program looks like after building it. However, for actually manipulating it in an automatical way, we must be able to access all those CIL instructions from within code – and that’s exactly what we’re trying to do next – check out INotifyPropertyChanged via post production #3!

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

Older posts «