DeutschEnglish

Jul 24

Automatic color adaptation to background brightness

Imagine in one of your projects (no matter if Phone, Store, or even Desktop = WPF) you’ve got some status to be displayed in a TextBox. There might be an enumeration like this

enum Status {
	Running,
	Warning,
	Error,
	Failure
}

The text could then be bound to some property of this Status type, and in addition you might want to bind the TextBox’s Background to the same property via a StatusToBrushConverter, in order to signal the status in a traffic-light-like color scheme. Now the text has four states that will look similar to the folloing four images:

Without ColorContrastConverter
 
 

Nice, but shouldn’t also the text’s foreground color adapt in order to be readable even on the darker background colors? Of course you could write another converter that defines the best foreground color for each value within the enumeration, but in this case you’d need to change both converters each time the enumeration changes.

Instead, I suggest setting the foreground color to black or white depending on the background’s brightness. How to achieve that in an automatic way? Let me introduce the ColorContrastConverter!

The idea is to analyze the background color (which we know, because it is explicitly set by an existing converter), and return either black or white, depending on whether the background color is lighter or darker than average. Put this logic into a ValueConverter, use the background color and this new coverter as the text’s Foreground property’s binding target, and we’re done! And the best thing: This converter is totally reusable in the next App project.

Okay, let’s take a look at the code (the following snippet shows the code for Windows Store Apps, for Phone or WPF you’d need to adapt the Convert and ConvertBack methods’ signatures accordingly):

public class ColorContrastConverter : IValueConverter
{
	public object Convert(object value, Type targetType, object parameter, string language)
	{
		if (value is SolidColorBrush)
		{
			var color = (value as SolidColorBrush).Color;
			const double threshold = (3*255)/2;
			int sum = color.R + color.G + color.B;
			return new SolidColorBrush(sum > threshold ? Colors.Black : Colors.White);
		}
		return DependencyProperty.UnsetValue;
	}

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

To enable direct binding, the converter expects and returns SolidColorBrush objects, however for internal calculation the brushes Color property is used.

The color value consists of three channels representing the red, green, and blue components. Each of the three channels can contain a numeric value from 0 to 255, so the color’s total value can range from 0 to 3 * 255 = 765. The threshold between defining a color as “light” or “dark” is between these values, at 765 / 2 = 382.5. If the actual color value is below this threshold, the background color is “dark” and we return white as foreground color, since this is the lightest possible color. Otherwise the background color is “light” and therefore we use black as foreground color.

Of course, this is just a simple example and you might adapt this algorithm to your needs, e.g. to take into accont transparent backgrounds by incorporating the color’s alpha value.

To use this converter in any XAML page, we first need to register it as resource:

<Page.Resources>
	<converters:ColorContrastConverter x:Key="ColorContrastConverter" />
</Page.Resources>

Now we’re ready to use it! Simply bind the TextBox’s Foreground to its own Background property via this new converter:

<TextBox Text="{Binding MyStatus}" Background="{Binding MyStatus, Converter={StaticResource StatusToBrushConverter}}" 
	Foreground="{Binding RelativeSource={RelativeSource Self}, Path=Background, Converter={StaticResource ColorContrastConverter}}" />

Now the foreground color is automatically adapting to the background’s brightness:

With ColorContrastConverter
 
 

In practice however, you’ll want the status field not to be editable, for example by using a TextBlock instead of the TextBlox. Unfortunately, the TextBlock control does not provide a Background property… Instead, we could wrap it inside a Border, then the ColorContrastConverter binding needs to reference the Border’s background color:

<Border x:Name="StatusBorder" Background="{Binding MyStatus, Converter={StaticResource StatusToBrushConverter}}">
	<TextBlock Text="{Binding MyStatus}"
		Foreground="{Binding ElementName=StatusBorder, Path=Background, Converter={StaticResource ColorContrastConverter}}" />
</Border>

Of course, an even tidier solution would be referencing the border via a RelativeSource binding instead of naming it. Since this is solved quite differently on the WPF, Store, and Phone platforms, refer to my older blog post Mastering RelativeSource Bindings: TemplatedParent as alternative to FindAncestor!

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

Jul 23

MVVMbasics 1.4 includes converters

The latest version of the MVVMbasics framework 1.4 now comes with a basic set of four value converters to be used in custom views! Both the framework itself and an updated version of the Visual Studio templates are now available for download.

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

Jul 19

Localizing a Store App’s manifest

The short story:

A few months ago, I wrote a series of blog posts concerning internationalization and localization of Windows Phone and Windows Store (and cross-platform) Apps, that explain the use of resource files to include culture-specific string values in both C# code and XAML markup. This article shows, how to localize entries within a Windows Store’s appxmanifest file.

The long story:

In addition to labels, caption, etc. within your code, you might want to add localized content to the App’s manifest also. For example, the App’s Display name and Description but also the Package display name and in some cases also the Publisher display name should appear in each user’s local language. This can be achieved using the ms-resource keyword.

Most of the text fields presented in Visual Studio’s visual manifest editor can be filled with the ms-resource: prefix, followed by a key that is defined in the global resource file. The following image shows an example:

Localized manifest file
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

However, in contrast to resource references from within XAML or C# code, the given key must be defined within a *.resw resource file, *.resx files are not supported.

If the App is pure Windows Store project (without Portable Class Libraries targeting different platforms), it might be useful to completely switch to the *.resw file format and only use one type of resource file. To add such a file to the project, select the Resources file (.resw) option from Visual Studio’s Add New Item wizard. Filling the file with key-value-pairs works the same way as with *.resx files.

One important difference between the two file types is that *.resw resource files must be positioned within a folder that encodes the language and/or culture of the contained resource file. (When using *.resx files, this is done by adding a language-code prefix to the filename itself.) For example, when supporting English, German, and French languages, there should be three folders, each containing one resources file with the same name, as illustrated in the following picture:

Resource files
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

When working on a Store project that is part of a cross-platform solution, resource files already exist on the Portable Class Library layer, in order to be shared by all contained projects. In this case, new *.resw files must be created directly within the Store project as described above, but they need only contain those key-value-pairs that are referenced within the appxmanifest.xml file. All other values that are used from within C# or XAML code can stay in the existing, old resource files.

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

Jul 11

Magically moving pushpins on a Bing map

The short story:

Always remember that images added as overlay pushpins to a Bing maps control have their bound location at the upper left corner!

The long story:

Let’s imagine you have a Windows Store App that includes a Bing maps control, and you’d like to add pushpins that contain a custom image to certain locations on the map. If your pushpin icon looks similar to X, not a problem. If the pin’s tip points in another direction, it will slowly move away from its original position when zooming into the map…

The reason is that the upper right corner of the pushpin image is positioned at the exact GPS location as specified. If it was the image’s center, we could simply enlarge to image to four times its size with a transparen background and move the icon inside the image such that its tip points to the image’s exact center point.

Unfortunately this is not the case, and this results in the effect of a (seemingly) moving pin, because the upper left corner is fixed, but the viewer concentrates on another point of the image (the one the pin’s tip points to) – since the maps changes its size when zooming and the pin image doesn’t, this point moves further and further away from its original position…

What can we do about this problem (if always using pushpins that point in the upper left direction is not a suitable solution)?

Lessons learned:

The obvious solution is to move the pushpin image – I’d like to introduce two ways to achieve this, although there might exists a lot more options.

Option 1 is using a translation. Imagine the following existing code, and a pushpin image that looks similar to Pushpin:

<Page.Resources>
	<Style TargetType="bing:Pushpin" x:Key="PushpinStyle">
		<Setter Property="Template">
			<Setter.Value>
				<ControlTemplate TargetType="bing:Pushpin">
					<Image Source="../Assets/pin_red.png" Width="32" Height="32"/>
				</ControlTemplate>
			</Setter.Value>
		</Setter>
	</Style>
</Page.Resources>

<bing:Map Credentials="YOUR_API_CODE">
	<bing:Map.Children>
		<bing:Pushpin Width="32" Height="32" Style="{StaticResource PushpinStyle}">
			<bing:MapLayer.Position>
				<bing:Location Latitude="{Binding Lat}" Longitude="{Binding Long}" />
			</bing:MapLayer.Position>
		</bing:Pushpin>
	</bing:Map.Children>
</bing:Map>

We simply add a transformation to the pushpin object that translates the image the same amount of pixels that correspond to the image’s height! So, let’s change the code as follows:

		<bing:Pushpin Width="32" Height="32" Style="{StaticResource PushpinStyle}">
			<bing:Pushpin.RenderTransform>
				<TranslateTransform Y="-32" />
			</bing:Pushpin.RenderTransform>
			<bing:MapLayer.Position>
				<bing:Location Latitude="{Binding Lat}" Longitude="{Binding Long}" />
			</bing:MapLayer.Position>
		</bing:Pushpin>

This snippet simply moves the image 32 pixels upwards (since the image is 32 pixels high), resulting in the lower left corner staying at the specified location!

Another option is to move the pushpin image through setting a margin. If we wanted to use a pushpin like this Cross, we’d need to move the image in two directions to bind its center point to the desired GPS location. In pratice, this look like the following:

<bing:Map Credentials="YOUR_API_CODE">
	<bing:Map.Children>
		<bing:Pushpin Width="32" Height="32" Style="{StaticResource PushpinStyle}" Margin="-16,-16,0,0">
			<bing:MapLayer.Position>
				<bing:Location Latitude="{Binding Lat}" Longitude="{Binding Long}" />
			</bing:MapLayer.Position>
		</bing:Pushpin>
	</bing:Map.Children>
</bing:Map>

In this example we’re moving the pushpin image 16 pixels up and 16 pixels to the left – done!

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

Jul 07

The People’s Swedish Dictionary

The People's Swedish Dictionary

This new App provides a tablet-friendly, touch-optimized user interface for the Folkets lexikon web service that is available at http://folkets-lexikon.csc.kth.se/. It provides a simple dictionary for translations of English words to Swedish, and vice versa.

Permanent link to this article: http://www.mobilemotion.eu/?page_id=1124

Jul 05

[MVVMbasics] Using the TimerService

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!

Version 1.3 of the MVVMbasics framework features the new TimerService class that is available for all three platforms (Desktop WPF, Phone, and Windows Store / Tablet). In this article, I’d like to show how to create timer events using this new service.

Principles:

The TimerService offers the possibility to create several timers that may run at the same time, each of which having its own tick interval. In general, there are two options when creating a new timer object:

  • Single timers run once, fire some action when the specified interval time has elapsed, and are deleted afterwards.
  • Looping timers are started once, fire some action when the specified interval time has elapsed, and then are started again.

This means that looping timers must be explicitly stopped by the developer if they shall quit sending tick events, while single timers may only be stopped as long as the interval time has not elapsed (because afterwards they are deleted automatically).

Coding:

To create a new timer or stop an existing one, retrieve the TimerService instance through the ServiceLocator. There exist two similar methods for creating and starting timers: StartOnce creates a single timer, while StartLooping creates a looping timer. It is important to notice that there are no explicit Create and Start methods, instead the two Start... methods create and at the same time start a new timer.

Both Start... methods mentioned above take the desired interval (as TimeSpan object) and a callback action as parameters. As the callback action, pass a method that shall be executed on each tick event. In addition, both Start... methods return a GUID identifier that can be used later to stop specific timers. When defining only one timer in your application, it’s not necessary to store this identifier, otherwise it’s recommended to store it within a local Guid variable.

In addition, the TimerService instance offers a Stop method that can be used to stop looping timers and single timers that have not yet been elapsed. This method can be called in several ways:

  • If there is only one timer defined in the App, to stop this one timer you can simply call the Stop method without parameters.
  • If there are multiple timers defined in the App that allshall be stopped, you can also just call the Stop method without parameters – it will stop all timers that have been created and have not yet elapsed.
  • To stop a specific timer, call the Stop method and pass the desired target timer’s GUID identifier as parameter.
  • To stop several specific timers at the same time, you might also pass several GUID identifiers as parameters to the Stop method.

The detailed specification of the ITimerService interface and all the platform-specific TimerService classes can be found in the MVVMbasics Class Reference, on the pages ITimerService, MVVMbasicsPhoneExtensions.TimerService, MVVMbasicsTabletExtensions.TimerService, and MVVMbasicsDesktopExtensions.TimerService.

Important hints:

When creating timer objects using the TimerService, these timers are bound to the App, not to a single View (page or window). In practive however, timers often will be used to trigger UI changes and are therefore only useful within special Views: When exiting the current View, these timers should be stopped since the UI event they are about to trigger is not necessary any more, except for when the View is only moved to the background and might be reloaded later. The TimerService does not handle these scenarios – for each timer, you need to decide on your own whether this timer affects View-specific UI elements, and in that case manuallly stop them in the Viewmodel’s OnNavigatedFrom event handler method!

What’s behind?

Technically speaking, the TimerService is a wrapper of the platform-specific DispatcherTimer classes, meaning that it is the method of choice when defining timer events that update the UI.

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

Jun 27

Resolving Nuget error “Input string was not in a correct format.”

This is not a purely mobile related topic, but might concern anyone who uses the Visual Studio Nuget package manager. In some cases, adding Nuget packages to a Visual Studio project fails and Nuget presents the following error:

Install failed. Rolling back…
install-package : Input string was not in a correct format.
At line:1 char:1

I recently faced this error on several machines, no matter which package I tried to install to which project. My first guess was some Internet connection issue that prevents Nuget from downloading packages through our company’s proxy server, so I tried changing the Visual Studio settings to use a different proxy. However, it turned out that all packages had been successfully downloaded, but Nuget was not able to add references to these packages to the project.

Finally it turned out that some kind of version conflict existed in the machines’ configration. I was able to resolve the issue by running the following command using administrator credentials:

regsvr32 "C:\Program Files (x86)\Common Files\microsoft shared\MSEnv\VsLangproj.olb"

By the way, this worked in Visual Studio 2010, 2012, and 2013 for me – just in case somebody faces a similar issue!

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

Jun 21

Getting TextBox binding to work in Store Apps

The short story:

Data-Binding a TextBox to a Viewmodel property in a Windows Store App using UpdateSourceTrigger="PropertyChanged" doesn’t update the property.

The long story:

Most of you will have noticed by now that Windows 8.1 finally brought the UpdateSourceTrigger property to the TextBox control which we know (and love) from WPF and Windows Phone. So why not making use of it? While refactoring one of our older projects originally designed for Win 8.0 we decided to go for it and get rid of some ugly code-behind event handlers. The App contains a TextBox and a Search button binding a command that shall only be enabled if the text box contains at least 5 characters. Initially, the TextBox’ TextChanged event would set some property in the Viewmodel, in order to check its content’s length. Now we’d simply bind the TextBox to this Viewmodel property, using the UpdateSourceTrigger="PropertyChanged" option to propagate changes on each key press (not only when losing focus).

The immediate, surprising effect was that the Viewmodel property was always null – even when forcing the TextBox to lose focus! It turned out that we needed to add Mode="TwoWay" to get the binding working, since it was only binding from Viewmodel to View but not the other way round…

Lessons learned:

It seems that WinRT TextBox controls use OneWay as their default binding mode. Just keep in mind that in most cases a text box needs to be set to Mode="TwoWay", since in most cases you’ll like the text box to propagate its content to the Viewmodel!

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

Jun 16

MVVMbasics: Version 1.3 available

The minor update 1.3 adds timer functionality to the MVVMbasics framework. The new version includes a TimerService that provides a platform-independent DispatcherTimer.

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

Jun 13

How to make Bing Maps work with MVVM

Unfortunately, the Bing Maps control for Windows Store Apps is not fully MVVM compatible. For example, it’s not possible to bind the map’s center location to latitude and longitude coordinates defined in the Viewmodel:

<Map Credentials="YOUR_LICENSE_KEY" ZoomLevel="16">
	<Map.Center>
		<Location Latitude="{Binding Lat}" Longitude="{Binding Long}"/>
	</Map.Center>
</Map>

While this does not result in a compile-time or runtime-error, you’ll end up with a blue map showing the Atlantic ocean’s water surface. The reason is that the Bing.Maps.Location element’s Latitude and Longitude properties are not realized as bindable properties, so if they are not set directly within XAML or C# code they are filled with their standard value 0. Now guess where GPS coordinates 0.0/0.0 are? Somewhere between Africa and South America, in the middle of the Atlantic ocean…

Microsoft states this constraint is necessary to ensure maximum performance of the map display. Indeed it’s not the best idea to bind a map’s center location to constantly changing coordinate values, such that the map needs to be redrawn constantly. On the other hand, the restriction that data binding is not possible at all makes it impossible to stick to the MVVM pattern. Of course you could set the center coordinates directly in XAML, but typically a map’s startup location is not known at compile-time. Instead, for setting it at runtime, you’ll need code-behind to access the map’s Location property, and that’s definitely something we’d like to avoid!

Let me show you one potential workaround that enables data binding of the Map control’s center coordinates! The idea is: If the original control does not provide bindable coordinate properties, let’s define our own! For the sake of simplicity, we’ll create a dependency property of type Location instead of two separate Latitude and Longitude properties of type double, since usually you won’t change only one of the two coordinates but both at the same time.

Let’s call our custom dependency property Center! In my case, it will reside in a static class named MapHelper:

namespace Helpers
{
	public static class MapHelper
    {
		public static readonly DependencyProperty CenterProperty = DependencyProperty.RegisterAttached(
			"Center",
			typeof(Location),
			typeof(MapHelper),
			new PropertyMetadata(0.0, new PropertyChangedCallback(CenterChanged))
		);

		public static void SetCenter(DependencyObject obj, Location value)
		{
			obj.SetValue(CenterProperty, value);
		}

		public static Location GetCenter(DependencyObject obj)
		{
			return (Location)obj.GetValue(CenterProperty);
		}

		private static void CenterChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
		{
			Map map = (Map)obj;
			if (map != null)
				map.Center = (Location) args.NewValue;
		}
	}
}

Quite self-explanatory, isn’t it? The only thing that’s necessary in addition to the “default” dependency property implementation including registration, getter and setter is the callback method that is called whenever the property changes. This method retrieves the Map control and sets its Center property.

How would we use this custom property in XAML code? If there is a property of type Bing.Maps.Location defined within the Viewmodel called Center, data binding is really simple:

<Map Credentials="YOUR_LICENSE_KEY" ZoomLevel="16" helpers:MapHelper.Center="{Binding Center}" />

Of course, this solution includes more code than you’d probably need to set the map’s location once in the page’s code-behind file, but you might as well put this into a library and re-use it in all your Bing Map projects. Just keep in mind that the data binding target should not change too often, to avoid the performace problems that were the initial reason for this blog post…

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

Older posts «