Advertisements
//
you're reading...
mango, Programming, wp7

Microsoft Style Dynamic Tiles for Windows Phone Mango

Mail Tile Image

Update: I’ve published the code for this post on github. Get the code here.

Have you ever wanted to create a transparent tile for your app that mimics the way the built in Messaging and Mail apps work on your Windows Phone? I’m going to provide specifics on how to mimic the style and do it all on the phone. Prior to Mango, there were only a couple ways to do this and both were nasty. With Mango, we can easily manipulate the primary and secondary tiles for our apps in code.

My goal is to provide a visual way to setup your tile and eliminate the need to write any unnecessary code. There’s no need to write any code to manipulate what’s actually on the tile (i.e. text, images, etc.) since we’ve already been provided a sophisticated layout tool by Microsoft, the visual designer of Visual Studio or Expression Blend. I’ve provided a sample project with all the source code for you to use freely in your projects. The above image is what we’re trying to achieve.

Let’s break down some of the details we’re going to need:

  • Font is Segoe WP Semibold 64 pt.
  • Vertical center of text container should be at 80 pixels from the top of the image.
  • Total height of usable area is 160. (This leaves room for the tile’s title. If you’re not using a title, you can use the entire height of 173 pixels)

User Control

As I said, we want to use these details and arrange the elements visually. To this end, we’re going to use a custom UserControl and use the XAML markup to specify how our tile works. I have a stand-in transparent png image to use as a glyph next to the numbers. Here’s the UserControl XAML:

<UserControl x:Class="MySuperTile.DynamicTile"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    d:DesignHeight="173" d:DesignWidth="173">

        <Canvas Background="{Binding Background}" Width="173" Height="173" x:Name="layoutRoot">
            <StackPanel Width="173" Height="160" Orientation="Horizontal">
                <Image Source="/images/coffee-cup.png" Width="58" Height="98" HorizontalAlignment="Center" Margin="12,0,0,0" />
                <TextBlock x:Name="numberText" Text="{Binding Text}" Width="103" FontFamily="Segoe WP Semibold" FontSize="64" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center"/>
            </StackPanel>
        </Canvas>

</UserControl>

The user control contains a canvas that contains a stack panel. Note that the stack panel is only 160px tall. Then, the transparent PNG is placed first with the numerals next to it. That’s all we need for the XAML. I used sweet data binding to dynamically set the values of the background and text. You could easily make the image bindable to any image if you want to change it on the fly.

The code behind for the user control is:

public partial class DynamicTile : UserControl
    {
        /// <summary>
        /// Identifies <see cref="TextProperty"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(DynamicTile), null);

        /// <summary>
        /// Identifies <see cref="TitleProperty"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(DynamicTile), null);

        /// <summary>
        /// Gets or sets the text displayed in the tile.
        /// This is a dependency property.
        /// </summary>
        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        /// <summary>
        /// Gets or sets the title of the tile.
        /// This is a dependency property.
        /// </summary>
        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        public DynamicTile()
        {
            InitializeComponent();

            DataContext = this;
        }

        /// <summary>
        /// Used to render the contents to a tile
        /// </summary>
        /// <returns>a <see cref="StandardTileData"/> with the contents of this control</returns>
        public StandardTileData ToTile()
        {
            // Need to call these, otherwise the contents aren't rendered correctly.
            this.Measure(new Size(173, 173));
            this.Arrange(new Rect(0, 0, 173, 173));

            // The png encoder is the work of the ImageTools API. http://imagetools.codeplex.com/
            ExtendedImage tileImaged = this.ToImage();

            Encoders.AddEncoder<PngEncoder>();

            var p = new PngEncoder();

            const string tempFileName = "/Shared/ShellContent/tileImage.png";

            using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (myIsolatedStorage.FileExists(tempFileName))
                {
                    myIsolatedStorage.DeleteFile(tempFileName);
                }

                IsolatedStorageFileStream fileStream = myIsolatedStorage.CreateFile(tempFileName);
                p.Encode(tileImaged, fileStream);
                fileStream.Close();
            }

            var newTile = new StandardTileData
            {
                Title = Title,
                BackgroundImage =
                    new Uri("isostore:" + tempFileName, UriKind.RelativeOrAbsolute)
            };

            return newTile;
        }
    }

In this code, we have a couple of dependency properties (for data binding) and a method to transform the user control into a tile. The difference here is that most guides use the built in JPEG manipulation tools for setting the tile image. But remember I said we are doing a Microsoft style tile with transparency. To get that transparency, we’ll need a PNG image. Saving to PNG is not built into the platform, so I used a 3rd party piece of software called ImageTools (http://imagetools.codeplex.com) that will handle the PNG manipulation.

ImageTools provides an extension method “ToImage()” that takes a UIElement and transforms it into an ExtendedImage (which is part of the ImageTools). Then, using that ExtendedImage, we use the PNG encoder to save the image to IsolatedStorage; the image URI is then given to the tile. The other piece of code that is imperative is:

this.Measure(new Size(173, 173));
this.Arrange(new Rect(0, 0, 173, 173));

If that’s not in there the elements will render, but not where they should be. So don’t forget those.

Dropping in the Tile

Now, to actually create the tile, we’ll use this code:

var mySweetDynamicTile = new DynamicTile
                                {
                                    Text = textCount.Text,
                                    Title = textCount.Text,
                                    Background = new SolidColorBrush(Colors.Purple)
                                };

// Retrieve the contents of the tile as a StandardTileData
var newTile = mySweetDynamicTile.ToTile();

// Use the new tile as the primary tile for this app.
ShellTile primaryTile = ShellTile.ActiveTiles.First();

if (primaryTile != null)
{
    primaryTile.Update(newTile);
}

That code instantiates a DynamicTile, sets the title, text, and background color, then asks DynamicTile to create a tile of itself. That tile is then set as the primary tile and, voila, the tile of our app is now set to a dynamic, transparent, tile with Microsoft style numbering. There’s a lot you could do to customize this solution. For example, I used a solid color brush, but there’s nothing stopping you from creating an image brush or a gradient brush. Setting a transparent background (no background, basically), will allow the phone’s accent color to show through.

End Result

Tile Image created by MySuperTile Bam. There you go. No nasty code. Transparent. Beautiful.

A sample project with all the source code is available here.

Comments or Questions? Let me know. Don’t forget to follow me on twitter (@kenstone).

Advertisements

Discussion

6 thoughts on “Microsoft Style Dynamic Tiles for Windows Phone Mango

  1. Nice code, but the toImage() creates a 90×70 image and the final livetile doesn’t look right.

    I’ve changed nothing in your code… Some ideas, why?

    Posted by arne | December 30, 2011, 7:16 am
    • Update: I called the code from out of an Click event in a toolkit:ContextMenu element. I guess the tile was rendered in the context of this UIElement instead of the MainPage.
      Calling it inside the entire UI-Thread solves the issue:

      Deployment.Current.Dispatcher.BeginInvoke(delegate
      {
      // … code to create the LiveTile here…
      });

      However, the LiveTile-Icon is not shown (7.1 SDK) – It’s “Build Action” is set to “Content” and it’s path is /Images/LiveTileIcon.png

      Posted by arne | January 1, 2012, 3:16 am
      • So are you trying to overwrite a tile image that’s built into the image? I’m not sure how to do that or if its possible. In my code, I write it to the isolated storage and reference that image as the tile image.

        Posted by Kenstone | January 1, 2012, 2:21 pm
  2. I’m not sure what you might be experiencing. There’s a discussion on the app hub forums that demonstrates how the code works and doesn’t work depending on where in your code you put it.

    http://forums.create.msdn.com/forums/t/96862.aspx

    Give that a look. Maybe it’ll help you figure out what’s wrong.

    Posted by Kenstone | December 30, 2011, 7:43 am
  3. So this is really awesome because I was despairing I would not be able to figure out how to do this. This is my first time creating a livetile and it looks really awesome and beautiful, thanks so much for making this and putting it up on github.

    I’ve hit a bit of a snag trying to figure out how to -update- the tiles I’ve created, though.

    I’m using Mango’s “pin tile” functionality in order to get multiple tiles, each showing a countdown for a different event. Here’s how I’m doing it:
    I’ve imported your DynamicTile.xaml and DynamicTile.xaml.cs and associated references into my VS2010 project. I have a page with a “Pin” appbar button. When “pin” is pressed, first I create a new DynamicTile object (“tileData”) and set the text and title properties. In this case, “text” gets:
    tileData.Text = ce.calculateTime().ToString();

    And then I create the Uri and title and use ShellTile.Create(…). That works great!

    But, I can’t figure out how to schedule updates for my tile such that every time it ‘updates’, I pass it in a new DynamicTile background. The code I’m using for updating is what I got from this tutorial: http://msdn.microsoft.com/en-us/library/ff769548(v=VS.92).aspx under “Scheduling secondary tiles”. Any ideas?
    thanks!
    -zach

    Posted by Zach A (@IcePotato) | February 29, 2012, 8:59 pm
  4. I believe the ShellTileSchedule you’re looking at will only update the background image of a tile at a given URI. Assuming this actually works against an isostore URI (which I’m not sure of), the tile would only update if you’ve already written new data to that image between updates.

    So, ShellTileSchedule will not update the tile with dynamic information the way you’re looking to do it. Give a look at creating a BackgroundAgent for your app. This will run periodically and let you run arbitrary code on every update. Doing this will let you update the isostore image and update the tile.

    Posted by Kenstone | March 1, 2012, 8:02 am

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Advertisements

I'm Ken Stone. I'm an indie developer with a focus on .NET and Windows Phone development. I have a day job, but everything I say is mine alone.

TechEd 2012July 11th, 2012
Let the learning begin.
%d bloggers like this: