DeutschEnglish

Okt 23

The project needs to be deployed before it can be started…

Have you ever experienced the following error message popping up in Visual Studio, instead of starting the App to debug?

Deployment error message 
 
 
 
 
 
 
 
 
 
 
 
 

This situation mostly occurs when starting the UWP part of a Xamarin.Forms project, but is not limited to this scenario. In general, it seems that the problem arises when adding a UWP app project to an already existing solution, setting it as startup project, and running the debugger (which apparently is exactly what Visual Studio does when creating a Xamarin.Forms project from scratch: An empty solution is created, to which a Portable Class Library or Shared Project is added, and finally all the platform-specific projects are created and inserted into the (at that time) already existing solution). The situation can also be reproduced by opening a new Visual Studio window, creating a Portable Class Library project, and adding a UWP app project to the solution.

How to overcome the error message and get the App to start up? The message is quite descriptive: Open Visual Studio’s Configuration Manager by right-clicking the current solution in Solution Manager, and choose Configuration Manager. Here, all projects are listed that are part of the current solution, followed by their default configuration (usually Debug / Release) and target platform. In addition, it is possible to define whether each project should be built and deployed when building the whole solution.

Configuration Manager 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

It seems that these two check boxes are only automatically checked when creating an UWP project as the only project within a solution. We can obviously check these manually to make the UWP app build and start up. But what’s behind the Configuration Manager window and the settings changed in there?

The Configuration Manager settings obviously apply to the whole solution, so let’s take a look at how the solution is built and stored! In your solution’s root directory, there should be a .sln file. Load this into any text editor – don’t worry, it’s not a binary files but perfectly readable for humans (well, probably not all of them, but it should not be a problem at least for developers)!

The first section of the solution file lists all projects referenced by the solution, e.g.:

Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App1.UWP", "App1\App1.UWP\App1.UWP.csproj", "{9CCEFEF9-259B-46E4-AE57-7865C17EF6E9}"
EndProject

