SharpGIS

#GIS from a .NET developer's perspective

Decoding the IXamlMetadataProvider interface - Part 1

The WinRT XAML SDK holds a big secret. It’s even a secret why it’s a secret. But you’ll see several of forum posts with Microsoft staff hinting at this secret, but not following up with actual examples or sufficient documentation.

So what is this secret? Well let’s start with good old WPF, Silverlight and what else is dead. One of the issues with these frameworks has been performance, and one of the performance issues was converting XAML into running code at runtime. This requires a lot of reflection and was part of the performance problem. WinRT attempts to solve this by taking this hit during compile time. It basically generates metadata about the classes you use, and thereby avoids the reflection overhead. At first glance this is pretty clever but as I’ll show later can also have some major issues that require a lot of code using hardly documented interfaces to resolve.

This is my attempt to decode some of these interfaces. I’m not fully understanding all the bits myself yet, so this blogpost is partly to share what I found, but also my process for better understanding it.

So back to the big secret: IXamlMetadataProvider. This is the main interface that drives this type resolving at runtime, and for the most part this is done for you, and this is also where our journey will start, because we can take a peek at that work. Open any of your Windows Store XAML apps projects, turn on the “show all files”, and open up the secret \obj\[Config]\XamlTypeInfo.g.cs file.

image

The code will look something like this in the top:

image

Keep scrolling a bit down, and you’ll start seeing some string-based typename lookups, including the types you use in your app:

image

Now let’s try and create a new class and see what happens to this file. Let’s add the following class:

public class StringCollection : ObservableCollection<string> { } 

Rebuild, and check the auto generated file. You’ll notice that this class does not show up. This is because it’s not used in XAML or by anything else that is used in XAML. Next try declaring this collection as a resource in XAML:

<Grid.Resources>
    <local:StringCollection x:Key="coll" />
</Grid.Resources>

Let’s jump back and look at the CreateXamlType method that magically  just got updated with a whole lot of more code:

private Windows.UI.Xaml.Markup.IXamlType CreateXamlType(string typeName)
{
    XamlMetadataSample.XamlMetadataSample_XamlTypeInfo.XamlSystemBaseType xamlType = null;
    XamlMetadataSample.XamlMetadataSample_XamlTypeInfo.XamlUserType userType;

    switch (typeName)
    {
    case "Object":
        xamlType = new XamlMetadataSample.XamlMetadataSample_XamlTypeInfo.XamlSystemBaseType(typeName, typeof(object));
        break;

    case "String":
        xamlType = new XamlMetadataSample.XamlMetadataSample_XamlTypeInfo.XamlSystemBaseType(typeName, typeof(string));
        break;

    case "Int32":
        xamlType = new XamlMetadataSample.XamlMetadataSample_XamlTypeInfo.XamlSystemBaseType(typeName, typeof(int));
        break;

    case "Windows.UI.Xaml.Controls.Page":
        xamlType = new XamlMetadataSample.XamlMetadataSample_XamlTypeInfo.XamlSystemBaseType(typeName, typeof(Windows.UI.Xaml.Controls.Page));
        break;

    case "Windows.UI.Xaml.Controls.UserControl":
        xamlType = new XamlMetadataSample.XamlMetadataSample_XamlTypeInfo.XamlSystemBaseType(typeName, typeof(Windows.UI.Xaml.Controls.UserControl));
        break;

    case "XamlMetadataSample.StringCollection":
        userType = new XamlMetadataSample.XamlMetadataSample_XamlTypeInfo.XamlUserType(this, typeName, typeof(XamlMetadataSample.StringCollection), GetXamlTypeByName("System.Collections.ObjectModel.ObservableCollection<String>"));
        userType.Activator = Activate_0_StringCollection;
        userType.CollectionAdd = VectorAdd_0_StringCollection;
        xamlType = userType;
        break;

    case "System.Collections.ObjectModel.ObservableCollection<String>":
        userType = new XamlMetadataSample.XamlMetadataSample_XamlTypeInfo.XamlUserType(this, typeName, typeof(ObservableCollection<string>), GetXamlTypeByName("System.Collections.ObjectModel.Collection<String>"));
        AddToMapOfTypeToStandardName(typeof(ObservableCollection<string>),
                                            "System.Collections.ObjectModel.ObservableCollection<String>");
        userType.Activator = Activate_1_ObservableCollection;
        userType.CollectionAdd = VectorAdd_1_ObservableCollection;
        xamlType = userType;
        break;

    case "System.Collections.ObjectModel.Collection<String>":
        userType = new XamlMetadataSample.XamlMetadataSample_XamlTypeInfo.XamlUserType(this, typeName, typeof(Collection<string>), GetXamlTypeByName("Object"));
        AddToMapOfTypeToStandardName(typeof(Collection<string>),
                                            "System.Collections.ObjectModel.Collection<String>");
        userType.Activator = Activate_2_Collection;
        userType.CollectionAdd = VectorAdd_2_Collection;
        userType.AddMemberName("Count");
        AddToMapOfTypeToStandardName(typeof(int),
                                            "Int32");
        xamlType = userType;
        break;

    case "XamlMetadataSample.MainPage":
        userType = new XamlMetadataSample.XamlMetadataSample_XamlTypeInfo.XamlUserType(this, typeName, typeof(XamlMetadataSample.MainPage), GetXamlTypeByName("Windows.UI.Xaml.Controls.Page"));
        userType.Activator = Activate_3_MainPage;
        xamlType = userType;
        break;

    }
    return xamlType;
}

What just happened? The compiler detected that you want to use your StringCollection class, so it creates type resolvers for this, and ANYTHING else it depends on, including base classes and types for all their properties which is why  you also see string, int, object etc show up.

Now let’s try something else. Remove the resource we added, and instead add the following property to MainPage.xaml.cs

public StringCollection MyCollection { get; set; }

CreateXamlType doesn’t change, but instead take a look at CreateXamlMember that changes from this:

private IXamlMember CreateXamlMember(string longMemberName)
{
    XamlMetadataSample.XamlMetadataSample_XamlTypeInfo.XamlMember xamlMember = null;
    // No Local Properties
    return xamlMember;
}

to this:

private IXamlMember CreateXamlMember(string longMemberName)
{
    XamlMetadataSample.XamlMetadataSample_XamlTypeInfo.XamlMember xamlMember = null;
    XamlMetadataSample.XamlMetadataSample_XamlTypeInfo.XamlUserType userType;

    switch (longMemberName)
    {
    case "XamlMetadataSample.MainPage.MyCollection":
        userType = (XamlMetadataSample.XamlMetadataSample_XamlTypeInfo.XamlUserType)GetXamlTypeByName("XamlMetadataSample.MainPage");
        xamlMember = new XamlMetadataSample.XamlMetadataSample_XamlTypeInfo.XamlMember(this, "MyCollection", "XamlMetadataSample.StringCollection");
        xamlMember.Getter = get_0_MainPage_MyCollection;
        xamlMember.Setter = set_0_MainPage_MyCollection;
        break;
    }
    return xamlMember;
}

So because our MainPage control now has a new property, this gets reflected by the auto-generated code.

What about 3rd party control libraries then? How do these get included? Well let’s take a look. First create a new Windows Store Class Library, and add a new “MyCustomControl” templated control to it. You’ll note that this new project will have its own auto-generated magic code in it’s obj folder and that works just the same way as explained on top. Basically anything you use in your Themes\Generic.xaml or any other XAML file is getting code generated for it. No surprises there. But let’s add a reference to this project to our test project, and see what will happen to the apps’s XamlTypeInfo.g.cs file. Suddenly a new property “XamlTypeInfoProvider.OtherProviders” is added:

private List<IXamlMetadataProvider> OtherProviders
{
    get
    {
        if(_otherProviders == null)
        {
            _otherProviders = new List<IXamlMetadataProvider>();
            IXamlMetadataProvider provider;
            provider = new MyControlLibrary.MyControlLibrary_XamlTypeInfo.XamlMetaDataProvider() as IXamlMetadataProvider;
            _otherProviders.Add(provider); 
        }
        return _otherProviders;
    }
}

