Andrej Tozon's blog

In the Attic

NAVIGATION - SEARCH

Pack your Windows App package yourself

A while ago, one of my Windows Store apps was in a weird stall – I’ve updated the app to support Windows 8.1 only, but published version was still targeting 8.0. After uploading new version of the app, I had to remove the 8.0 version due to some validation errors – the mistake!

I was left in a situation where I couldn’t publish my new 8,1 app because the process required having the 8.0 along the new one. Uploading 8.0 version didn’t work either because the process required that any new upload has to have its version number incremented. An option to just end the Windows 8.0 support at this point would be a helpful solution to the problem, but that option is not available until both versions of the app are validated and published.

I had to manually increment the old app’s version (targeting 8.0) and put it up there for validation to be able to continue publishing the new app (targeting 8.1).

Luckily, the application’s version is easily modified in AppxManifest.xml and Appx files are just archive files, right? Yes, but any modification made to package content will invalidate package signature so it’s necessary to recreate it.

Creating the package

Starting from existing package, I have first unpacked it to a new folder and incremented the version in the app manifest. I could’ve also changed other content files if I needed to.

To recreate package, I’ve used the App Packager tool. It’s located in Windows SDK folder (8.0 or 8.1) and it’s pretty easy to use: just point it to the unpacked folder and specify a new package path:

"C:\Program Files (x86)\Windows Kits\8.0\bin\x86\makeappx.exe" pack /d <PathToMyUnpackedAppFolder> /p <PathToNewAppPackage>\<PackageName>.appx

If the tool complains about missing resource files, add the /l option – that will disable missing file validation for cases where multiple version of the same resource is included in the package (e.g. multiple bitmap scale variations).

Signing the package

When package is created, it has to be signed. The signing is done using a different tool called SignTool. Again, the process is pretty straightforward, but you’ll need to have a certificate to sign the package. It’s best to use the certificate that was created by Visual Studio when the solution was associated with the Store application. That certificate file should be named something like <AppName>_StoreKey.pfx.

"C:\Program Files (x86)\Windows Kits\8.0\bin\x86\SignTool" sign /fd SHA256 /a /f <PathToCertificate>\<AppName>_StoreKey.pfx <PathToNewAppPackage>\<PackageName>.appx

The default hashing algorithm used to hash files when creating packages is SHA256 and since SIgnTool uses a different default (SHA1), it’s necessary to set the /fd parameter to appropriate algorithm. If you haven’t created the app package yourself and you’re not sure what algorithm was used while creating, check the AppBlockMap.xml that should be in the package. The file includes all file hashes and first element’s HashMethod attribute must specify the algorithm used.

So this is it! If you’re ever stuck with the Store application package that can’t be (re)created using Visual Studio and you only need to make a few modifications to be able to deploy it to the Store, you can do It manually.
Of course the same applies if you’re automating your app building process to create deployment-ready packages as well.

Windows Phone 8.1 – LocalCacheFolder

In one of my talks at recent NT konferenca I talked about some of the new ways of working with application data in Windows Phone 8.1. With all the exciting additions to the latest Windows Phone 8.1 APIs, the best news around application data in those new APIs is that they are now (mostly) aligned with the Windows Runtime (WinRT), so Windows 8 developers can pick up on them immediately and transition their work to the new platform, share code, etc.

With the aligned data APIs, Windows Phone 8.1 applications (both Silverlight and Runtime) can now store their data into one of the following folders:

  1. LocalFolder – a local folder, used for storing application data, it’s persistent across application updates and gets backed up to the cloud. This folder was already available in Windows Phone 8 and it’s the same folder as Isolated Storage known from Windows Phone 7.
  2. TemporaryFolder – also a local folder, but its space is managed by the OS. Whenever the system detects it’s running low on storage space, it will start deleting files in temporary so don’t ever strongly depend on files stored in this folder. It makes a perfect place for storing cached web responses or images that can be recreated any time. This folder does not participate in backups.
  3. RoamingFolder – files, stored in this folder, will roam across devices, meaning those files will be synchronized over the cloud whenever possible. Perfect for settings and/or small chunks of state (i.e. for continuous clients). When roaming is disabled on the device, those files (and settings) will get backed up as well. The storage space is limited to 100kB – if application goes over that quota, the synchronization stops (until the total usage falls back under roaming storage quota).

LocalCacheFolder

But wait - there’s one more folder in Windows Phone 8.1, that’s available in Windows Phone 8.1 API only. Even more, unlike some other APIs that are present on both Windows and Windows Phone and will throw an exception when used from the wrong platform, this one is completely hidden from Windows. Using it from a shared project, you have to #ifdef it out of Windows platform and include in Windows Phone build only:

#if WINDOWS_PHONE_APP
    var localCache = ApplicationData.Current.LocalCacheFolder;
#endif

So what is it? Is it used for caching? Well, not exactly (though it might, but I prefer the TemporaryFolder for that).

The LocalCacheFolder is almost exactly like the good old LocalFolder, with one single, but important exception – unlike LocalFoder, the files written to this folder will never be backed up to the cloud and will always stay on the device it was originally written at. Good for storing some (semi) sensitive information or pieces of state you don’t want or need to restore later.

And while I mentioned sensitive data, there’s one more thing worth mentioning - the best place to store sensitive data is into the Credential Locker (represented by the PasswordVault class), a familiar class from WinRT APIs, that is now also available to Windows Phone 8.1 – YAY!

Summary

To finish up, here’s a quick recap – use PasswordVault for storing sensitive information, LocalCacheFolder for data you don’t want ever to leave that particular phone, TemporaryFolder for temporary, easy-to-recreate data, RoamingFolder for settings and small state to synchronize across devices, and LocalFolder for main application data that gets backed up to the cloud (and, of course – restored).

Enable automatic daylight / night mode switch with your Windows Phone 8.1 app

Sample source code is available for download.

You know those fancy car GPS navigators that automatically switch color mode to dark when it gets dark to make it easy on your eyes? The display even turns dark when you drive into a tunnel and lights back up when you’re out…

Well, with ambient-light sensor support in the latest Windows Phone 8.1 SDK, it’s possible to build something quite like that. The new API is quite straightforward and follows the same practice as with other device sensors.

When your app starts, you should first query the device for the sensor to see if it exists. The GetDefault() method will return null if sensor isn’t present on the device or the system was unable to get a reference to it (happens when device is in a connected standby):

var sensor = Windows.Devices.Sensors.LightSensor.GetDefault();
if (sensor == null)
{
    return;
}

Once having access to the sensor, it’s recommended to set its reporting interval to default value, but in cases where you need to set it explicitly, you can do it by changing sensor’s ReportInterval, but check you’re not going below MinimumReportInterval. Here’s the code for setting it to 5 minutes, but if you need more dynamic readings, just leave it at default:

sensor.ReportInterval = Math.Max(sensor.MinimumReportInterval, 5*60*1000);

[Note: don’t forget to set it back to default – 0 – when you’re done]

To start reading, you can either perform a one-time read:

var reading = sensor.GetCurrentReading();

… or subscribe to continuous reads (with read interval set earlier):

sensor.ReadingChanged += OnLightSensorReadingChanged;

Either way, you’ll get a LightSensorReading with information about the current reading. The illuminance level returned by this is in lux so it should be easy to compare with some known values. I figured 500 – 1000 would be a good value to detect a decent daylight and in this example I’m testing against a value of 1000 lux.

We have the ambient light level, now what?

There are various cases where light sensor could come in handy, here’s a couple:

1. Allow user to have it’s theme respond to light, e.g. have light theme during the day and dark theme during the night. Reading apps, for example.
Luckily, in Windows Phone 8,1, changing theme for a page (or for any specific element) is now very simple. No more 3rd party helpers. Here’s an example of a OnLightSensorReadingChange event handler for the case, where application theme will be according to the latest sensor reading:

void OnLightSensorReadingChanged(Windows.Devices.Sensors.LightSensor sender, Windows.Devices.Sensors.LightSensorReadingChangedEventArgs args)
{
    Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
        () => RequestedTheme = args.Reading.IlluminanceInLux < 1000
              ? ElementTheme.Dark
              : ElementTheme.Light
        );
}

[Notice the relevant line is wrapped in a Dispatcher call – the LightSensorReadingChanged event will always be fired on a background thread so we have to get back to the UI thread to set a visual property properly]

2. Any app that displays a map could use this feature. Navigation apps, locators, running apps, …
And the Map control has a vary handy property to support this, let’s have a look at Map’s ColorScheme:

void OnLightSensorReadingChanged(Windows.Devices.Sensors.LightSensor sender, Windows.Devices.Sensors.LightSensorReadingChangedEventArgs args)
{
    Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
        () =>  Map.ColorScheme = args.Reading.IlluminanceInLux < 1000
               ? MapColorScheme.Dark
               : MapColorScheme.Light;
        );
}

One final note – the same API is available to Windows Store apps as well. Build for both, it’s great Smile

Download sample source code.

Launch Windows Phone 8.1 Podcasts app from your app

Latest Windows Phone update, called Windows Phone 8.1 will bring us a new app for managing podcasts. The Podcasts app, similar to what we previously had in Music+Videos hub’s podcasts section, will let users subscribe to their favorite shows to be played later on.

The good things for developers here is a fact that we’ll be able to integrate the new app in our applications’ workflow by launching the Podcasts app by one of the following URI schemes: itpc:, pcast: and podcast:.

For example, this is how you launch the Podcast app:

await Launcher.LaunchUriAsync(new Uri("podcast:"));

But it doesn’t end here. By specifying an Url pointing to a specific podcast feed, the app will fetch that feed and display podcast overview page and make it easy for the user to subscribe to that feed. Here’s an example of how to make it display the Hanselminutes feed:

await Launcher.LaunchUriAsync(new Uri("podcast:feeds.feedburner.com/HanselminutesCompleteMP3"));

image

Fun fact: the above screenshot was taken from my phone (device) using the Project my screen app, which was released today. Read more about it here.

Upon launching the app, the user has quick access to playing the latest episode (Podcasts app supports streaming) or subscribe to the series.

When user is done with subscribing or playing podcasts, navigating back will get her back to your app where she can continue her work with it.

Of course other apps can now move to supporting those URI protocols as well so, each user could choose her favorite podcast app to integrate with on her device.

Windows 8.1 XAML: Render to Bitmap

One of my favorite features coming in Windows 8.1 for developers has got to be the ability to render a selected piece of UI to an image and allowing for further manipulation with that image (changing pixels and ultimately saving it to some permanent storage location). We have this in WPF, Silverlight and Windows Phone. And now it’s coming to Windows Store apps as well. Specifically, it’s the RenderTargetBitmap class that makes this possible.

Take for example, this piece of UI:

image

Let’s say I don’t want to send this user data in a text form, but rather send an image of the filled-out form, for a change. And I want to include the violet part only, to get just the form, pure. You know, get rid of the gradient...

So I would take the Grid element that’s topmost in XAML tree I want to capture, and name it “TheForm”.
On button click, I’d let the user pick a file location, then invoke three magical lines:

var renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(TheForm);
var pixelBuffer = await renderTargetBitmap.GetPixelsAsync();

Where in fact the second line is the one actually doing the hard work of capturing the snapshot… So simple!

The rest of the code I have is just about picking the right encoder and actually pushing the bytes to the file:

using (var stream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
    var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
    encoder.SetPixelData(
        BitmapPixelFormat.Bgra8,
        BitmapAlphaMode.Ignore,
        (uint)renderTargetBitmap.PixelWidth,
        (uint)renderTargetBitmap.PixelHeight,
        logicalDpi,
        logicalDpi,
        pixelBuffer.ToArray());

    await encoder.FlushAsync();
}

But wait, there’s more!

The RenderTargetBitmap class is actually a subclass of ImageSource, which means you can set it to any property accepting the same type without having to worry about encoders or moving bytes around.

In the following example, I’m going to create a fake form entry sniffer that would take a snapshot of the form once on every two user keystrokes.
Instead of secretly sending snapped image to a secret location through a secret channel, I’ll simply add an Image control next to TheForm and make it a little bigger, say twice the width of the original form. I named it MirorImage.

In Page’s constructor, I’ll initialize a new instance of RenderTargetBitmap and set it as MirrorImage’s source:

mirrorRenderTargetBitmap = new RenderTargetBitmap();
MirrorImage.Source = mirrorRenderTargetBitmap;

With that done, I only have to worry about picking the right time to capture the form. I said I’d capture once every two keystrokes, so:

private async void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
    if (mustRender)
    {
        await mirrorRenderTargetBitmap.RenderAsync(TheForm);
    }
    mustRender = !mustRender;
}

(every TextBox on TheForm is of course wired to the TextBox_TextChanged event handler)

And the result:

image

The form on the right is just a rendered image of the original “TheForm” from the left. And although I’ve set the Image’s width to be twice the one of “TheForm” (while not specifically setting the height), the image is rendered correctly and proportionally. Note that you can also set the target image size manually when invoking the RenderAsync method – its overload is accepting width and height parameters.

These are only a couple of very basic examples of RenderTargetBItmap class usages, there are numerous cases where this is going to come in handy, I’m sure. This feature will be included in forthcoming Windows 8.1 update and will not work on current Windows 8 version.

Here’s a downloadable source code for this example. You’ll Visual Studio 2013 (Preview) and Windows 8.1 to open and run the project.

Starting with Nokia Imaging SDK

A couple of days ago, Nokia announced their new Lumia phone, Lumia 1020, that features a powerful 41 MP camera sensor. letting you shoot photos in incredible details, or as they’ve put it, “shoot first, zoom later” (nods to Lytro, I guess). Of course that kind of beast would require some serious needs for editing photos, taken by those lenses (there’s 6 in Lumia 1020 to be exact), and as it just happens, Nokia yesterday also released their Imaging SDK that allows Windows Phone (8) developers to create apps that manipulate pictures by applying various filters, resizing, etc. An SDK, that, if you will, will let you develop your next best-to Instagram app.

What can the Nokia Imaging SDK do?

The main feature of the SDK are 50+ image filters with adjustable settings, that you can apply to any image. The filters are listed here. Besides filters, there are APIs for manipulating images, like resizing, cropping and rotating.

Where do I find It?

Nokia Imaging SDK is freely downloadable from here. The SDK is free to use, but check the license here. You can skip the publisher entry form by clicking the “No thanks” button, but if you’re already a Windows Phone publisher, you can leave your publisher details to increase the chance Nokia spotting your next great app featuring their imaging SDK Smile

Installing the SDK will get you a local version of Nokia’s libraries, as well as a demo / sample project.

Note that you can also totally skip installing the SDK manually and rather pull the required libraries into existing projects through NuGet (always a good option).

How do I start?

If you installed the SDK through the installer, there’s a simple sample project included in the package (look in Program Files (x86)\Nokia\Nokia Imaging SDK\tutorial\TutorialNokiaImagingSDK\ImagingSDKTutorial folder).

If you want more samples, Nokia has got you covered. There are currently 3 more sample projects you can download from their sample projects page:

1. Filter Effects (project download here) lets you apply different filters to photos

2. Filter Explorer (project download here) is quite powerful image editor with extensive effects gallery.

3. Real-Time Filter Demo (project download here) shows how to apply included effects to a real-time camera stream.

Hands-on

I’ve created a new Windows Phone 8 project from scratch, using the installed libraries. There are some manual steps to take when adding references and I trust these will be addressed in the forthcoming releases. You can review these steps for both manual and NuGet install here.

What I wanted to try for this post, was a few simple tasks: take the photo, apply one of the photo filters, crop the image and save it to the library.

And implementing them was quite straightforward.

First, here’s some XAML:

<Grid Background="Transparent"
      Tap="OnChangePhoto">
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Image x:Name="Source" 
           Width="480" 
           Height="400" />
    <Image x:Name="Altered" 
           Width="480" 
           Height="400" 
           Grid.Row="1" />
</Grid>

It’s basically to Images stacked onto the page, each set to explicit size (more on that later). I want the “Source” image to display unaltered, raw captured photo, and “Altered” to display the manipulated image.

The code is simple too. Capture the photo:

var task = new CameraCaptureTask();
task.Completed += OnCapture;
task.Show();

Now we’re get to more exciting stuff. The meat of Nokia’s Imaging SDK lies in the EditingSession class that takes either a Bitmap class as a constructor, or an IBuffer implementation. And because we’re reading from a captured stream, IBuffer seems a closer fit:

Windows.Storage.Streams.IBuffer buffer;
using (var stream = new MemoryStream())
{
    await e.ChosenPhoto.CopyToAsync(stream);
    buffer = stream.GetWindowsRuntimeBuffer();
}

Once we get hold of the buffer, we can start the editing session:

using (var session = new EditingSession(buffer))
{

Except all you do in this session does not necessarily apply to “editing”. For example, there’s a helper method that will set the source of an image in a single statement:

await session.RenderToImageAsync(Source, OutputOption.PreserveAspectRatio);

Just don’t forget to set initial size of the image (see the XAML snippet above). The method will throw an exception if initial size is not set.

Source image is displayed, time for filters!

session.AddFilter(FilterFactory.CreateLomoFilter(.5, .5, LomoVignetting.High, LomoStyle.Neutral));

Every filter is created through Filter Factory and has different options you can set. Filter are also not just fancy artistic manipulations you can add to photo, there are also filters for mirroring, flipping, or rotating, to name a few. This is how you apply a cropping filter that cuts photos edges a bit. First, calculate the cropping rectangle and use it as a parameter:

var width = session.Dimensions.Width;
var height = session.Dimensions.Height;
var rect = new Windows.Foundation.Rect(width * .1, height * .1, width * .8, height * .8);

session.AddFilter(FilterFactory.CreateCropFilter(rect));

Done manipulating, display the “Altered” image:

await session.RenderToImageAsync(Altered, OutputOption.PreserveAspectRatio);

One task left. Save the image as JPEG:

var jpegBuffer = await session.RenderToJpegAsync();
var library = new MediaLibrary();
library.SavePicture("SDKSample.jpg", jpegBuffer.ToArray());

There are other RenderToJpeg method overloads that let you resize the image when writing to the output buffer, or specify the destination image quality.

Sounds fun, should I use it?

Nokia’s Imaging SDK is mostly valuable for its collection of filters, but it also takes the additional complexity away from working with compressed image files so it’s definitely worth looking at it.

And if you come up with a cool idea for an app that could make use of this SDK, don’t forget to enter the Nokia Future Capture competition (closes July 31st 2013).

Share charm stopped working while debugging Windows Store app?

An important part of working on Windows Store apps is implementing a Share contract, which allows your app to share parts of its content with other installed apps. Those apps then act as an extension to your app, taking that content and implementing them in different ways, e.g. the Mail app will include it in the body of a new mail or an attachment, twitter and Facebook clients will post it on your timeline, etc.

Debugging your Search contract code can, however, result in system-wide shutdown of the service, meaning that no Windows Store app can share any content with other apps anymore. In such case, instead of getting a list of apps, that are available to share, you’ll be notified that:

Something went wrong with Share. Try again later.

Typically, this happens when you stop debugging (in Visual Studio) while in DataTransferManager’s DataRequested event handler. And this can happen a lot, if you’re not careful Smile

OK, here’s what you do if it does happen. [tl;dr; Restart Explorer]

1. Open Task Manager
2. Select the Details tab
3. Find Explorer.exe (easiest to sort by Name)
4. End Task (button in right lower corner will do the job).
- don’t be afraid when your taskbar disappears, you’ll get it back
5. Select File –> Run new task
6. Type Explorer.exe in the input box
7. Press OK (and taskbar is back)

Your Share charm should be working again.

Highlighting search results within Windows Store apps

Download source code

Guidelines and checklist for search page for Windows Store apps (formerly Metro) suggest using hit highlighting to “indicate why a search result matches the [search] query”, as displayed on this screenshot (taken from the linked page):

That’s a great way to show the user why results are returned from the search query, but how do you implement that?

I already hinted at the suggested approach in my previous post, where I wrote about bindable Runs. Using the same technique, the hit highlighting guideline can be implemented pretty easily.

Let’s see how.

I’ve started out with a default Windows Store Grid app template, which provides the conveniently built-in sample data source. That’s the source we’re going to search through.

image

Of course we’ll need to implement the Search contract: Project –> Add New Item –> Search Contract. That will add the search results page to the project and put search activation code snippet into the App class.

image

The details for searching through the sample data source is yours to implement(a sample is included in provided source code).

Now for the relevant part.

The trick is to create a binding service that would take 3 input parameters:

1. Full text that contains the highlighted part,
2. Search text,
3. (Optional) highlight brush.

The service would extend the TextBlock control by clearing all its inlines and replacing them with a new set of Runs that will compose the new, highlighted text.

I’ve created a service that exposes these three parameters as dependency properties, this is the relevant code that executes when either full or highlighted text changes (find full implementation in the provided source code):

private static void OnTextChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    TextBlock textBlock = d as TextBlock;
    if (textBlock == null)
    {
        return;
    }
    string fullText = GetFullText(textBlock);
    string highlightedText = GetHighlightedText(textBlock);

    if (string.IsNullOrEmpty(fullText) || highlightedText == null)
    {
        return;
    }

    Brush brush = GetHighlightBrush(textBlock) ?? new SolidColorBrush(Windows.UI.Colors.Red);

    highlightedText = highlightedText.Substring(1, highlightedText.Length - 2);

    int length = highlightedText.Length;
    int lastIndex = 0;
    int index = fullText.IndexOf(highlightedText, 0, StringComparison.CurrentCultureIgnoreCase);

    textBlock.Inlines.Clear();
    while (index >= 0)
    {
        textBlock.Inlines.Add(new Run { Text = fullText.Substring(lastIndex, index - lastIndex) });
        textBlock.Inlines.Add(new Run { Text = fullText.Substring(index, length), Foreground = brush });
        lastIndex = index + length;
        index = fullText.IndexOf(highlightedText, lastIndex, StringComparison.CurrentCultureIgnoreCase);
    }
    textBlock.Inlines.Add(new Run { Text = fullText.Substring(lastIndex) });
}