The project name and path attributes should be self-evident. The GUID shown at the beginning of the line depicts the type of project – see List of Visual Studio Project Type GUIDs for an overview. The most interesting part for us is the second GUID per line – this is used to represent each project in the setion of the solution file. Let’s scroll down to the GlobalSection(ProjectConfigurationPlatforms) = postSolution section, and look out for the GUID that represents our UWP project. This section lists all configuration that are activated, for each project. Look out for the lines matching your current configuration (if you just created the solution, these will probably be Debug and Any CPUM: There should be at least one line containing ActiveCfg. We can add two additional lines below, replacing ActiveCfg by Build.0 and Deploy.0 respectively:

{9CCEFEF9-259B-46E4-AE57-7865C17EF6E9}.Ad-Hoc|Any CPU.ActiveCfg = Release|x86
{9CCEFEF9-259B-46E4-AE57-7865C17EF6E9}.Ad-Hoc|Any CPU.Build.0 = Release|x86
{9CCEFEF9-259B-46E4-AE57-7865C17EF6E9}.Ad-Hoc|Any CPU.Deploy.0 = Release|x86

These two lines tell Visual Studio to carry out the build and deploy processes (to be exact, the first such process, as the .0 represents an indexer, but in most cases there will be only one build and deploy action defined anyway).

Save the file, switch back to Visual Studio, choose Reload all when asked what to do with the external changed. In Configuration Manager, the UWP project should now be marked to build and deploy!

Permanentlink zu diesem Beitrag: http://www.mobilemotion.eu/?p=1866&lang=de

Sep 19

Store apps and window sizing

The problem:

Similar to WPF Windows, for a Store app’s Page we can set Width, Height, MinWidth, and MinHeight attributes. However, in contrast to WPF, the Page.Width and Page.Height attributes only affect the size of the container that contains all of the page’s visual elements – the window the app is displayed in is not changed. Moreover, the Min... attributes do not affect the visual presentation in any way.

First of all, the reason for this behavior is that the Page object is not the root visual element, as it resides within a Frame which in turn is the content of the root Window. We can reconstruct this structure by looking at any Store App’s typical OnLaunched event handler: In most Apps, it will look similar to the following code snippet:

protected override void OnLaunched(LaunchActivatedEventArgs e)
{
	Frame rootFrame = Window.Current.Content as Frame;
	if (rootFrame.Content == null)
	{
		rootFrame.Navigate(typeof(MainPage));
	}
	Window.Current.Activate();
}

In this example, a new instance of MainPage is created and assigned as the content of the root window’s content frame, and then the window is shown on the screen. By adapting the page’s size attributes, obvisouly neither the containing frame nor the window are affected.

On the other hand, it is possible to directly access the root window’s Bounds property which represents its screen size and position, e.g.:

var width = Window.Current.Bounds.Width;

Unfortunately, this does not allow us to change the widow size neither, since Window.Bounds does not provide a (public) setter. The question is: How to define the minimum size of a Store App’s container window?

The solution(s):

For Windows 8/8.1 Apps, the answer is short since possibilities are quite limited: The app manifest requires the definition of the ApplicationView.MinWidth attribute:

MinWidth option 
 
 
 
 
 
 
 
 
 
 

This limits us in three ways:

  • It allows to set the minimum width, but not height,
  • we can only choose between the two options 320px and 500px, and
  • this minimum width only applies when using the app in full-screen mode, if displayed in a window it does not affect the window size at all.

Compared to this, the UWP platform is more flexible: Although the MinWidth attribute has completely disappeared from the manifest, there are a few options available through the ApplicationView class, all to be set in C# code:

  • To set an App’s desired startup width, use the PreferredLaunchViewSize and PreferredLaunchWindowingMode properties:

    ApplicationView.PreferredLaunchViewSize = new Size(800, 600);
    ApplicationView.PreferredLaunchWindowingMode = ApplicationViewWindowingMode.PreferredLaunchViewSize;
    
  • To define an App’s minimum (window) size, use the SetPreferredMinSize method:

    ApplicationView.GetForCurrentView().SetPreferredMinSize(new Size(500, 350));
    
  • Also resizing an App window during runtime from within C# code is possible:

    ApplicationView.GetForCurrentView().TryResizeView(new Size(1000, 600));
    

The platform gap:

The major shortcoming of the options listed above is that it’s not possible to affect a Windows 8 App’s size when running in window mode. The reason for this is historical: When the WinRT platform was released (good old Windows 8 times…), apps could only be started in full-screen mode. Running apps within windows is only possible in Windows 10, and together with the Windows 10 OS the UWP development platform was released, allowing to manipulate an app’s container window (as shown above). Unfortunately, this does not help Windows 8 Apps that are still around (or that are still actively developed, e.g. to ensure downwards compatibility) – the only option is to upgrade to UWP and hope that all Windows 8 users will as well update soon!

Permanentlink zu diesem Beitrag: http://www.mobilemotion.eu/?p=1859&lang=de

Sep 03

Numeric text box data binding

I was recently working on a bug report which stated that users were not possible to enter decimal numbers in a text box by hand, while it was still possible to past decimals from the clipboard. Obviously, we first checked the text box implementation and the data type used for binding – it was a simple WPF TextBox with direct data binding to a double property in ViewModel.

If you want to reconstruct the problem, create a simple .NET 4.5 / 4.6 WPF project with a window with corresponding ViewModel. The ViewModel contains one bindable property of type double (let’s call it Number), while the window only consists of a TextBox with the following binding expression:

<TextBox Text="{Binding Number, UpdateSourceTrigger=PropertyChanged}" />

Technically, this should not be a problem, since WPF is capable of automatically transforming a double into a string, and vice versa. It’s worth noting that the latter – obviously – needs parsing, which is all done under the hood, but I’ll come to that in a moment.

Start the app, and you’ll notice that the text box is pre-filled with the number 0, which is the default value of the Number property. Start typing some decimal number, e.g. by placing the cursor next to 0 and typing a decimal point (. or , etc., depending on the input culture) and some other digit – the result is that the decimal sign disappears, and the 0 digit is replaced by whichever number you entered.

What happened? We can inspect this behavior in detail if we create a simple converter that does nothing, and hook it into the binding. To watch the data, set breakpoints in the Convert and ConvertBack methods:

public class DoubleConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value;
    }
}

Start the app and enter the decimal point in addition to the existing 0 digit! The ConvertBack method will be called first, since we entered something and this value must be passed back to the ViewModel property, and “0.” is passed as value – everything fine so far! Immediately afterwards, the Convert method is invoked, and a value of “0” is passed to it! What happened? To actually pass the value of “0.” to our Number property, it obviously must be parsed to match the double data type – as mentioned before, this is done automatically. However, after this step, the Number property contains a value that differs from the text box’ content (“0” vs. “0.”), so WPF thinks it should update the text box so that it shows the actual property value!

Now, if we enter another digit, say 5 (to complete the intended input of the decimal number 0.5), the same process starts again: Since the decimal point has disappeared, the text box contains the text “05”, which is automatically parsed to the number 5, which is then passed back into the text box.

Another interesting observation: Target the project to .NET 3.5, and restart the app. You’ll notice that entering decimal numbers suddenly works without any problems! Why is this?

Let’s take a look at the FrameworkCompatibilityPreferences.KeepTextBoxDisplaySynchronizedWithTextProperty property: This property can be set app-wide, and its purpose is to specify whether the process described above (the permanent synchronisation of a text box’ content to the binding property) should be turned on or off. The MSDN page states that If your app targets WPF 4.0 or earlier, the default is false. If your app targets WPF 4.5, the default is true.

I have no idea why Microsoft decided to change this default behavior, but the solution for our problem is obvious: Set KeepTextBoxDisplaySynchronizedWithTextProperty to false in the App’s constructor, and you’ll be able to use decimal numbers as usual:

System.Windows.FrameworkCompatibilityPreferences.KeepTextBoxDisplaySynchronizedWithTextProperty = false;

Permanentlink zu diesem Beitrag: http://www.mobilemotion.eu/?p=1855&lang=de

Aug 24

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

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

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

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

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

    …we can bind to it from in XAML:

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

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

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

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

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

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

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

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

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

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

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

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

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

Permanentlink zu diesem Beitrag: http://www.mobilemotion.eu/?p=1845&lang=de

Jun 23

MVVM event to command binding #5: Custom markup extensions

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

Surprise, surprise!

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

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

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

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

The code:

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

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

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

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

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

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

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

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

public class EventBindingExtension : MarkupExtension
{
	private readonly string _commandName;

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

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

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

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

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

Discussion:

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

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

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

Permanentlink zu diesem Beitrag: http://www.mobilemotion.eu/?p=1837&lang=de

Jun 12

MVVM event to command binding #4: Predefined event handlers

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

The code:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Discussion:

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

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

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

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

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

Permanentlink zu diesem Beitrag: http://www.mobilemotion.eu/?p=1828&lang=de

Jun 03

MVVM event to command binding #3: Attached properties

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

The code:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Discussion:

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

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

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

Permanentlink zu diesem Beitrag: http://www.mobilemotion.eu/?p=1822&lang=de

Mai 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!

Permanentlink zu diesem Beitrag: http://www.mobilemotion.eu/?p=1808&lang=de

Mai 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!

Permanentlink zu diesem Beitrag: http://www.mobilemotion.eu/?p=1806&lang=de

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.

Permanentlink zu diesem Beitrag: http://www.mobilemotion.eu/?p=1788&lang=de

Ältere Beiträge «