So your app’s metadata provider automatically “merges” other project’s providers in this autogenerated code. Just for fun, let’s try and create a new class that implements IXamlMetadataProvider and add to our controls library, and see what happens:

public class MyCustomMetadataProvider : IXamlMetadataProvider
{
    public IXamlType GetXamlType(string fullName)
    {
        throw new NotImplementedException();
    }

    public IXamlType GetXamlType(Type type)
    {
        throw new NotImplementedException();
    }

    public XmlnsDefinition[] GetXmlnsDefinitions()
    {
        throw new NotImplementedException();
    }
}

And the OtherProviders property now suddenly looks like this:

private List<IXamlMetadataProvider> OtherProviders
{
    get
    {
        if(_otherProviders == null)
        {
            _otherProviders = new List<IXamlMetadataProvider>();
            IXamlMetadataProvider provider;
            provider = new MyControlLibrary.MyCustomMetadataProvider() as IXamlMetadataProvider;
            _otherProviders.Add(provider); 
            provider = new MyControlLibrary.MyControlLibrary_XamlTypeInfo.XamlMetaDataProvider() as IXamlMetadataProvider;
            _otherProviders.Add(provider); 
        }
        return _otherProviders;
    }
}

So the auto-generated code automatically detected that my custom library has a second metadata provider embedded, and injects it into this list as well as the auto-generated one. So it looks like we should be able to provide our own implementations, which I’ll get back to later.

So what have we found so far? That all types that’s being used directly or indirectly in XAML is getting type information generated, and properties on controls are getting metadata generated for those. Great you might think, but why would you need to know about this? Well the devil is in the details. Let me repeat the first finding again:

“All types that’s being used directly or indirectly in XAML is getting type information generated”

But what if I’m not using a type at compile time but only at runtime?” you might ask. That’s an excellent question and this is actually very likely to happen if your ViewModel or Model returns a type not used anywhere directly or indirectly in XAML to begin with, or if you were to use the XamlReader to parse XAML at runtime. This is also where Windows Store Xaml development starts to get really tricky very fast, and while there’s a way around this, it’s definitely not a straightforward one. And I’ll leave you hanging here to ponder on that, while I get working on Part 2 of this blogpost where I’ll get back to the custom IXamlMetadataProviders…

Building A Powerful Platform for Windows Store Mapping apps

When Microsoft announced WinRT at the Build conference in Anaheim, I instantly started researching and prototyping what this new platform could mean for the company I’m working for. The promise of integrating legacy native code with XAML and .NET seemed to finally be the exactly what I’ve been looking for. Also the tight integration between XAML and DirectX, something which is really complex to get working in WPF was intriguing, since we were often hitting the limit of what XAML could do.

We have a huge amount of native code that does a lot of advanced spatial analysis, advanced map rendering, spatial databases, etc. Even better was that most of it is written in a cross-platform way using C++ and was already running on Windows Classic, Linux, iOS, Android and several other platforms.

In hindsight I’m really amazed how quickly this work can go. Granted a lot of time was spent on researching, prototyping, ‘socializing the idea’ etc, but after we had the bases right, we were actually able to move very fast, and in less than 3 months create a whole new SDK geared for the Windows Store (albeit beta).

The things that made this go so fast was:

  1. We had lots of C++ code that was already written to be compiled cross-platform, so most of the development time was spent on exposing this via the WinRT interface and C++/CX.
  2. We chose to build a hybrid SDK based on both C++ and C#. This enabled us to port large amount of our existing C# code from our WPF and Silverlight SDKs. It also allowed us to not be limited by the inheritance limitations that WinRT has by simply creating .NET class libraries rather than WinRT class libraries, which in turn greatly simplifies the API for other developers.

Things that set us back:

  1. Our rendering engine only supported DirectX 9 and OpenGL. Windows Store apps require DirectX 11, which is quite different from v9, so a lot of work had to be done there, because we wanted to do it in a way that wasn’t being hurt by the least common denominator (ie. if DX11 supports a feature that DX9 or OpenGL doesn’t, it shouldn’t hold us back from using it). In the end, our map rendering engine became better because of it for all the platforms.
  2. The documentation on SurfaceImageSource (the glue behind DirectX and XAML) was very limited.
  3. Some time was spent on making sure the native code passes certification, although not too bad.

Several people both within the company, from Microsoft, MVPs etc has been extremely helpful getting us through those setbacks. Thank you! You know who you are (and yes I owe you beer :-)

So enough about that. Instead, I would really encourage you to go download our SDK. It’s actually free! Just go to our developers siteand hit the download button. You’ll be required to register/sign in – don’t worry – as far as I know we don’t spam :-)

Grab the download, install it, and create a new C# or VB.NET Windows Store app. Add a reference to the ArcGIS Runtime SDKs, set the build target to x86, x64 or ARM (AnyCPU won’t work since this has cool C++ code in its guts).

image

And now code away. There’s a few samples on how to get started with the API as well as a library reference on the developers site.  We know the documentation is a little slim at this point – we’re hard at work improving that. However we do have a getting started tutorial here: http://developers.arcgis.com/en/windows-store/guide/add-a-map-to-your-app.htm

In addition we have a set of samples in the form of a sample browser available today on GitHub: https://github.com/Esri/arcgis-samples-winstore

There’s also a toolkit with some controls here that you are encouraged to fork and contribute to: https://github.com/Esri/arcgis-toolkit-winstore

I did a short introduction to the API at our plenary about 4 mins into this video:

You can download the source code for the sample I built on stage on my github account here: https://github.com/dotMorten/WinStore-Routing-Sample

Go download and code away today, and ask questions and give us feedback in the forum.

Also please go read the official SDK release announcement here: http://blogs.esri.com/esri/arcgis/2013/03/25/arcgis-runtime-sdk-for-windows-store-apps-beta-is-available/

Shortcut Key Handling in Windows Store Apps

I wanted to create a simple ALT+S shortcut in my app to jump to a TextBox in my Windows Store App (no this is not the Win+Q search charm shortcut). However, this is not that obvious to get working app-wide, so I’ll share it here:

The obvious way to do this is assign a KeyDown event to your page using the typical “this.KeyDown += MyKeyDownHandler”, or override OnKeyDown. However this has one problem: If any control that has focus currently handles key down events (like TextBox), this event won’t be raised due to how event bubbling works. However there is another way to create an event handler that overrides the bubbling: UIElement.AddHandler. In the 3rd parameter of that, you can specify that you want to be notified even if the event has been handled. Here’s what that looks like for listening to the event app-wide:

Window.Current.Content.AddHandler(UIElement.KeyDownEvent, new KeyEventHandler(App_KeyDown), true);
//...
private void App_KeyDown(object sender, KeyRoutedEventArgs e)
{
     //Handle Key Down
}

If you attach to Window.Current.Content, be sure to detach again in OnNavigatingFrom, or you’ll risk having a memory leak, and also still get events firing in that page when it’s not loaded any longer. If you just want this within the page, use myPage.AddHandler of Window.Current.Content.AddHandler, but beware that if anything outside this page has focus the event won’t be raised. – at least in that case you don’t need to worry about unhooking again though.

Now second is to handle the key combination. You can check the menu/alt key status using the following line of code:

bool isMenuKeyDown = CoreWindow.GetForCurrentThread().GetAsyncKeyState(VirtualKey.Menu) == CoreVirtualKeyStates.Down;

So the obvious handler code would look like this:

private void App_KeyDown(object sender, KeyRoutedEventArgs e)
{
    if (e.Key == Windows.System.VirtualKey.S)
    {
        if(CoreWindow.GetForCurrentThread().GetAsyncKeyState(VirtualKey.Menu) == CoreVirtualKeyStates.Down)
        {
            //Handle key combination… 
} } }

Turns out the above code only works every other time. When reading the documentation on GetAsyncKeyState it states that “Determines whether a key is up or down at the time the function is called, and whether the key was pressed after a previous call to GetAsyncKeyState.