To use this binding service, open StandardStyles.xaml (found in the Common folder) and search for the StandardSmallIcon300x70ItemTemplate style. This style is used to display the items in the search results page. You’ll find three TextBlocks in there – one for Title, one for Subtitle and the last one displays the Description. Instead of binding to Text property, wire those TextBlocks to the new binding service:

<TextBlock ifs:BindingService.FullText="{Binding Title}" ifs:BindingService.HighlightedText="{Binding DataContext.QueryText, ElementName=resultsPanel}" ifs:BindingService.HighlightBrush="#d9001f" Style="{StaticResource BodyTextStyle}" TextWrapping="NoWrap"/>
<TextBlock ifs:BindingService.FullText="{Binding Subtitle}" ifs:BindingService.HighlightedText="{Binding DataContext.QueryText, ElementName=resultsPanel}" ifs:BindingService.HighlightBrush="#d9001f"  Style="{StaticResource BodyTextStyle}" Foreground="{StaticResource ApplicationSecondaryForegroundThemeBrush}" TextWrapping="NoWrap"/>
<TextBlock ifs:BindingService.FullText="{Binding Description}" ifs:BindingService.HighlightedText="{Binding DataContext.QueryText, ElementName=resultsPanel}" ifs:BindingService.HighlightBrush="#d9001f"  Style="{StaticResource BodyTextStyle}" Foreground="{StaticResource ApplicationSecondaryForegroundThemeBrush}" TextWrapping="NoWrap"/>

And you’re done Smile

image

Download source code

Windows Store apps: the case of missing StringFormat or Binding on the Run

If your previous developer experience include developing for other XAML technologies and you’re moving into the Windows Store apps space, you’ve already noticed that a lot of things you were used to in other techs, are missing from your Windows Store app development experience. One example being there’s no more StringFormat property available in your Binding markup construct. You may have been used to writing something like:

<TextBlock Text="{Binding Name, StringFormat='Name: \{0\}'}" />

(that would bind your TextBlock to the Name property, outputting “Name: [property value]” to the UI)

With StringFormat missing from WinRT’s XAML Binding, you have two options:

1. Create a StringFormat value converter and handle your string formatting there.

2. Break down your text into smaller chunks of text and bind those to the Runs, which are part of your TextBlock:

<TextBlock Style="{StaticResource BodyTextStyle}" TextWrapping="NoWrap">
  <Run Text="Name: " />
  <Run Text="{Binding Name}" Foreground="Red" />
</TextBlock>

Yes, Runs are bindable!

Not only will Runs inherit styling attributes from their parent TextBlock, you can override them in whole, or just parts of it (like changing color only, etc.) And you make your TextBlock “bind” to more than one property in one go, something not possible with StringFormat or converter workaround.

Pretty cool.

Variable-sized grid items in Windows 8 apps

This is a screenshot of the Windows 8 Store app:

image

And this is what you get when you start a new Windows 8 “Windows Store Grid App”:

image_3

Wouldn’t it be great if you would be able to control the size of each particular item in your grid? To break out from dullness of having all items the same size, like, for example, to emphasize featured items; or for just any other reason?

Turns out you can do that (quite easily). I came about to this blog post describing one way to do it: “Windows 8 Beauty Tip: Using a VariableSizedWrapGrid in a GridView makes Grids Prettier” by Jerry Nixon. Reading it, I thought there had to be some easier way to do it than subclassing a GridView just for this.

And it turned out there was. Or at least it would be, if Windows 8 XAML supported Style Bindings like Silverlight 5. Not having that, the solution required that extra step that would allow binding to properties from within declared styles.

So what’s the idea?

Looking at GridView’s GroupStyle ItemsPanelTemplate after creating a new, default, Windows Store Grid App, it’s already set to VariableSizedWrapGrid – exactly what I needed. Now you just have to set its ItemWidth and ItemHeight properties to 250, and at the same time, remove those explicit sizes from the Standard250x250ItemTemplate (found in StandardStyles.Xaml). This puts GridView in control of sizing the GridViewItems.

