DeutschEnglish

May 24

Retrieving logon information in a Store App

The short story:

When using the UserInformation.GetDomainNameAsync() method from within a Windows Store App, make sure that the app’s Enterprise Authentication capability is set, and be prepared for exceptions…

The long story:

As part of the line-of-business app I was recently blogging about, one requirement was to retrieve the Windows user name of the currently logged in user and pass it on to some web service.

Basically, all available Windows logon information can be retrieved via the Windows.System.UserProfile.UserInformation class. For example, the user name can easily be accessed by calling the GetDomainNameAsync method which returns the current user’s logon name including the domain name.

Although this sounds easy, on the first try all I got was an unhandled exception, so I looked into the method’s documentation in details and played around a bit. When using this method in one of your applications, note the following:

  • Obviously, the method runs asynchronously and needs to be awaited:

    var username = await Windows.System.UserProfile.UserInformation.GetDomainNameAsync();

  • The user needs to allow usage of the logon information in the machine’s privacy options:
    Privacy options: Allow logon information usage 
     
     
     
     
     
     
     

  • The apps’ Enterprise Authentication capability must be set:
    Store App Capabilities: Enterprise Authentication 
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     

  • Just in case, wrap the method call in a try / catch block and care for an alternative solution. Although the GetDomainNameAsync method’s documentation on MSDN states: If access is blocked, this method returns an empty string. This method does not throw an exception. – This is not true, for example if you forget checking the Enterprise Authentication capability, an UnauthorizedAccessException will be thrown!

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

May 20

Store Apps & Private network access

The short story:

To consume a domain-internal WCF service from within a Windows Store App, the app’s Private networks (Client & Server) capability must be set.

The long story:

Recently, I was (once again) coding a line-of-business app for company-internal use. This app connects to a server that resides within our company’s domain to consume a WCF service. The service’s WSDL was accessible through the web browser, and other (console) applications running on the same machine could communicate with the WCF service without problem. This particular Store App, however, failed with the following exception:

There was no endpoint listening at http://myserver/myservice.svc that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.

…with an InnerException saying "Unable to connect to the remote server".

The (obvious) solution:

Unfortunately this exception, although it’s correct of course, is somewhat misleading. I spent quite some time checking the service reference’s configurations, deleting and recreating the service reference, etc. because in any other application I had expected the problem to be somewhere in there. However, the final solution was surprisingly simple: Connecting to the web service failed because the app was not allowed to access the company network. I simply forgot to set the app’s Private networks (Client & Server) capability within its manifest file. After doing so, there were no more connection problems, and I knew I’d never again forget checking App capabilities…

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

Apr 27

Using template parameters in a Store App’s manifest

The short story:

When using parameters while creating Project Templates for Visual Studio, the default parameters (e.g., $safeprojectname$) are only replaced in code files. To enable parameter substitution for other files (e.g., a Windows Store App’s manifest file), set the ReplaceParameters attribute in the template’s .vstemplate file.

The long story:

Recently, I’ve been asked whether it was possible to use template parameters in a Windows Store App’s manifest file. For all of you who need a bit more background information: When exporting a project as template in Visual Studio, certain parts of the source code are replaced by predefined parameters, for example the namespace declaration in all code files is replaces with $safeprojectname$. Later on, when applying the template as a new project, there parameters are substituted with actual values, for example, all occurences of $safeprojectname$ are replaced with the new project’s name.

The problem is: Out of the box, this does not work for .appxmanifest files, although it would make sense to use template parameters in a Store App’s manifest to, for example, customize the app’s display name (by referencing $projectname$) or publisher name (through $registeredorganization$). Technically, this is not a problem since the .appxmanifest file is a simple XML file, so XML attributes and contents could be replaced by $...$ variables. The question is, what to do in order to make Visual Studio actually replace those variables?

The solution:

Technically, the template is just a .zip package that contains all the files that were present in the project that has been exported as template (C / C# / VB source files, manifest file, resources, etc.). When unpacking its contents to some local folder, you will find an additional file that was not part of that project, it is called [ProjectName].vstemplate.

This .vstemplate file acts as the template’s manifest. If you open it using notepad, you’ll find out that it is an XML file that contains:

  • the template’s meta data (name, description, icon, etc.),
  • and all of the projects references.

The latter includes both external references (e.g., to NuGet packages or DLL files), and internal references (meaning all source files that belong to the project). Those internal file references are listed as ProjectItem nodes and are structured within Folder nodes to represent the file system structur. For each ProjectItem, the XML attribute ReplaceParameters is defined – this attribute controls whether template parameters can be used within a certain file (and will be substituted on project creation) or not.

Now, the solution is simple: Find the .appxmanifest file in the list, change its ProjectItem to ReplaceParameters="true", and re-pack all files in a ZIP archive that now can be used as project template!

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

Apr 16

Data binding and image cache

One of the comfortable things in WPF data binding is the fact that a lot of types are converted automatically during binding. One example is the Image control and its Source property: This property is of type ImageSource, but it also accepts string input. To illustrate this, let’s assume that you have some string property in your Viewmodel that points to some local image on your hard drive:

private string _path;
public string Path
{
	get { return _path; }
	set { _path = value; RaisePropertyChanged("Path"); }
}

public MyViewmodel()
{
	Path = @"C:\image.png";
}

The View contains an Image control that binds to this string property:

<Image Source="{Binding Url}" />

The problem with this type of binding is that the image is loaded directly from the file to be rendered on the screen – trying to modify, swap, or even rename the file while the application is running will fail because the file is in use and locked by our WPF application.

The reason for this is that the automatic type conversion from string to ImageSource uses default settings and there is no way to customize it. If we’d manually create a BitmapImage (which inherits from ImageSource and can therefore be used as input to the image’s Source property), we’d set its BitmapCacheOption property to OnLoad, since this loads the image into memory at load time and instantly releases the image file. However, it’s unpleasant to hold an object of type BitmapImage in the Viewmodel (e.g. when targeting multiple platforms and keeping all Viewmodels within a Portable Class Library, the BitmapImage can not even be instantiated within the Viewmodel since it’s WPF specific).

The elegant solution here (as in many other cases) is a binding converter: It converts the Viewmodel’s string property to a platform-specific BitmapImage while resolving the binding expression, and sets the custom cache option during this process:

public class ImageConverter : IValueConverter
{
	public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
	{
		var path = value as string;
		if (path != null)
		{
			var uri = new Uri(path);
			var bitmap = new BitmapImage();
			bitmap.BeginInit();
			bitmap.UriSource = uri;
			bitmap.CacheOption = BitmapCacheOption.OnLoad;
			bitmap.EndInit();
			return bitmap;
		}
		return DependencyProperty.UnsetValue;
	}
}

This solution keeps the Viewmodel clean, while the binding expression in the View’s XAML code needs only be complemented by a short converter reference:

<Image Source="{Binding Url, Converter={StaticResource ImageConverter}}" />

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

Mar 31

[MVVMbasics] Passing custom parameters during event-to-command redirection

Notice

All blog posts with a title that starts with [MVVMbasics] are related to the MVVMbasics framework. If you are only interested in my regular blog posts and not in MVVMbasics, ignore these. To list all articles covering MVVMbasics, go to http://mvvmbasics.mobilemotion.eu/documentation!

In version 2.0 of the MVVMbasics framework, a simple way to redirect a UI event directly to a Viewmodel Command has been introduced, via the EventToCommand keyword and the Command attached property:

<ListBox SelectionChanged="EventToCommand" mvvm:Event.Command="{Binding ListSelectionChangedCommand}" ... />

This can be used as a short cut in many situations to avoid including the Interaction framework (which usually results in long XAML code lines) or invoking Viewmodel Commands from within code-behind event handlers.

With the 2.2 release, this feature has become more flexible: An additional attached property CommandParameter has been introduced that allows passing custom parameters to the target Command instead of the generic event arguments! The CommandParameter can be specified either as fixed value, or through Data Binding:

<ListBox x:Name="List"
         SelectionChanged="EventToCommand"
         mvvm:Event.Command="{Binding ListSelectionChangedCommand}"
         mvvm:Event.CommandParameter="{Binding ElementName=List, Path=SelectedItem}" />
<CustomControl DoubleClick="EventToCommand"
               mvvm:Event.Command="{Binding ActivatedCommand}"
               mvvm:Event.Command="123" />

In the Viewmodel, you instantiate the BaseCommand with a target method that accepts one parameter of type object, just as in the previous version. This parameter, however, will contain the passed parameter. Of course, it is still possible to get the raw event arguments forwarded to the Command by simple omitting the CommandParameter property, as in this case the event args will be automatically used as parameter.

Be aware, though, that you still need to declare the mvvm namespace in the View’s XAML header. In addition, please notice that Windows Phone Silverlight projects do not support the EventToCommand keyword due to a bug in the Silverlight platform. Instead you’ll need to attach the EventToCommand handler to the desired event in C# code-behind, as explained in detail in the original article presenting the MVVMbasics event-to-command binding solution!

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

Mar 22

[MVVMbasics] Attribute-based bindable property declaration

Notice

All blog posts with a title that starts with [MVVMbasics] are related to the MVVMbasics framework. If you are only interested in my regular blog posts and not in MVVMbasics, ignore these. To list all articles covering MVVMbasics, go to http://mvvmbasics.mobilemotion.eu/documentation!

Previous versions of the MVVMbasics framework provided the Set method to help shorten bindable property declarations in Models and Viewmodels:

private string _someText;
public string SomeText
{
	get { return _someText; }
	set { Set(ref _someText, value); }
}

The Set method sets the property’s value and raises the PropertyChanged event if necessary. This allows the reduction of the setter method’s body to only one line, however the full property declaration still needs several lines of code since it is still necessary to define getter and setter method as well as the backing field manually.

MVVMbasics 2.2 finally supports the use of auto-properties as bindable properties. Properties defined in Models or Viewmodels that are marked with the MVVMbasics.Attributes.MvvmBindable attribute automatically raise the PropertyChanged event when their value is updated:

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

While this significantly reduces code lines for bindable property declaration, it can still be simplified by using the [MvvmBindableProperties] attribute: In Viewmodels that contain many bindable properties, this attribute can be assigned to the Viewmodel class – in this case, all public properties defined within the Viewmodel class are treated as bindable, meaning that they will raise the PropertyChanged event when changed. To exclude single properties from this general rule, they can be marked with the [MvvmBindableIgnore] attribute:

[MvvmBindableProperties]
public class MyViewmodel : BaseViewmodel
{
	public string SomeText { get; set; }  // raises the PropertyChanged event
	
	public int SomeNumber { get; set; }  // raises the PropertyChanged event
	
	[MvvmBindableIgnore]
	public bool SomeInternalProperty { get; set; }  // does not raise the PropertyChanged event!
}

Please note that the [MvvmBindable...] attributes only work on properties that are defined within classes that inherit (directly or not) from the BaseModel or BaseViewmodel class! The reason for this limitation is that the automatic event raising mechanism that is responsible for all this magic relies on the NotifyPropertyChanged method which is defined by the BaseModel and BaseViewmodel classes.

Sometimes, bindable properties need to raise the PropertyChanged event more than once: The most typical case is a property that specifies only a getter method which returns a combination of several other properties:

public string FirstName { get; set; }

public string LastName { get; set; }

public string FullName
{
	get { return String.Format("{0} {1}", FirstName, LastName); }
}

The [MvvmBindable...] attributes even work in this case, since the underlying automatic event raising mechanism work in two iterations: First, all properties that don’t define a setter method are analyzed, and all the properties that are referenced in their getter methods are stored. In the second iteration, all properties that define setter methods are adapted, in order to raise their own PropertyChanged as well as all their dependent properties’ events! Note that for this to work, also the “read-only” properties (that only contain getter methods) need to be marked with the [MvvmBindable] attribute, or the whole class needs to be marked with the [MvvmBindableProperties] attribute.

public class MyViewmodel : BaseViewmodel
{
	[MvvmBindable]
	public string FirstName { get; set; }  // raises the PropertyChanged event for properties FirstName and FullName

	[MvvmBindable]
	public string LastName { get; set; }  // raises the PropertyChanged event for properties LastName and FullName

	[MvvmBindable]
	public string FullName
	{
		get { return String.Format("{0} {1}", FirstName, LastName); }
	}
}

Of course, the conventional way of creating a backing field and calling the Set method inside the property’s setter method is still available. For complex property declarations where the automatic event raising mechanism fails, you can still rely on this approach. Also if you like to automatically call a certain action before or after the property update, the Set method might be the better solution. All of the options it offers is documented in the article New version 2.0 features #2: Simplified Data Binding with more flexibility.

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

Mar 18

[MVVMbasics] Targeting the Android and iOS platforms via Xamarin.Forms #2

Notice

All blog posts with a title that starts with [MVVMbasics] are related to the MVVMbasics framework. If you are only interested in my regular blog posts and not in MVVMbasics, ignore these. To list all articles covering MVVMbasics, go to http://mvvmbasics.mobilemotion.eu/documentation!

Project setup in Xamarin Studio:

When using the Xamarin Starter, Indie, or Academic license (or when using Mac OS), it is not possible to use Visual Studio as IDE, instead you might be forced to use Xamarin Studio for development. In this case, you can basically follow the same steps for setting up the project structure as if you were using Visual Studio, however there are a few items that need special attention:

  • Xamarin Studio doesn’t support the creation of Windows Phone applications. Therefore, the solution won’t contain a WinPhone project.

    I’d strongly recommend to add an additional Portable Class Library (PCL) to the automatically created projects that contains all Data Models, Viewmodels, and Service interfaces. In this case, you can create a separate Windows Phone solution in Visual Studio, add a reference to this PCL project, and create a WinPhone application out of the given Models and Viewmodels. In this case, you are not even restricted to using Windows Phone Silverlight (as you would be if using pure Xamarin.Forms), but the Phone project can also be a WinRT App that also runs on Windows 8 devices. (Of course, in this case the effort is a little higher than with Xamarin.Forms-only project, since the Views and Service implementations must be created individually for the Silverlight / WinRT part.)

  • The use of an additional PCL project that contains Models and Viewmodels, as suggested above, also ensures that the App can be ported to other platforms (e.g., WPF) at a later point in time. Alternatively, this PCL can also be created in Visual Studio as part of a WPF solution, and referenced from Xamarin Studio at a later point in time to create a Xamarin.Forms App that provides the same functionality as the WPF application.

  • The MVVMbasics NuGet package contains PowerShell scripts that need to run during package installation in order to add all necessary assembly references. When adding NuGet references through the visual NuGet Package Manager using Xamarin Studio on Mac OS, these PowerShell scripts are not executed. Instead, I recommend to install the NuGet PowerShell Console and use this add-in for adding the MVVMbasics reference.

    To do so, choose the Package Console Extension item from the View -> Pads menu after the NuGet PowerShell Console add-in has been installed, and type Install-Package MvvmBasics to add the MVVMbasics framework to the current project!

Implementing Views:

When creating pages, make sure to add a new item of type Forms Xaml Page as this will allow you to specify the page’s content in XAML code. All pages that shall be automatically assigned their Viewmodel by the MVVMbasics NavigatorService must be derived from the MVVMbasics.Views.BaseView base class. All pages generated by Visual Studio or Xamarin Studio usually are derived from the Xamarin ContentPage class, so you must adapt each page’s base class in both C# and XAML code.When referencing the MVVMbasics.Views namespace in XAML, note that it is defined within the MVVMbasicsXF assembly:

xmlns:views="clr-namespace:MVVMbasics.Views;assembly=MVVMbasicsXF"

The MVVMbasics.Views.BaseView class itself inherits from Xamarin.Forms.ContentPage, so you may design the page’s content as if it was a default ContentPage. The creation of other Xamarin page types (e.g., TabbedPage, CarouselPage, …) is not supported by MVVMbasics at the moment, however the MVVMbasics framework provides an alternative for using NavigationPages as shown in the following section Implementing the global App class.

In addition, the MvvmNavigationTarget attribute should be added to each View class, as this enables the automatic assignment of Viewmodels to View. In summary, a sample MVVMbasics page could be implemented as follows:

<?xml version="1.0" encoding="utf-8" ?>
<views:BaseView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:views="clr-namespace:MVVMbasics.Views;assembly=MVVMbasicsXF"
             x:Class="MyApp.Views.MyPage">
	<Label Text="{Binding DisplayText}"/>
</views:BaseView>
using Core.Viewmodels;
using MVVMbasics.Attributes;
using MVVMbasics.Views;

namespace MyApp.Views
{
	[MvvmNavigationTarget(typeof(MyViewmodel))]
	public partial class MyPage : BaseView
	{
		public MyPage()
		{
			InitializeComponent();
		}
	}
}

Implementing the global App class:

Each Xamarin.Forms application contains one global App.cs class file, which is instantiated and started during App startup by the various platform-specific projects. When using MVVMbasics, this App class must be derived from the MVVMbasics.BaseApplication base class. This one itself inherits from Xamarin.Forms.Application, which means that inside your App class you can do whatever you are used to from any other Xamarin.Forms applications, e.g. override the OnSleep() and OnResume() methods.

Within the App class’ constructor, you may register all desired MVVM services to the global ServiceLocator, as is the case in all MVVMbasics applications on other platforms. The only major difference to a typical Xamarin.Forms App class is that instead of assigning the App’s startup page to the MainPage property, you call the SetStartupPage method. This method expects the App’s startup page either as type parameter (in which case it is automatically instantiated) or as parameter (if it has been instantiated already):

SetStartupPage<MyPage>();
SetStartupPage(new MyPage());

Internally, the SetStartupPage method instantiates the provided page if necessary and assigns it to the App’s MainPage property. In addition, it checks whether the MVVMbasics NavigatorService has been registered and if it contains more than one View / Viewmodel pair – in this case it can be assumed that the App shall support page navigation, and the startup page is automatically wrapped within a Xamarin.Forms.NavigationPage. This means that there is no need to manually create an instance of NavigationPage!

In summary, the full implementation of an MVVMbasics App class for Xamarin.Forms could look as follows:

public class App : BaseApplication
{
	public App()
	{
		// Services used by the application
		var navigationService = new NavigatorService();
		navigationService.RegisterAll("MyApp.Views.*");
		ServiceLocator.Register(navigationService);
		ServiceLocator.Register<MessageboxService>();

		// The root page of the application
		SetStartupPage<MyPage>();
	}
}

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

Mar 17

[MVVMbasics] Targeting the Android and iOS platforms via Xamarin.Forms #1

Notice

All blog posts with a title that starts with [MVVMbasics] are related to the MVVMbasics framework. If you are only interested in my regular blog posts and not in MVVMbasics, ignore these. To list all articles covering MVVMbasics, go to http://mvvmbasics.mobilemotion.eu/documentation!

New platforms supported by version 2.2 and higher:

Version 2.2 of the MVVMbasics framework adds functionality for creating mobile applications using the Xamarin.Forms platform. Xamarin.Forms enables the creation of native cross-platform applications for the Android, iOS and Windows Phone Silverlight platforms using C#.

With the help of MVVMbasics 2.2 or higher, implementing these Apps following the MVVM patterns is getting a lot easier. In addition, it allows to add Android and iOS support to existing Apps that are based on MVVMbasics with minimal effort: All that needs to be done is implementing platform-dependent services as well as visual pages for the Xamarin.Forms platform.

Project structure:

Xamarin.Forms solutions typically consist of three or four C# projects:

  • A platform-specific project for each target platform – iOS, Android, Windows Phone (only in Visual Studio as Windows Phone development is not supported in Xamarin Studio):
    These projects may contain artwork and platform-specific controls, but typically only one page / activity that instantiates and starts one common App class.
  • A common project that includes all files that are shared between the target platforms:
    This project contains the above-mentioned global App class, as well as any Data Models, Viewmodels, Views, Services, Converters, etc.
    This project can either be a Portable Class Library, or a Shared project. In both cases, it must be referenced by the platform-specific starter projects.

In addition to this project structure, I’d suggest to add another C# project to the solution, which would be a Portable Class Library that targets all Xamarin.Forms platforms and Windows Phone Silverlight, as well as any additional platforms you might want your App to support. In this case, this project would hold all Data Models, Viewmodel, and Service interfaces, while the Xamarin.Forms common project (the PCL or shared project mentioned in the list above) would only contain Views, Converters, and Service implementations.

This architecture allows to add platform-specific projects that target, for example, WPF or Windows Store Apps, at a later point in time. You could then re-use all the Data Models and Viewmodels on all additional platforms and need to re-implement only Views and platform-specific services.

Project setup in Visual Studio:

Project setup in Visual Studio and Xamarin Studio follows similar rules, however there are a few steps that need special attention in Xamarin Studio, therefore I’ll cover these in a separate section in the second part of this article.

In general, the simplest way of setting up an MVVMbasics application is using the MVVMbasics Project Templates which can be downloaded from Visual Studio Gallery: If you have the project templates installed as Visual Studio extension, just create a new solution of type Multi-Platform Application Core using MVVMbasics (which can be found within the Visual C# -> Multi-Platform category). The solution will contain one project which is a Portable Class Library, which will contain all your Models, Viewmodels, and Service interfaces. Then, add a new project of type Xamarin.Forms App for MVVMbasics Core project to the solution: Several projects will be created automatically, one for each target platform and one PCL that will contain all your Views and Service implementations!

If you’d like to create the project structure manually (or need to add MVVMbasics support to an existing project), simply follow these steps:

  1. If the project doesn’t exist already, create a new project in Visual Studio and choose one of the Blank App project types found in the Visual C# -> Mobile Apps category (depending on whether you like a Portable Class Library or a Shared Project as common Xamarin project), and name it like your desired application’s name:

    MVVM pattern: Hierarchy of layers 
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     

    In addition, add an additional project of type Class Library (Xamarin.Forms Portable) to the solution. I usually call this project “Core” since it will contain the core functionality for all target platforms, but you can name it whatever you want – just don’t be confused as I will refer to this project as the Core project within this article.

  2. Add a reference to the MVVMbasics framework to all those projects (even the platform-specific Android / iOS / WinPhone projects). To do so, use either the visual Nuget Package Manager or the Package Manager Console to download and install the MVVMbasics library, and make sure that version 2.2.x (or newer) has been installed. You’ll notice that two new references MVVMbasics and MVVMbasicsXF have been added to most of the projects.
  3. Add the respective Models, Viewmodels, Services, etc. namespaces to the Core project. For details about how to create the Models, Viewmodels, and Service interfaces, please refer to the MVVMbasics Documentation & Tutorials page.
    The Xamarin.Forms common project should already contain one class file App.cs. To create pages, add a new Views namespace and create at least one file of type Forms Xaml Page. For details about how to implement the App class and the pages, please see the section Implementing Views and the App class in the second part of this article!

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

Mar 16

MVVMbasics 2.2 with Xamarin.Forms support is now available

The newly released version 2.2 of the MVVMbasics frameworks adds support for the Android and iOS platforms via Xamarin.Forms. In addition, it is now possible to specify attribute-based bindable properties within Models and View Models.                                                    

Permanent link to this article: http://mvvmbasics.mobilemotion.eu

Feb 24

A smart ICommand implementation #4

In the previous blog post, we discussed an approach that allows to specify an MVVM Command’s CanExecute condition as well as the properties this condition depends on in one line, without the need of adding information about participating commands to the properties’ setter methods.

This solution improves maintainability by positioning code snippets that syntactically belong together nearby each other, but it still contains redundant code parts that are defined more than once: All of the properties that are already referenced within the CanExecute condition need to be repeated in separate fields – this can definitely be shortened!

Automatic retrieval of dependent properties:

If we can automatically retrieve a property’s name (as string value) out of an expression that defines the property (as mentioned in the previous blog post and described in detail in Thomas Mutzl’s article A smart MVVM command), why shouldn’t we be able to retrieve all referenced properties’ names directly from the Command’s CanExecute condition? This is in fact possible – let’s take a look at how to implement such an optimization:

What have we done so far? The last version of the DelegateCommand constructor presented in the previous blog post has the following signature:

public DelegateCommand(Action<object> action, Func<object, bool> condition,
		INotifyPropertyChanged viewmodel, params Expression<Func<object>>[] dependsOnProperties)

Our aim is to get rid of the dependsOnProperties parameter, so let’s omit it. Instead, we pass the condition as lambda expression:

public DelegateCommand(Action<object> action, Expression<Func<object, bool>> condition,
		INotifyPropertyChanged viewmodel)

Apart from the missing list of dependent properties, this method can be called the same way as the previous one, since syntactically there is no difference between passing a Func and an Expression, except for one case: If you didn’t specify the condition inline (as lambda expression) but in a separate method, you’ll need to convert this method call to a lambda expression, for example:

public MyViewmodel()
{
	SearchCommand = new DelegateCommand(SearchMethod, () => IsSearchAllowed());
}

private bool IsSearchAllowed()
{
	// Evaluate condition
}

However, in real life most conditions won’t be too complex and will usually depend on only one or two properties, so it should be possible to define the condition’s body as lambda expression directly within the Command’s initialization – let’s focus on this case for the moment:

public MyViewmodel()
{
	SearchCommand = new DelegateCommand(SearchMethod,
			() => IsLoggedIn && !String.IsNullOrEmpty(Keywords));
}

Of course, also the constructor’s body needs to be adapted to reflect this changed signature. We need to

  1. convert the condition that has been passed as lambda expression back to a standard Func type to be able to store it in the private _canExecute field (which the Command’s CanExecute() method depends on), and
  2. fill the list of dependent properties which, in the old version, had been passed explicitly.

The first task is easily solved by compiling the lambda expression and storing it as the global _canExecute condition:

_canExecute = canExecute.Compile();

The second task is much more complex – after all, this is what we’ve been after since the beginning: Getting rid of an explicitly passed list of dependent properties and magically retrieving them from the condition’s body! Let’s extract that logic to a separate helper method ParseExpresionTree():

private void ParseExpresionTree(Expression inputExpression, List<string> properties)

The lambda expression that represents the Command’s condition is structured as tree: It contains several other expressions that are combined with each other through operations. There exist different types of expressions – the one we’re after is MemberExpression as this one represents a call to a member, e.g. to a property (after all, this is what we’re looking for: each call to a property must be found, as we need to register to all those properties’ PropertyChanged events!).

So, if we’re dealing with a MemberExpression, check if the member that shall be called is a property, and in that case retrieve its name and store it in the global list of dependent properties:

private void ParseExpresionTree(Expression inputExpression, List<string> properties)
{
	if (inputExpression is MemberExpression)
	{
		var e = inputExpression as MemberExpression;
		var member = e.Member;
		if (member is PropertyInfo)
		{
			PropertyInfo property = member as PropertyInfo;
			Type owner = property.DeclaringType;
			if (owner.GetTypeInfo().ImplementedInterfaces.Contains(typeof(INotifyPropertyChanged)))
			{
				string propertyName = property.Name;
				if (!properties.Contains(propertyName))
					properties.Add(propertyName);
			}
		}
	}
	else
	{
		// process all other types of expressions...
	}
}

The problem is: To find those MemberExpressions, we need to parse the whole tree, and this tree will contain various other expressions that all need to be processed in a different way. For example, if the tree contains a ConditionalExpression at some position (which is an expression that represents an if block), we need to divide this part of the tree into three sub-parts:

  • the expression that shall be tested,
  • the expression that shall be invoked if the test returns true, and
  • the expression that shall be invoked if the test returns false.

Each of these three sub-parts again is represented as expression of some type, and each of those three expressions needs to be processed separately to check if one of them contains a MemberExpression – we do this by calling the ParseExpresionTree() method recursively, passing each of the three sub-expressions:

private void ParseExpresionTree(Expression inputExpression, List<string> properties)
{
	if (inputExpression is MemberExpression)
	{
		// retrieve property name as shown above
	}
	else if (inputExpression is ConditionalExpression)
	{
		var e = inputExpression as ConditionalExpression;
		ParseExpresionTree(e.Test, properties);
		ParseExpresionTree(e.IfTrue, properties);
		ParseExpresionTree(e.IfFalse, properties);
	}
	else
	{
		// process all other types of expressions...
	}
}

A list of all types of expressions defined by the .NET framework can be found at MSDN. I won’t describe how to process each of these types in detail, if you’re interested in the full code please check out my ICommand implementation (available at codeplex) that has been published as part of the MVVMbasics framework!

Any way, after traversing the full expression tree we should end up with a list containing the names of all properties that are called from within the Command’s CanExecute condition! This list can then be used within the Viewmodel’s PropertyChanged event handler to force the condition to be re-evaluated.

A few thoughts about this solution:

  • Of course, working with lambda expressions has an impact on performance. Since analyzing the expression tree is done only once during Command initialization (and not each time the Command is invoked, or the condition is re-evaluated), and since most real-life Command conditions are rather simple and depend on only one or two properties, this should not affect a project’s overall performance.

    Nevertheless, you should always take into account that more complex conditions may be necessary in certain use-cases, so it might be a good idea to provide an overload to the Command’s constructor that still accepts a list of dependent properties. This allows other developers who make use of the Command implementation to circumvent the ParseExpresionTree() method in certain cases.

  • I decided to stop walking down the expression tree whenever a separate method is called. This decision is mainly based on performance considerations: It can be assumed that CanExecute conditions that are passed as inline lambda expressions won’t be too complex and therefore can be analyzed rather quickly by traversing their expression tree, while the complexity of an external method’s body (and therefore the effort necessary for analyzing the method’s contents) cannot be estimated.

    However, it might be a good idea to at least process the expressions contained in a MethodCallExpression‘s Arguments collection, since they might contain a MemberExpression that references a property which otherwise would have been omitted. For example, the Keywords property in our sample Command declaration is only referenced once as parameter to the String.IsNullOrEmpty() method – this property would have been lost!

    Again, also because of this limitation it might be a good idea to offer an overload constructor that allows to manually specify the list of dependent properties – otherwise, it would be impossible to retrieve the dependent properties if only an external method was passed as condition.

  • Finally, this approach is rather tolerant: It might find values that are actually not referenced as properties from within the given expression. This is not a problem, since those values (although being stored in the list of dependent properties) won’t appear as PropertyChanged event args and therefore won’t ever be used for comparison.

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

Older posts «