So basically this method changes its result based on whether it was called before, and not solely whether the key is down or not. This makes no sense to me why it was designed like this (but do feel free to explain in the comments if you know).

Anyway, if we just make sure this method is always called in the handler it now starts working predictably. So here’s my snippet that ckecks if ALT+S is pressed, sets focus on my textbox and selects all the text:

private void App_KeyDown(object sender, KeyRoutedEventArgs e)
{
    bool isMenuKey = CoreWindow.GetForCurrentThread().GetAsyncKeyState(Windows.System.VirtualKey.Menu) == CoreVirtualKeyStates.Down;
    if (isMenuKey && e.Key == VirtualKey.S)
    {
        queryTextBox.Focus(FocusState.Keyboard);
        queryTextBox.SelectAll();
    }
}

Rotating Elements in XAML While Maintaining Proper Flow

I recently had to lay out some text vertically stacked on top of each other in Windows 8, similar to how tabs in Visual Studio are laid out.

image

The obvious way to do that would be to first place the texts in a stack panel, and then rotate them like so:

<StackPanel>
    <TextBlock Text="Text 1">
        <TextBlock.RenderTransform>
            <RotateTransform Angle="90" />
        </TextBlock.RenderTransform>
    </TextBlock>
    <TextBlock Text="Text 2">
        <TextBlock.RenderTransform>
            <RotateTransform Angle="90" />
        </TextBlock.RenderTransform>
    </TextBlock>
    <TextBlock Text="Text 3">
        <TextBlock.RenderTransform>
            <RotateTransform Angle="90" />
        </TextBlock.RenderTransform>
    </TextBlock>
</StackPanel>

This is what it looks like without the RotateTransform:

image

And after adding rotation:

image

Notice how the text is now outside the containing StackPanel, and overlapping each other? So what happened? The problem is that RenderTransform is applied AFTER the layout cycle occurs so StackPanel has no way of placing these elements, since it already did it’s job prior to rotating the text. We’ll get back to how to resolve this, but let’s first cover the layout cycle, which consists of two steps: Measure and Arrange.

In the Measure step, each TextBlock is measured. This is basically the step where the parent control – in this case the StackPanel – tells each TextBlock “If you have [x,y] space, how much of that would you like to have?”. It does this by calling TextBlock.Measure(Size) on each of them. The TextBlock then reports back the size it would like to have using the .DesiredSize property. You will notice that controls’ DesiredSize property will always return (0,0) until the Measure step has run. Usually for TextBlocks it would report back the size of the text. If the text doesn’t fit within the width that the StackPanel provided and TextWrapping was enabled on the TextBlock, the TextBlock might choose to break the text and report a taller height instead, so it can keep inside the width it was provided with.

The next step is the Arrange step. This occurs after all children has been measured, and the StackPanel here decides how much space it will provide to each control. While the TextBlocks provided a certain DesiredSize, they might not actually get that much space – that’s all up to the parent control – for instance for a Grid’s columns and rows with auto and * sizes, the measure step helped it determine how much space each row and column will be, and then applies that to each element during arrange. Arrange is done by calling .Arrange(Rect) on each element, providing them with a rectangle to place itself within.

So back to our problem: How can we use this knowledge to get the layout cycle to proper place my rotated textblocks?

Well first of all, when we rotate an element 90 degrees, the width of the text becomes the height, and vice-versa. So if we were to “swap” the width and height during Arrange, we should be able to prevent the overlapping and ensure that there’s enough width, errr height for each TextBlock so they don’t overlap. During the arrange step, we can ensure that the elements gets placed right and doesn’t end up outside the containing control.

To do that, the first thing we’ll do is create a new control. Add a new TemplatedControl to your project:

image

A new class inheriting from Control will be created, as well as a new \Themes\Generic.xaml template (if you already have a Generic.xaml file, the following will be added):

Let’s get rid of the Border in this template, and add a simple ContentControl instead:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:RotateSample">

    <Style TargetType="local:RotateContentControl">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:RotateContentControl">
                    <Border
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                    </Border>
<ContentControl x:Name="Content" Content="{TemplateBinding Content}" />
</ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>

Next let’s add a Content dependency property to our class so that we can bind to the content. We’ll also add a Content property to the class, to signify that anything that is used as content inside this control in XAML is meant to be assigned to the Content property. Our control now looks like this:

[Windows.UI.Xaml.Markup.ContentProperty(Name="Content")]
public sealed class RotateContentControl : Control
{
    public RotateContentControl()
    {
        this.DefaultStyleKey = typeof(RotateContentControl);
    }

    public object Content
    {
        get { return (object)GetValue(ContentProperty); }
        set { SetValue(ContentProperty, value); }
    }

    public static readonly DependencyProperty ContentProperty =
        DependencyProperty.Register("Content", typeof(object), typeof(RotateContentControl), null);      
}

Now if we were to run the app using this control, it’ll basically be the same as using a ContentControl.

<local:RotateContentControl>
    <TextBlock Text="Text 1" FontSize="32" Margin="5" />
</local:RotateContentControl>

Of course this is not much fun, so let’s first use the OnApplyTemplate to grab the content and apply the rotation to the content:

private ContentControl m_Content;
private const double rotation = 90;
protected override void OnApplyTemplate()
{
    m_Content = GetTemplateChild("Content") as ContentControl;
    if (m_Content != null)
    {
        m_Content.RenderTransform = new RotateTransform() { Angle = rotation };
    }
    base.OnApplyTemplate();
}

If you run the sample now, we’ll basically be back to where we started with the texts offset and placed outside the parent container. You can see that the StackPanel is highlighted below with the size it thinks it needs to be to hold the TextBlocks, which doesn’t match the actual size of the TextBlocks:

image

So let’s first override the Measure step and swap width and heights:

protected override Windows.Foundation.Size MeasureOverride(Windows.Foundation.Size availableSize)
{
    if (m_Content != null)
    {
        m_Content.Measure(new Size(availableSize.Height, availableSize.Width));
        return new Size(m_Content.DesiredSize.Height, m_Content.DesiredSize.Width);
    }
    else
        return base.MeasureOverride(availableSize);
}

You’ll now see the following happen – notice how the height and width is now correct for the StackPanel if the TextBlocks were rendered in the right place, but we start seeing clipping on the TextBlocks:

image

This happens because the ArrangeStep still uses the unswapped width/height and causes clipping. Let’s next override the Arrange and swap width and height here as well:

protected override Size ArrangeOverride(Size finalSize)
{
    if (m_Content != null)
    {
        m_Content.Arrange(new Rect(new Point(0, 0), 
new Size(finalSize.Height, finalSize.Width))); return finalSize; } else return base.ArrangeOverride(finalSize); }

And the result we get is:

image

Now the text are not overlapping any longer nor are they clipped, but we still get them placed outside the parent StackPanel. This is because the rotation happens around the upper left corner and pushes the text out, as illustrated here:

image

Luckily the fix is easy because the Arrange step allows us to specify where to place the element as well. We basically have to move the TextBlock over to the left by the height of the text, so instead of specifying (0,0) for the rectangle corner, we use (width,0), so our Arrange looks like this:

protected override Size ArrangeOverride(Size finalSize)
{
    if (m_Content != null)
    {
        m_Content.Arrange(new Rect(new Point(finalSize.Width, 0), new Size(finalSize.Height, finalSize.Width)));
        return finalSize;
    }
    else
        return base.ArrangeOverride(finalSize);
}

And our controls now flows correctly within the StackPanel:

image

It also plays nice with other controls and respects alignments:

image

If you want to rotate the content –90 degrees, the offset in arrange changes slightly to:

m_Content.Arrange(new Rect(new Point(0, finalSize.Height), 
new Size(finalSize.Height, finalSize.Width)));

We could make this a property on our control, so you can easily change direction on the fly. We’ll add a new Direction enumeration and a DependencyProperty that triggers Arrange when it changes:

public RotateDirection Direction
{
    get { return (RotateDirection)GetValue(DirectionProperty); }
    set { SetValue(DirectionProperty, value); }
}

public static readonly DependencyProperty DirectionProperty =
    DependencyProperty.Register("Direction", typeof(RotateDirection),
typeof(RotateContentControl), new PropertyMetadata(RotateDirection.Down, OnDirectionPropertyChanged)); public static void OnDirectionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as RotateContentControl).InvalidateArrange(); //Trigger reflow }

We’ll also use remove the RenderTransform setting from OnApplyTemplate, and instead set it in ArrangeOverride, so that now looks like this:

protected override Size ArrangeOverride(Size finalSize)
{
    if (m_Content != null)
    {
        m_Content.RenderTransform = new RotateTransform() { Angle = (int)this.Direction };
        if (Direction == RotateDirection.Down)
            m_Content.Arrange(new Rect(new Point(finalSize.Width, 0), 
new Size(finalSize.Height, finalSize.Width))); else if (Direction == RotateDirection.Up) m_Content.Arrange(new Rect(new Point(0, finalSize.Height),
new Size(finalSize.Height, finalSize.Width))); return finalSize; } else return base.ArrangeOverride(finalSize); }

So here’s what that looks like in the designer:

image

That’s it! Below is the entire source code including support for 0 and 180 degree rotations as well:

using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;

namespace RotateSample
{
    [Windows.UI.Xaml.Markup.ContentProperty(Name="Content")]
    public sealed class RotateContentControl : Control
    {
        private ContentControl m_Content;

        public RotateContentControl()
        {
            this.DefaultStyleKey = typeof(RotateContentControl);
        }

        protected override void OnApplyTemplate()
        {
            m_Content = GetTemplateChild("Content") as ContentControl;
            base.OnApplyTemplate();
        }

        protected override Windows.Foundation.Size MeasureOverride(Windows.Foundation.Size availableSize)
        {
            if (m_Content != null)
            {
                if (((int)Direction) % 180 == 90)
                {
                    m_Content.Measure(new Windows.Foundation.Size(availableSize.Height, availableSize.Width));
                    return new Size(m_Content.DesiredSize.Height, m_Content.DesiredSize.Width);
                }
                else
                {
                    m_Content.Measure(availableSize);
                    return m_Content.DesiredSize;
                }
            }
            else
                return base.MeasureOverride(availableSize);
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            if (m_Content != null)
            {
                m_Content.RenderTransform = new RotateTransform() { Angle = (int)this.Direction };
                if (Direction == RotateDirection.Up)
                    m_Content.Arrange(new Rect(new Point(0, finalSize.Height),
                                      new Size(finalSize.Height, finalSize.Width)));
                else if (Direction == RotateDirection.Down)
                    m_Content.Arrange(new Rect(new Point(finalSize.Width, 0), 
                                      new Size(finalSize.Height, finalSize.Width)));
                else if (Direction == RotateDirection.UpsideDown)
                    m_Content.Arrange(new Rect(new Point(finalSize.Width, finalSize.Height), finalSize));
                else
                    m_Content.Arrange(new Rect(new Point(), finalSize));
                return finalSize;
            }
            else
                return base.ArrangeOverride(finalSize);
        }


        public object Content
        {
            get { return (object)GetValue(ContentProperty); }
            set { SetValue(ContentProperty, value); }
        }

        public static readonly DependencyProperty ContentProperty =
            DependencyProperty.Register("Content", typeof(object), typeof(RotateContentControl), null);

        public enum RotateDirection : int
        {
            Normal = 0,
            Down = 90,
            UpsideDown = 180,
            Up = 270
        }

        public RotateDirection Direction
        {
            get { return (RotateDirection)GetValue(DirectionProperty); }
            set { SetValue(DirectionProperty, value); }
        }

        public static readonly DependencyProperty DirectionProperty =
            DependencyProperty.Register("Direction", typeof(RotateDirection),
            typeof(RotateContentControl), new PropertyMetadata(RotateDirection.Down, OnDirectionPropertyChanged));

        public static void OnDirectionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if(((int)e.OldValue) % 180 == ((int)e.NewValue) % 180)
                (d as RotateContentControl).InvalidateArrange(); //flipping 180 degrees only changes flow not size
            else
                (d as RotateContentControl).InvalidateMeasure(); //flipping 90 or 270 degrees changes size too, so remeasure
        }
    }
}

Note: While this article was written for Windows Store apps, these concepts apply directly to Silverlight, WPF and Windows Phone as well, albeit they already provide controls in the Toolkit (LayoutTransformer) to handle this.

Running a Storyboard as a Task

Sometimes you have some code that needs to run after a storyboard has completed. In my case I'm working on a little board game, and after each move (which I animate using a Storyboard), I need to figure out the next move, and either start a new play-animation or pass the turn to the other player.

Therefore I run in a loop until the turn is over. You can detect when a storyboard has finished when the "Completed" event triggers, but that makes for some recursive spaghetti code. It's much easier if I could just "await" the storyboard using a task. So I created the little extension method below that makes this possible. All you have to do to start and wait for the storyboard to finish is:

    await myStoryboard.BeginAsync();

Below is the little extension method (which also serves as a general example on how you turn an event-based class into an awaitable Task using the TaskCompletionSource):

using System;
using System.Threading.Tasks;
using Windows.UI.Xaml.Media.Animation;

namespace SharpGIS
{
    public static class StoryboardExtensions
    {
        public static Task BeginAsync(this Storyboard storyboard)
        {
            System.Threading.Tasks.TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
            if (storyboard == null)
                tcs.SetException(new ArgumentNullException());
            else
            {
                EventHandler<object> onComplete = null;
                onComplete = (s, e) => {
                    storyboard.Completed -= onComplete; 
                    tcs.SetResult(true); 
                };
                storyboard.Completed += onComplete;
                storyboard.Begin();
            }
            return tcs.Task;
        }
    }
}

Note: This code is written for WinRT. If you want to use this for Silverlight or WPF, just change ‘Eventhandler<object>’ to ‘EventHandler’.

Creating a DirectX XAML control using C++/CX

With Windows 8 Metro style apps, you can now also build XAML controls not only with C# and VB.NET but also with C++. If you are a .NET developer you will probably wonder why you would do that – and granted there might be several reasons you wouldn’t. However there is a few nice things about C++ that .NET libraries doesn’t give you:
1. You can use existing C++ libraries and link them directly in. This will allow you to re-use an enormous amount of code already out there.
2. DirectX is a first-class citizen in C++ 11, and officially the only way to use DirectX in XAML (although there are ways to access this from C#).

If you need high-performance rendering or 3D, DirectX is the way to go on the Windows Platform, and finally we can effortless mix DX and XAML (well at least compared to how it was in WPF). So this blogpost will show you how to build the base control you will need to make DirectX-in-XAML possible.

If you haven’t made any custom controls before, I urge you to read my earlier post on why they are so awesome and how they work: Why Custom Controls are underrated

So let’s open up Visual Studio 11, and go: New Project –> Visual C++ –> WinRT Component DLL

image

The project will create a new component class: WinRTComponent.cpp/.h. Delete these two files. We won’t need them. Instead, right-click project –> Add new item, and pick “Templated Control”.

image

This will add 3 new files, where the first two are:

MyDirectXControl.h:

#pragma once

#include "pch.h"

namespace MyControlsLibrary
{
    public ref class MyDirectXControl sealed : public Windows::UI::Xaml::Controls::Control
    {
    public:
        MyDirectXControl();
    };
}

MyDirectXControl.cpp:

#include "pch.h"
#include "MyDirectXControl.h"

using namespace MyControlsLibrary;

using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Documents;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Interop;
using namespace Windows::UI::Xaml::Media;

MyDirectXControl::MyDirectXControl()
{
    DefaultStyleKey = "MyControlsLibrary.MyDirectXControl";
}

Also notice the comment at the top of the header file. This is important, and tells you to go open “pch.h” and add the following line at the bottom:

#include "MyDirectXControl.h"

I ignored this comment (ie. my brain refused to notice it) for hours until a friendly soul pointed it out – kinda annoying but just do it and move along.

The third file is the “Generic.xaml” template file. This is where the XAML that should be applied to the control is defined (this is exactly the same as in C#/VB.NET). We will open this and add a couple of minor changes highlighted in yellow, and remove the line crossed out:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MyControlsLibrary">

    <Style TargetType="local:MyDirectXControl">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:MyDirectXControl">
                    <Border x:Name="DrawSurface"
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                        <TextBlock Text="My DirectX Control" 
                                   HorizontalAlignment="Center"
                                   VerticalAlignment="Center" />
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

We name the border so we can get a reference to it from code behind (which we will get back to later), and also add a little text in the center just for fun.

Next let’s try and use this control in a C# app. Right-click on your solution and select Add New Project. Pick a blank C# Metro style application.

image

Right-click the “references” in this new project and select “Add references” and select your other project under the “Solutions” tab:

image

Now open BlankPage.xaml and add the highlighted sections:

<Page
    x:Class="Application1.BlankPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Application1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:my="using:MyControlsLibrary"
    mc:Ignorable="d">

    <Grid Background="{StaticResource ApplicationPageBackgroundBrush}">
        
        <my:MyDirectXControl Background="Red" Width="400" Height="300" />
        
    </Grid>
</Page>

And you should see the control pop up in your designer (you won’t see the red color yet – I left it so you can better see it in this screenshot):

image

Awesome! We now got a XAML control built in C++ consumed by C#!
Now let’s continue and add some DirectX magic to this control…

The first step for this is to include the DirectX libraries. If you are a .net developer, it’s kinda like adding assembly references (but the experience will feel 1980s :-). Right-click your C++ project and select Properties. Navigate to Linker->Input, and add the following to “Additional Dependencies”: d2d1.lib;d3d11.lib;

image

Next, lets add some methods, overrides and private variables to MyDirectXControl.h file that we’ll be using for the our directx rendering:

#pragma once
#include <d3d11_1.h>
#include <dxgi1_2.h>
#include <wrl.h>
#include <windows.ui.xaml.media.dxinterop.h>

#include "pch.h"

namespace MyControlsLibrary
{
    public ref class MyDirectXControl sealed : public Windows::UI::Xaml::Controls::Control
    {
    public:
        MyDirectXControl();
        virtual void OnApplyTemplate() override;
        void Refresh();

    private:
        Windows::UI::Xaml::Media::Imaging::SurfaceImageSource^ CreateImageSource(int width, int height);
        void OnMapSurfaceSizeChanged(Platform::Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e);
        void Draw(int width, int height);

        // template child that holds the UI Element
        Windows::UI::Xaml::Controls::Border^                m_MapSurfaceElement;
        // surface image source
        Windows::UI::Xaml::Media::Imaging::SurfaceImageSource^ m_imageSource;
        // Native interface of the surface image source
        Microsoft::WRL::ComPtr<ISurfaceImageSourceNative>   m_imageSourceNative;
        // D3D device
        Microsoft::WRL::ComPtr<ID3D11Device>                m_d3dDevice;
        Microsoft::WRL::ComPtr<ID3D11DeviceContext>         m_d3dContext;
Windows::Foundation::EventRegistrationToken m_sizeChangedToken; }; }

The first we’ll implement is the “CreateImageSource” method which will generate a DirectX surface we can render to. We’ll be using SurfaceImageSource which is one of the 3 types of DirectX surfaces we can use for this:

using namespace Windows::UI::Xaml::Media::Imaging;
[...]
SurfaceImageSource^ MyDirectXControl::CreateImageSource(int width, int height)
{
    //Define the size of the shared surface by passing the height and width to 
    //the SurfaceImageSource constructor. You can also indicate whether the surface
    //needs alpha (opacity) support.
    SurfaceImageSource^  surfaceImageSource = ref new SurfaceImageSource(width, height, true);
    if(width <= 0 || height <= 0) return surfaceImageSource;
    

    //Get a pointer to ISurfaceImageSourceNative. Cast the SurfaceImageSource object
    //as IInspectable (or IUnknown), and call QueryInterface on it to get the underlying
    //ISurfaceImageSourceNative implementation. You use the methods defined on this 
    //implementation to set the device and run the draw operations.
    IInspectable* sisInspectable = (IInspectable*) reinterpret_cast<IInspectable*>(surfaceImageSource);
    sisInspectable->QueryInterface(__uuidof(ISurfaceImageSourceNative), (void **)&m_imageSourceNative);

    //Set the DXGI device by first calling D3D11CreateDevice and then passing the device and 
    //context to ISurfaceImageSourceNative::SetDevice. 

    // This flag adds support for surfaces with a different color channel ordering than the API default.
    // It is recommended usage, and is required for compatibility with Direct2D.
    UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;

#if defined(_DEBUG)
    // If the project is in a debug build, enable debugging via SDK Layers with this flag.
    creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
     // This array defines the set of DirectX hardware feature levels this app will support.
    // Note the ordering should be preserved.
    D3D_FEATURE_LEVEL featureLevels[] = 
    {
        D3D_FEATURE_LEVEL_11_1,
        D3D_FEATURE_LEVEL_11_0,
        D3D_FEATURE_LEVEL_10_1,
        D3D_FEATURE_LEVEL_10_0,
        D3D_FEATURE_LEVEL_9_3,
        D3D_FEATURE_LEVEL_9_2,
        D3D_FEATURE_LEVEL_9_1
    };

    HRESULT hr = D3D11CreateDevice(
            NULL,
            D3D_DRIVER_TYPE_HARDWARE,
            NULL,
            creationFlags,
            featureLevels,
            ARRAYSIZE(featureLevels),
            D3D11_SDK_VERSION,
            &m_d3dDevice,
            NULL,
            &m_d3dContext
            );
if(FAILED(hr))
throw ref new COMException(hr); Microsoft::WRL::ComPtr<IDXGIDevice> dxgiDevice; // Obtain the underlying DXGI device of the Direct3D11.1 device. m_d3dDevice.As(&dxgiDevice); m_imageSourceNative->SetDevice(dxgiDevice.Get()); return surfaceImageSource; }

This is all boiler-plate code from MSDN. You can find more information there about what the above code really do.

The next portion is the code that will actually do the draw. I’ll keep it simple here and just grab the background color of the control, and render that color to the surface.

using namespace Microsoft::WRL;
[...]
void MyDirectXControl::Draw(int width, int height)
{
    if(width <= 0 ||  height <= 0) return;
    ComPtr<IDXGISurface> surface;
    RECT updateRect = {0};
    updateRect.left = 0;
    updateRect.right = width;
    updateRect.top = 0;
    updateRect.bottom = height;
    POINT offset = {0};
    
    //Provide a pointer to IDXGISurface object to ISurfaceImageSourceNative::BeginDraw, and 
    //draw into that surface using DirectX. Only the area specified for update in the 
    //updateRect parameter is drawn. 
    //
    //This method returns the point (x,y) offset of the updated target rectangle in the offset
    //parameter. You use this offset to determine where to draw into inside the IDXGISurface.
    HRESULT beginDrawHR = m_imageSourceNative->BeginDraw(updateRect, &surface, &offset);
    if (beginDrawHR == DXGI_ERROR_DEVICE_REMOVED || beginDrawHR == DXGI_ERROR_DEVICE_RESET)
    {
              // device changed
    }
    else
    {
        // draw to IDXGISurface (the surface paramater)
        // get D3D texture from surface returned by BeginDraw
        ComPtr<ID3D11Texture2D> d3DTexture;
        surface.As(&d3DTexture);
        // create render target view
        ComPtr<ID3D11RenderTargetView> m_renderTargetView;
        m_d3dDevice->CreateRenderTargetView(d3DTexture.Get(), nullptr, &m_renderTargetView);
        auto brush = (SolidColorBrush^)this->Background;
        float a = brush->Color.A/255.0f;
        float r = brush->Color.R/255.0f;
        float g = brush->Color.G/255.0f;
        float b = brush->Color.B/255.0f;
         const float clearColor[4] = { r, g, b, a };
         m_d3dContext->ClearRenderTargetView(m_renderTargetView.Get(),clearColor);
    }

    // TODO: Add more draw calls here

    //Call ISurfaceImageSourceNative::EndDraw to complete the bitmap. Pass this bitmap to an ImageBrush.
    m_imageSourceNative->EndDraw();
}

The next thing we’ll implement is “OnApplyTemplate”, which is called when the template in Generic.xaml is applied. At this point we can get a reference to the Border element, and apply the SurfaceImageSource as a brush to the background of the border.

void MyDirectXControl::OnApplyTemplate() 
{
if(m_MapSurfaceElement != nullptr)
    {   
        m_MapSurfaceElement->SizeChanged -= m_sizeChangedToken;
        m_MapSurfaceElement = nullptr;
    }
    //Get template child for draw surface
    m_MapSurfaceElement = (Border^)GetTemplateChild("DrawSurface");
    if(m_MapSurfaceElement != nullptr)
    {
        int width = (int)m_MapSurfaceElement->ActualWidth;
        int height = (int)m_MapSurfaceElement->ActualHeight;
        m_imageSource = CreateImageSource(width, height);
        ImageBrush^ brush = ref new ImageBrush();
        brush->ImageSource = m_imageSource;
        m_MapSurfaceElement->Background = brush;
        m_sizeChangedToken = m_MapSurfaceElement->SizeChanged += 
ref new SizeChangedEventHandler(this, &MyDirectXControl::OnMapSurfaceSizeChanged); } }

Also notice that we attached a handler to when the border element changes its size. If this happen we need to recreate the surface and render it again:

//surface size changed handler
void MyDirectXControl::OnMapSurfaceSizeChanged(Platform::Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e)
{
    int width = (int)m_MapSurfaceElement->ActualWidth;
    int height = (int)m_MapSurfaceElement->ActualHeight;
    m_imageSource = CreateImageSource(width, height);
    Draw(width, height);
    ImageBrush^ brush = ref new ImageBrush();
    brush->ImageSource = m_imageSource;
    m_MapSurfaceElement->Background = brush;
}

Lastly, we have a Refresh() method that triggers a new draw. You can call this on your control to trigger a new rendering. Calls to should be triggered by a pulse and only happen when there’s something new to draw (like for instance changing the background brush).

void MyDirectXControl::Refresh()
{
    int width = (int)m_MapSurfaceElement->ActualWidth;
    int height = (int)m_MapSurfaceElement->ActualHeight;
    Draw(width, height);
}

And that’s it! We now have a complete XAML control that you can use in both your .NET and C++ XAML apps.

You can download the entire sample app here.

Also a big thanks goes out to Jeremiah Morrill for peer-reviewing this blog-post.

TiltEffect for Windows 8 Metro XAML

The tiles on the new Windows 8 Start Menu “tilts” when you press them, tilting toward the direction you click/touch them. This effect is also well known from the Windows Phone tiles. Unfortunately there is no out-of-the-box way of accomplishing this in either of the platforms. However for Windows Phone, a TiltEffect class is in the Silverlight Toolkit, so I figured I could just port that. Turns out it wasn’t that hard – all I pretty much had to do was change the manipulation events to use the new Pointer events instead, and will work with both mouse and touch.

To use it, first download the updated tilt effect class and add it to your project.

Next add a xmlns to register the namespace for use in XAML:

     xmlns:sg="using:SharpGIS.Metro.Controls"

And lastly add the tilt effect to your control exactly like  you would on the phone:

    <Rectangle Width="200" Height="200" Fill="Blue"
        sg:TiltEffect.IsTiltEnabled="True" />

Here’s what this look like on a couple of animated panels:

It’s worth noting that the tilt effect is not EXACTLY the same as the Windows 8 start menu, but it’s fairly close (and a bit cooler if you ask me Smile)

Why Custom Controls are underrated

I’m a big fan of building controls. I love writing them, designing them, trying to make it work in as many scenarios I can while keeping them simple, extensible and most importantly reusable. In fact for the past 6 years, it’s all I’ve been doing full time (first ASP.NET and later XAML), and frequently in my spare time as well.

If you dabble in XAML, you have most likely already been building some controls, by going “File -> New -> User Control” in Visual Studio. You probably do this because you want to create a new page in your app, or you just want to encapsulate some of the UI in a separate section. Or perhaps it’s because you realize that this little tidbit can be used over and over again in your application. Or maybe you have even considered it can be used again and again across many DIFFERENT applications. If you have tried those two last categories (or if you will one day), this blog post is for you! It will apply to any of the XAML techs there is: WPF, Silverlight, Windows Phone and the future Windows 8 Runtime.

Despite the title in this blog post, User Controls are awesome. They are quick to throw together and reuse over and over - and there’s a lot of value in that. But what if I told you there’s another control type that has even MORE power, better performance, and can be way more flexible and reusable than a user control, and where the clean code will make most developers fall in love?

The thing is you already know this because you’ve been using them all the time: Button, ListBox, ItemsControls, Grid, StackPanel etc. are all controls harnessing the same power you can! And you have probably seen XAML styles that completely changed the look and feel of a control, without touching any of its code. To give you an idea of how powerful this is, look at this Silverlight Sample below. On the left you will see a ListBox binding to a list of planets. You have probably already done something like this. On the right, you see a solar system. But in fact this is ALSO a ListBox. And there is NO extra code involved here. It’s done entirely by restyling the template. Notice how selection and up/down keys work just like it does with the “normal” ListBox. So I got to reuse all the code that has this, and all I had to do was restyle the ListBox a bit. Something I could have done entirely in Blend without ever touching code.

Let me repeat that: I didn’t add any code to the ListBox do this. In fact the code behind for this page is completely empty. If you don’t believe me, here’s the source code. You can also see more about this technique in this presentation from Mix’08, or read David Ansons blogpost on it.

So at this point hopefully I have won you over to learning more about Custom Controls (if not I’m amazed you have read this far :-).

The Anatomy of A User Control

To start, let’s first look at the anatomy of a typical UserControl and try and fully understand how that works first. Below here we have the XAML portion of our control that defines the layout. We’ll keep it simple and have a Grid with a Button inside it:

<UserControl x:Class="MyApp.SilverlightControl1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
    <Grid x:Name="LayoutRoot" Background="White">
        <Button Content="Click Me" Click="Button_Click" Opacity=".5" />
    </Grid>
</UserControl>

And we have the code-behind that loads up the control, handles user interaction etc.

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace SolarSystemRetemplate
{
    public partial class SilverlightControl1 : UserControl
    {
        public SilverlightControl1()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            LayoutRoot.Background = new SolidColorBrush(Colors.Red);
        }
    }
}

The things worth noting here are two things: “LayoutRoot” is defined in the XAML using x:Name, and we automatically get a variable by that name in code behind. Also the event handler hooked to the Button’s Click event is magically linked to the code-behind. All this is really handled by the compiler and the “InitializeComponent” call - a method that interestingly doesn’t exist here. The reason this works is really because this is a partial class as indicated, and Visual Studio creates a little ‘secret’ file under the covers for you. You can get to if if you right-click the method and select “Go To Definition”. Here’s what the contents of that file looks like:

namespace MyApp {    
    
    public partial class SilverlightControl1 : System.Windows.Controls.UserControl {
        
        internal System.Windows.Controls.Grid LayoutRoot;
        
        private bool _contentLoaded;
        
        /// <summary>
        /// InitializeComponent
        /// </summary>
        [System.Diagnostics.DebuggerNonUserCodeAttribute()]
        public void InitializeComponent() {
            if (_contentLoaded)
                return;
            _contentLoaded = true;
            System.Windows.Application.LoadComponent(this, 
new System.Uri("/MyApp;component/SilverlightControl1.xaml",
System.UriKind.Relative)); this.LayoutRoot = ((System.Windows.Controls.Grid)(this.FindName("LayoutRoot"))); } } }

You’ll notice that the LayoutRoot is defined here as internal, and it’s assigned using the “FindName” method.

This is one of the nice things about UserControls: A lot of the work is automatically done for you, but with Custom Controls you will have to do this yourself! (but this isn’t so bad considering the power you get!). And here’s the kicker: A UserControl is just another custom control!

The Anatomy of A Custom Control

A custom control doesn’t have a XAML and a code-behind component in the same way UserControl does. Instead it’s ALL code along with a default XAML template. You can consider the template the equivalent of the XAML in the User Control, but the important part to remember here is that this template can be changed by ANYONE, which is what I did to the ListBox in the solar system sample. Another thing to note is that since the template doesn’t have a corresponding code-behind where Visual Studio generates a partial class for you, any event handlers cannot be defined in the template. So how do we go about recreating the user control above as a custom control?

For Silverlight this is easy. Right-click your project and select “File -> Add New -> Silverlight Templated Control”. WPF and Windows Phone doesn’t come with this template so you’ll have to do it manually there, by creating a class and a generic template file. After you do this, you’ll notice two new files: First a simple C# class, and second a new file in \Themes\Generic.xaml. The second file is where you place all templates for all your controls in that assembly. It HAS to have this name and live in this folder for the custom control to pick up the template.

Below is what this template looks like. I’ve added the grid and the button inside the suggested border that was created for me.

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MyApp">

    <Style TargetType="local:TemplatedControl1">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:TemplatedControl1">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <Grid x:Name="LayoutRoot">
                            <Button x:Name="ClickButton" Content="Click me!" Opacity=".5" />
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

First notice the TemplateBinding statements on the border. This is an important feature of controls. You can bind straight to a dependency property defined in your control code. Since a custom control inherits from “Control”, you automatically get Background, BorderBrush, BorderThickness and many other general properties from the inheritance. The great thing is that you can just write <my:TemplatedControl Border=”Red” /> and the border will automatically be bound into this template (and anywhere else where you have a TemplateBinding to that property). This beats UserControl, where to accomplish this in Silverlight you will have resolve to a hack by setting the DataContext of the control to itself, breaking the DataContext flow.

Second, notice that I didn’t add a click-handler to Button. If I did, this template would fail to load. We’ll hook the click handler up later.

Next let’s look at the code for the control:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;

namespace MyApp
{
    [TemplatePart(Name="LayoutRoot", Type=typeof(Control))]
    [TemplatePart(Name = "ClickButton", Type = typeof(ButtonBase))]
    public class TemplatedControl1 : Control
    {
        Control layoutRoot;
        ButtonBase button;
        public TemplatedControl1()
        {
            this.DefaultStyleKey = typeof(TemplatedControl1);
        }
        public override void OnApplyTemplate()
        {
            if (button != null) //unhook from previous template part
            {
                button.Click -= new RoutedEventHandler(button_Click);
            }    
            button = GetTemplateChild("ClickButton") as ButtonBase;
            if (button != null)
            {
                button.Click += new RoutedEventHandler(button_Click);
            }
            layoutRoot = GetTemplateChild("LayoutRoot") as Panel;
            base.OnApplyTemplate();
        }

        private void button_Click(object sender, RoutedEventArgs e)
        {
            layoutRoot.Background = new SolidColorBrush(Colors.Red);
        }
    }
}

First I declare the “TemplatePart” attributes on the control. They tell what parts (ie controls) are expected to be in my template. In this case LayoutRoot of type Panel (Grid is a Control), and ClickButton of type ButtonBase. These are not strictly required, but they help Expression Blend understand the template requirements when you later customize the control. I always declare the lowest needed type in the control hierarchy to make the template more flexible. For instance I use ButtonBase and not Button, because I only rely on the Click event which is declared on the ButtonBase base class. That way I don’t lock a user of the control into using “Button” but they can place ANY control that inherits from ButtonBase here. Same thing applies for the LayoutRoot, where I just need the Background property.

Next the control inherits from “Control”. Custom controls must inherit from this.

In the constructor I define the “DefaultStyleKey”. This tells the framework that I have a default template defined in Themes\Generic.xaml. If I didn’t the user would always have to explicitly defined a control template for the control.

Lastly, the most important part is “OnApplyTemplate”. This method is called when the control has loaded the template. This is our earliest opportunity to grab references to controls in the template, ie. the TemplateParts. In this case I grab a reference to the ButtonBase defined in the template. If it’s found, I’ll add a click handler to it. Also if a new template gets applied, I must remember to unhook from the previous instance (this is a rare scenario though, and you could probably get away with skipping that bit). It’s also important to note that Template Parts are always optional! So always do the null check anywhere you rely on a reference to a template part.

And that’s really it! I kept the sample simple, so it is easier to go through the individual parts of a control, therefore the differences between a custom control and a user control doesn’t really stand out. If this was all you needed to do, a custom control is probably overkill. But think of scenarios where you have a lot of code-behind that you want to reuse, but you don’t want to lock the design in. The major next parts you will want to add to this now is more Dependency Properties you can bind into the template, as well as VisualStates - ie. storyboards that triggers on certain events. The great thing about Visual States is that the code-behind doesn’t define the storyboard or what it does - only when it starts. This gives the user even more flexibility to customize the behavior.

Adding Visual States to the control

Let’s add some mouse over states to our control, and have the control animate when that happens. In the code-behind where we defined the TemplateParts let’s add two TemplateVisualState attributes:

[TemplateVisualState(GroupName = "HoverStates", Name = "MouseOver")]
[TemplateVisualState(GroupName = "HoverStates", Name = "Normal")]

Again these are optional, but great for Blend integration.

Next add the code that triggers the visual state to the control:

bool isMouseOver;
protected override void OnMouseEnter(System.Windows.Input.MouseEventArgs e)
{
    isMouseOver = true;
    ChangeVisualState(true);
    base.OnMouseEnter(e);
}
protected override void OnMouseLeave(System.Windows.Input.MouseEventArgs e)
{
    isMouseOver = false;
    ChangeVisualState(true);
    base.OnMouseLeave(e);
}

private void ChangeVisualState(bool useTransitions)
{
    if (isMouseOver)
    {
        GoToState(useTransitions, "MouseOver");
    }
    else
    {
        GoToState(useTransitions, "Normal");
    }
}

private bool GoToState(bool useTransitions, string stateName)
{
    return VisualStateManager.GoToState(this, stateName, useTransitions);
}

This is really all the code we need. It’s pretty simple. If the mouse is over, trigger the MouseOver state, else trigger the Normal state. Note how we don’t really define what “MouseOver” looks like. That’s the job of the template. Let’s define that (you might already be very familiar with this when overriding templates - it’s exactly the same thing, except we get to define the default state):

<ControlTemplate TargetType="local:TemplatedControl1">
    <Border Background="{TemplateBinding Background}"
            BorderBrush="{TemplateBinding BorderBrush}"
            BorderThickness="{TemplateBinding BorderThickness}">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="HoverStates">
                <VisualState x:Name="MouseOver">
                    <Storyboard>
                        <ColorAnimation
                            Storyboard.TargetName="BackgroundElement"
                            Storyboard.TargetProperty="(Rectangle.Fill).(SolidColorBrush.Color)"
                            To="Yellow" Duration="0:0:.5" />
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="Normal">
                    <Storyboard>
                        <ColorAnimation
                            Storyboard.TargetName="BackgroundElement"
                            Storyboard.TargetProperty="(Rectangle.Fill).(SolidColorBrush.Color)"
                            To="Transparent" Duration="0:0:.5" />
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <Grid x:Name="LayoutRoot">
            <Rectangle x:Name="BackgroundElement" Fill="Transparent" />
            <Button x:Name="ClickButton" 
                    Content="Click me!" Opacity=".5" />
        </Grid>
    </Border>
</ControlTemplate>

So the changes here is adding a rectangle in the background that we animate into yellow when the mouse hovers over.

You now have a control that sets a background on some Panel when some ButtonBase is clicked, as well as running an animation on MouseEnter/Leave. This could serve the purpose for quite a lot of controls, without you having to rewrite the code!

Here’s a few resources you will want to read if you want to learn more about this:

A couple of other controls I’ve built over the time and described on this blog:

If you want to go even more hardcore, wrap your head around the ArrangeOverride and MeasureOverride methods. This is where you can get some really amazing control over how the contents are laid out, but this is outside the scope of this article, but I urge you to read into it. Here’s one article to get your started on that: http://www.switchonthecode.com/tutorials/wpf-tutorial-creating-a-custom-panel-control

Building A Multi-Touch Photo Viewer Control

If you want to view an image on your Windows Phone app, or on your Windows 8 tablet, most people would probably expect to be able to use their fingers to pinch zoom and drag using the touch screen.

Since this is a common scenario, I want to create a simple reusable control that allows me to do this using very little xaml, along the lines of this:

<my:ImageViewer
    Thumbnail="http://url.com/to/my/thumbnail.jpg"
    Image="http://url.com/to/my/MyImage.jpg"  />

…where Thumbnail is a low resolution image that loads fast, while the full resolution Image is being downloaded.

If you just want to use this control and don’t want to learn how to create a custom control, skip to the bottom to download the source for both Windows Phone and Windows 8 Runtime.

First off, we’ll create a new Windows Phone Class Library project and name it “SharpGIS.Controls”. (or whatever you like)

image

Create a new folder “Themes”, add a new XAML resource file and name it “Generic.xaml”. Make sure the “build action” for this file is set to “ApplicationDefinition”.

We will want to define the default template in this file for our control (if you are used to making User Controls, this is essentially where the XAML for custom controls go instead).

In the xaml we will want two things: An image for displaying a fast-loading thumbnail at first, and a second image for displaying the high resolution image. Also we will use a Grid around them to group them together. Generic.xaml should look something like this:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:SharpGIS.Controls">
    <Style TargetType="local:ImageViewer">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:ImageViewer">
                    <Grid x:Name="Root" Background="Transparent">
                        <Image x:Name="Thumbnail" Source="{TemplateBinding Thumbnail}" CacheMode="BitmapCache" />
                        <Image x:Name="Image" Source="{TemplateBinding Image}" CacheMode="BitmapCache" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Notice the “CacheMode” property. This is important to set, to get proper performance when zooming and panning the image. If you have a Windows Phone try the official Facebook app, open an image and you will see what I mean (if you worked on that app PLEASE fix this).

Next up is the actual code. Add a new class, and name it “ImageViewer”. Make it inherit from ‘Control’. Add a constructor and use the “DefaultStyleKey” to tell Silverlight that you have a template defined in Generic.xaml that it should use.

public class ImageViewer : Control
{
    public ImageViewer()
    {
        DefaultStyleKey = typeof(ImageViewer);
    }
}

Next we define the dependency properties for the two images that the template was binding to:

public ImageSource Image
{
    get { return (ImageSource)GetValue(ImageProperty); }
    set { SetValue(ImageProperty, value); }
}

public static readonly DependencyProperty ImageProperty =
    DependencyProperty.Register("Image", typeof(ImageSource), typeof(ImageViewer), null);

public ImageSource Thumbnail
{
    get { return (ImageSource)GetValue(ThumbnailProperty); }
    set { SetValue(ThumbnailProperty, value); }
}

public static readonly DependencyProperty ThumbnailProperty =
    DependencyProperty.Register("Thumbnail", typeof(ImageSource), typeof(ImageViewer), null);

We should now be able to use this control in a Windows Phone project. Add a new Windows Phone Appplication project to your solution, right-click the ‘references’ and select “add reference’. Pick the SharpGIS.Controls project.

You should now be able to use some XAML like this to display an image:

<my:ImageViewer
    xmlns:my="clr-namespace:SharpGIS.Controls;assembly=SharpGIS.Controls"
    Thumbnail="http://url.com/to/my/thumbnail.jpg"
    Image="http://url.com/to/my/image.jpg" />

That’s all fine, but you still can’t use any touch to zoom the image.

Go back to the code and override OnApplyTemplate(). This code executes when the template from Themes\Generic.xaml has been loaded, and it’s your chance to grab any reference to the elements in there and ‘do something’ with them. In user controls you would often set the event handlers directly in the xaml. With templates on custom controls, you will have to hook these up in code-behind during OnApplyTemplate().

Here we will hook up for the manipulation events, as well as assign a transform we will apply to the element when these events trigger.

private Grid Root;
        
public override void OnApplyTemplate()
{
    Root = GetTemplateChild("Root") as Grid;
    if (Root != null)
    {
        Root.ManipulationDelta += Root_ManipulationDelta;
        Root.ManipulationStarted += Root_ManipulationStarted;
        Root.RenderTransform = new CompositeTransform();
    }
    base.OnApplyTemplate();
}

The ManipulationDelta event triggers as you move. It will give you information about how much the user dragged, and how much he/she pinches, as well as the center of the pinch. Unfortunately the pinch scale amount is shown as separate X and Y directions, and no ‘Uniform Scale’ is shown. This makes it hard to get a good average of the scale, and you would have to pick just one of them (one could be pinching and the other stretching).

I’ve found that defining the amount you’re scaling is the change of the length of the diagonal of the boundingbox of all the touch points works well. Errrrrrr, that might have sounded confusing. Let’s use a picture instead. The orange circles below are touchpoints, and the rectangle is the box that encompasses all of them (2 or more points). The blue line is the diagonal length of this box. So the amount of scaling = length_Before / length_After.

image

We don’t get the actual touch points in the manipulation events. So instead I start with a simple box that I define as 1x1 and track the scaling of it. The diagonal length of that box at the beginning is the square root of 2, which we will define in the ManipulationStarted event. We also add a property for tracking the center of the box.

private Point? lastOrigin;
private double lastUniformScale;

private void Root_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
{
    lastUniformScale = Math.Sqrt(2);
    lastOrigin = null;
}

So all that’s left is listen to the ManipulationDelta event, and update the transform on the grid. This consist of comparing previous origin to the new, as well as calculating the scale factor based on the box diagonal. Also note that when you apply scale, this is means you’re scaling out and away from the upper left corner. To offset this, you will need to add some additional translation to the image, as shown below:

private void Root_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
    var transform = Root.RenderTransform as CompositeTransform;
    if (transform != null)
    {
        var origin = e.ManipulationContainer.TransformToVisual(this).Transform(e.ManipulationOrigin);

        if (!lastOrigin.HasValue)
            lastOrigin = origin;

        //Calculate uniform scale factor
        double uniformScale = Math.Sqrt(Math.Pow(e.CumulativeManipulation.Scale.X, 2) + 
                                        Math.Pow(e.CumulativeManipulation.Scale.Y, 2));
        if (uniformScale == 0)
            uniformScale = lastUniformScale;

        //Current scale factor
        double scale = uniformScale / lastUniformScale;

        if (scale > 0 && scale != 1)
        {
            //Apply scaling
            transform.ScaleY = transform.ScaleX *= scale;
            //Update the offset caused by this scaling
            var ul = Root.TransformToVisual(this).Transform(new Point());
            transform.TranslateX = origin.X - (origin.X - ul.X) * scale;
            transform.TranslateY = origin.Y - (origin.Y - ul.Y) * scale;
        }
        //Apply translate caused by drag
        transform.TranslateX += (origin.X - lastOrigin.Value.X);
        transform.TranslateY += (origin.Y - lastOrigin.Value.Y);

        //Cache values for next time
        lastOrigin = origin;
        lastUniformScale = uniformScale;
    }
}

And that’s it!

Now what’s left is to turn off the thumbnail when the image has loaded, as well as raise loaded events for the high resolution image, so that you can display a progress bar while you wait for the image to load. I won’t go into details on this, but in OnApplyTemplate, simply grab the Image template child, and listen for the ImageLoaded event.

I’ve packaged it all up in one complete control, as well as a sample showing how this would be used in an application where you would navigate to a page with this control on it.

You can download the source and a sample app here.

Here’s a preview off what that app looks like: