Building a colour palette for your app

Posted Thursday, April 10, 2014 by

When creating your app on both the phone and tablet almost all guidelines will tell you create a consistent colour palette. There's a lot of tools out there to help you design your palette, Kuler from Adobe is a good example. But what's the best way to use our palette in your app?

There's a couple of goals here, the first is we only want to have to define our colours once for the entire app. This way if we need to tweak them or do a wholesale replacement we're not spending hours hunting for every instance of that colour.

The second is to provide an easy way to override existing theme resources.

What I tend to do is create a separate resource dictionary for the palette, this is because it's usually imported into other dictionaries and I want to keep the repetition low. The other resource dictionary I'll create at this point is a theme overrides one, this contains all the redefinition of the built in resources using the new palette of colours.

In our palette dictionary we'll want to define the colours and brushes separately, this is because despite most of the time we'll be using the brush there will be times the colour is required. Naturally the brush definition refers to the colour so we're sticking with our goals. Typically a colour / brush definition will look like:

<Color x:Key="MajorAccentColor">#FF2980B9</Color>

<SolidColorBrush x:Key="MajorAccentBrush" Color="{StaticResource MajorAccentColor}"/>

Sometimes your designs may make use of the same colour but with different alpha (or opacity) values. For me if this brush is going to be used through the app I'll define it within the palette like so:

<Color x:Key="MinorAccentColor">#FF80B929</Color>

<SolidColorBrush x:Key="MinorAccentBrush" Color="{StaticResource MinorAccentColor}"/>

<SolidColorBrush x:Key="MinorAccentOverlayBrush" Color="{StaticResource MinorAccentColor}" Opacity="0.5"/>

However if it's a one off I'll probably define the brush as inline XAML referring back to our colour resource.

<controls:Sidebar x:Name="Sidebar" IsExpandedChanged="OnIsExpandedChanged">

    <controls:Sidebar.Background>

        <SolidColorBrush Color="{StaticResource SidebarBackgroundColor}" Opacity="0.5"/>

    </controls:Sidebar.Background>

I try to name the colour / brush pairs in generic names more along the lines of their usage than what they look like colour wise. This is because they'll often be tweaked and it can look rather silly to have a resource named "RedColour" that's actually blue.

Now our palette is defined let's make use of it, the first thing I go through and do is redefine quite a few of the out of the box theme resources to make the controls more in line with the rest of my app. It's these little bits that really polish an app, I die a little on the inside when I see the default purple in combo boxes and progress rings. I swear Microsoft chose that colour so people would be forced to deal with it but a lot don't.

In my theme overrides resource dictionary I import the palette and start to define styles for the controls in terms of colours from the palette. We don't need to redefine every single resource, typically only the ones that add the accent colour. For instance with the ComboBox control the overrides are:

<ResourceDictionary.MergedDictionaries>

    <ResourceDictionary Source="/Resources/Palette.xaml"/>

</ResourceDictionary.MergedDictionaries>

 

<SolidColorBrush x:Key="ComboBoxItemSelectedBackgroundThemeBrush" Color="{StaticResource MinorAccentColor}" />

<SolidColorBrush x:Key="ComboBoxItemSelectedPointerOverBackgroundThemeBrush" Color="{StaticResource LightMinorAccentColor}" />

<SolidColorBrush x:Key="ComboBoxSelectedBackgroundThemeBrush" Color="{StaticResource MinorAccentColor}" />

<SolidColorBrush x:Key="ComboBoxSelectedPointerOverBackgroundThemeBrush" Color="{StaticResource LightMinorAccentColor}" />

That's pretty much it, a nice easy way to define your colour scheme realistically in any XAML app and reuse it well.

Using value converters by convention

Posted Thursday, March 27, 2014 by

The application of a convention in Caliburn.Micro is a bit of a pipeline with multiple steps, almost all of them we can modify, let's look at bringing value converters into the equation.

Most of the time the default conventions tend to bring like-minded types together. That's natural in that conventions should be reasonably intuitive, like a string property on the view model being bound to the Text property of the TextBox.

Sometimes these types don't always line up, which is where value converters typically come in. The most common of these being converting between boolean and visibility properties.

Caliburn.Micro does a little bit of work here already, if a convention calls for properties of the two above types (boolean and visibility) then it automatically adds a BooleanToVisibilityConverter to the Binding.

We can extend this through the modification of the ConventionManager.ApplyValueConverters method, but why would we do this? In an app I'm currently working on I want to use relative dates through the app, I'm using a value converter that leverages the Humanizer library (check it out if you haven't already) to do the conversion. This means everywhere I want to out put the date I need to dispense with the normal convention using x:Name and set up the binding with the value converter. A bit of a pain and there's always a chance I could miss one.

What we need to do is modify Caliburn such that when it applies a convention between a DateTime (or DateTimeOffset) property and a TextBlock's Text when add the converter to the process.

The code is pretty simple, the only weird part is taking a reference to the default implementation first so that we can keep the default behavior as well.

var baseApplyValueConverter = ConventionManager.ApplyValueConverter;

 

ConventionManager.ApplyValueConverter = (binding, bindableProperty, property) =>

{

    baseApplyValueConverter(binding, bindableProperty, property);

 

    if (bindableProperty == TextBlock.TextProperty && typeof(DateTime).IsAssignableFrom(property.PropertyType))

        binding.Converter = new RelativeDateTimeConverter();

 

    if (bindableProperty == TextBlock.TextProperty && typeof(DateTimeOffset).IsAssignableFrom(property.PropertyType))

        binding.Converter = new RelativeDateTimeConverter();

};

Now whenever a convention on a TextBlock is wired to a DateTime it will display a relative date time. We can remove all our bindings and converters from code and go back to simple x:Name conventions.

Some thoughts about custom Uri Protocols

Posted Thursday, March 20, 2014 by

I've seen a lot of content around lately discussing the use of custom uri protocols in your Windows Tablet and Phone apps. They're a great way to have other apps launch your app in a deep link kind of way, however I don't think developers are really using them to their full potential.

Matt Lacey has a great post listing some of the 300 or so apps that implement custom uri protocols and their protocol name. Looking through the list a couple of things jump out at me.

The first is that there's no documentation about the protocol itself, even with the protocol name from the list I have no real idea about how to use it. Some developers like Lazyworm Apps have documented their metrotube protocol but the amount that have are few and far between. There needs to be a central resource for this list including documentation.

My second observation is that almost all the protocols are completely unique to that app, usually derived from the app name. This means that any other app is limited to launch that and only that app. The end user also doesn't have a choice of which app they want to use to handle that protocol.

This problem is caused by a lack of global protocols besides the usual suspects of http, mailto etc. There are no established protocols for things like "watch a youtube video" leaving all the protocols as their own little islands.

What I'd love to see is the whole app protocol thing expanded so we can have a rich ecosystem of apps plugging into to fill different parts of a workflow, probably not going to happen but a guy can dream right?

Scaling with a PathIcon

Posted Thursday, March 13, 2014 by

The new AppBarButton control in Windows 8.1 is incredibly useful, the ability to use symbols, gylphs, images or paths as an icon within the button makes it a lot easier to customise that in 8.0. There's just one slight problem.

Path Icon doesn't scale the Path geometry to fit within the button, it renders just as the Path geometry is specified which is kind of awkward.

We could try and re-template PathIcon but that's probably overkill. The easiest thing to do is to rescale the Path, tools like Inkscape would be one way to do it. Thankfully Christian Mosers has created a really simple tool to transform Path geometry down to the appropriate scale. It's called Geometry Transformer and is available on his website.

Custom Special Values in Caliburn.Micro

Posted Sunday, March 2, 2014 by

Caliburn.Micro has features to allow you bind methods to actions with parameters. Check out the Action Parameters section of the documentation. Part of this set of features includes "special values" such as $eventArgs or $dataContext, these allow an easy to access information contextual to the action.

I use these special values in a number of different ways. When binding a list of values the item template may contain a button with the following:

<Button Style="{StaticResource ContentButton}" cm:Message.Attach="ViewSection($dataContext)">

This action bubbles up to the root model passing the item in the list the button was pressed for.

public void ViewSection(RepositorySection group)

Another is making use of the ItemClick functionality on GridView and ListView in Windows 8. This provides similar functionality without requiring buttons in your item templates. The difference is that clicked item is in the event args so I'd use syntax something similar to:

<ListView cm:Message.Attach="[Event ItemClick] = [SelectItem($eventArgs)]" IsItemClickEnabled="True">

public void SelectItem(ItemClickEventArgs e)

Another example is around pinning tiles in Windows 8, for better user experience we want to pass an invocation point to SecondaryTile.RequestCreateAsync to ensure the popup is near the element that invoked it. You can get access to element using $source or the $executionContext.

public async void ToggleTile(ActionExecutionContext context)

{

    var transform = context.Source.TransformToVisual(null);

 

    var invocationPoint = transform.TransformPoint(new Point(0, 0));

While all these solutions solve the problem at hand they do make the code messier than I'd ideally like. The ItemClick example forces you view model to depend on a xaml event args object with an internal constructor. While the invocation point sample forces the view model to start dealing with UI elements and their layout on the screen.

So how do we solve these problems? We can actually create custom special values, this removes the weird dependencies on the view model and increases code reuse as the special values are only dealt with once. For the above examples we'd have the following code in our bootstrapper (or application) depending platform.

MessageBinder.SpecialValues.Add("$invocationpoint", c => c.Source.TransformToVisual(null).TransformPoint(new Point()));

MessageBinder.SpecialValues.Add("$clickeditem", c => ((ItemClickEventArgs)c.EventArgs).ClickedItem);

Important points to note is that the key's must start with $ and be lowercase (they don't need to be in the xaml though). We can now change our xaml for our examples to the following.

<ListView cm:Message.Attach="[Event ItemClick] = [SelectIssue($clickedItem)]"

<AppBarButton cm:Message.Attach="TogglePin($invocationPoint)"

There's a myriad of ways this trick could possibly be put to use. I'm going back through old projects and looking where I'm depending on special values and seeing if they can be simplified.

Page 1 of 912345>

Professional Windows App Development