The next step is adapting the model with extra two properties that will hold the horizontal and vertical spanning values. For this, you have to extend the provided SampleDataItem class with two new properties:

private int _horizontalSize = 1;
public int HorizontalSize
{
    get { return this._horizontalSize; }
    set { this.SetProperty(ref this._horizontalSize, value); }
}

private int _verticalSize = 1;
public int VerticalSize
{
    get { return this._verticalSize; }
    set { this.SetProperty(ref this._verticalSize, value); }
}

The default value for both is 1, which means, each item should occupy one unit of the grid only. HorizontalSize of 2 should span 2 columns, and VerticalSize of 2 should span 2 rows. Having both properties set to 2 would of course make the item occupy four units of the grid (2x2).

For this example, I only made the first item bigger.

If Windows 8 apps supported Binding from styles, I would easily finish this off by creating a new Style like:

<Style x:Key="VariableGridViewItemStyle" TargetType="GridViewItem">
  <Setter Property="VariableSizedWrapGrid.ColumnSpan" Value="{Binding HorizontalSize}" />
  <Setter Property="VariableSizedWrapGrid.RowSpan" Value="{Binding VerticalSize}" />
</Style>

… and set this style as GridView’s ItemContainerStyle.

Unfortunately, such binding is not yet supported, so I had to find some other way to do it.

Delay’s code to the rescue! It’s a complete (and short) solution that does exactly what I needed and it just works. I had to adapt it to suit WinRT and its new reflection model a bit, but at its core it stayed the same.

Here’s the adapted style that can bind to my properties through modified Delay’s helper:

<Style x:Key="VariableGridViewItemStyle" TargetType="GridViewItem">
    <Setter Property="local:SetterValueBindingHelper.PropertyBinding">
        <Setter.Value>
            <local:SetterValueBindingHelper>
                <local:SetterValueBindingHelper
                    Type="VariableSizedWrapGrid"
                    Property="ColumnSpan"
                    Binding="{Binding HorizontalSize}" />
                <local:SetterValueBindingHelper
                    Type="VariableSizedWrapGrid"
                    Property="RowSpan"
                    Binding="{Binding VerticalSize}" />
            </local:SetterValueBindingHelper>
        </Setter.Value>
    </Setter>
</Style>

After applying this change, the result can effectively be observed in Visual Studio 2012 (thanks XAML Editor Smile), and here’s how the app looks when running:

image_4

I like this approach because it’s XAML-only - it doesn’t force me to use a derived control and I can specify the sizing properties I want to bind to through my style resource. Which makes the solution a bit more flexible. The downside is of course this requirement of having a Style binding helper class, but I really really hope the Windows 8 gets this built in ASAP.

To close, here’s the modified version of Delay’s SetterValueBindingHelper (not really tested yet!):

public class SetterValueBindingHelper
{
    /// <summary>
    /// Optional type parameter used to specify the type of an attached
    /// DependencyProperty as an assembly-qualified name, full name, or
    /// short name.
    /// </summary>
    [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods",
        Justification = "Unambiguous in XAML.")]
    public string Type { get; set; }

    /// <summary>
    /// Property name for the normal/attached DependencyProperty on which
    /// to set the Binding.
    /// </summary>
    public string Property { get; set; }

    /// <summary>
    /// Binding to set on the specified property.
    /// </summary>
    public Binding Binding { get; set; }

    /// <summary>
    /// Collection of SetterValueBindingHelper instances to apply to the
    /// target element.
    /// </summary>
    /// <remarks>
    /// Used when multiple Bindings need to be applied to the same element.
    /// </remarks>
    public Collection<SetterValueBindingHelper> Values
    {
        get
        {
            // Defer creating collection until needed
            if (null == _values)
            {
                _values = new Collection<SetterValueBindingHelper>();
            }
            return _values;
        }
    }

    private Collection<SetterValueBindingHelper> _values;

    /// <summary>
    /// Gets the value of the PropertyBinding attached DependencyProperty.
    /// </summary>
    /// <param name="element">Element for which to get the property.</param>
    /// <returns>Value of PropertyBinding attached DependencyProperty.</returns>
    [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters",
        Justification = "SetBinding is only available on FrameworkElement.")]
    public static SetterValueBindingHelper GetPropertyBinding(FrameworkElement element)
    {
        if (null == element)
        {
            throw new ArgumentNullException("element");
        }
        return (SetterValueBindingHelper) element.GetValue(PropertyBindingProperty);
    }

    /// <summary>
    /// Sets the value of the PropertyBinding attached DependencyProperty.
    /// </summary>
    /// <param name="element">Element on which to set the property.</param>
    /// <param name="value">Value forPropertyBinding attached DependencyProperty.</param>
    [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters",
        Justification = "SetBinding is only available on FrameworkElement.")]
    public static void SetPropertyBinding(FrameworkElement element, SetterValueBindingHelper value)
    {
        if (null == element)
        {
            throw new ArgumentNullException("element");
        }
        element.SetValue(PropertyBindingProperty, value);
    }

    /// <summary>
    /// PropertyBinding attached DependencyProperty.
    /// </summary>
    public static readonly DependencyProperty PropertyBindingProperty =
        DependencyProperty.RegisterAttached(
            "PropertyBinding",
            typeof (SetterValueBindingHelper),
            typeof (SetterValueBindingHelper),
            new PropertyMetadata(null, OnPropertyBindingPropertyChanged));

    /// <summary>
    /// Change handler for the PropertyBinding attached DependencyProperty.
    /// </summary>
    /// <param name="d">Object on which the property was changed.</param>
    /// <param name="e">Property change arguments.</param>
    private static void OnPropertyBindingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        // Get/validate parameters
        var element = (FrameworkElement) d;
        var item = (SetterValueBindingHelper) (e.NewValue);

        if ((null == item.Values) || (0 == item.Values.Count))
        {
            // No children; apply the relevant binding
            ApplyBinding(element, item);
        }
        else
        {
            // Apply the bindings of each child
            foreach (var child in item.Values)
            {
                if ((null != item.Property) || (null != item.Binding))
                {
                    throw new ArgumentException(
                        "A SetterValueBindingHelper with Values may not have its Property or Binding set.");
                }
                if (0 != child.Values.Count)
                {
                    throw new ArgumentException(
                        "Values of a SetterValueBindingHelper may not have Values themselves.");
                }
                ApplyBinding(element, child);
            }
        }
    }

    /// <summary>
    /// Applies the Binding represented by the SetterValueBindingHelper.
    /// </summary>
    /// <param name="element">Element to apply the Binding to.</param>
    /// <param name="item">SetterValueBindingHelper representing the Binding.</param>
    private static void ApplyBinding(FrameworkElement element, SetterValueBindingHelper item)
    {
        if ((null == item.Property) || (null == item.Binding))
        {
            throw new ArgumentException(
                "SetterValueBindingHelper's Property and Binding must both be set to non-null values.");
        }

        // Get the type on which to set the Binding
        Type type = null;
        TypeInfo typeInfo = null;
        if (null == item.Type)
        {
            // No type specified; setting for the specified element
            type = element.GetType();
            typeInfo = type.GetTypeInfo();
        }
        else
        {
            // Try to get the type from the type system
            type = System.Type.GetType(item.Type);
            if (null == type)
            {
                // Search for the type in the list of assemblies
                foreach (var assembly in AssembliesToSearch)
                {
                    // Match on short or full name
                    typeInfo = assembly.DefinedTypes
                        .Where(t => (t.FullName == item.Type) || (t.Name == item.Type))
                        .FirstOrDefault();
                    if (null != typeInfo)
                    {
                        // Found; done searching
                        break;
                    }
                }
                if (null == typeInfo)
                {
                    // Unable to find the requested type anywhere
                    throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                                                              "Unable to access type \"{0}\". Try using an assembly qualified type name.",
                                                              item.Type));
                }
            }
            else
            {
                typeInfo = type.GetTypeInfo();
            }
        }
        
        // Get the DependencyProperty for which to set the Binding
        DependencyProperty property = null;
        var field = typeInfo.GetDeclaredProperty(item.Property + "Property"); // type.GetRuntimeField(item.Property + "Property");
        if (null != field)
        {
            property = field.GetValue(null) as DependencyProperty;
        }
        if (null == property)
        {
            // Unable to find the requsted property
            throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                                                      "Unable to access DependencyProperty \"{0}\" on type \"{1}\".",
                                                      item.Property, type.Name));
        }

        // Set the specified Binding on the specified property
        element.SetBinding(property, item.Binding);
    }

    /// <summary>
    /// Returns a stream of assemblies to search for the provided type name.
    /// </summary>
    private static IEnumerable<Assembly> AssembliesToSearch
    {
        get
        {
            // Start with the System.Windows assembly (home of all core controls)
            yield return typeof(Control).GetTypeInfo().Assembly;
        }
    }
}