Shortcut Key Handling in Windows Store Apps

by Morten 21. October 2012 14:19

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();
    }
}

Tags:

Windows Runtime | XAML

Using User-Provided Images for Secondary Tiles

by Morten 8. October 2012 21:51

Often when you are creating a secondary tile in Windows 8, it will be based on images coming from the internet.  However a requirement of secondary tile images are that they need to be stored locally. I initially had some problems getting this working right and the streams closed correctly for this to work, so here’s the code for other to use and save the hazzle:

public async static Task CreateSecondaryTileFromWebImage(
    string tileId, Uri imageUri, string shortName, string displayName,
    string arguments, Rect selection)
{
    //Download image to LocalFolder and use the tileId as the identifier
    string filename = string.Format("{0}.png", tileId);
    HttpClient httpClient = new HttpClient();
    var response = await httpClient.GetAsync(imageUri);
    var imageFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);
    using (var fs = await imageFile.OpenAsync(FileAccessMode.ReadWrite))
    {
        using (var outStream = fs.GetOutputStreamAt(0))
        {
            DataWriter writer = new DataWriter(outStream);
            writer.WriteBytes(await response.Content.ReadAsByteArrayAsync());
            await writer.StoreAsync();
            writer.DetachStream();
            await outStream.FlushAsync();
        }
    }
    //Create tile
    Uri image = new Uri(string.Format("ms-appdata:///local/{0}", filename));
    SecondaryTile secondaryTile = new SecondaryTile(tileId, shortName, displayName, arguments, TileOptions.ShowNameOnLogo, image);
    secondaryTile.ForegroundText = ForegroundText.Light;
    await secondaryTile.RequestCreateForSelectionAsync(selection, Windows.UI.Popups.Placement.Above);
}

Often this is enough, but there is still a small problem. What if the image is very light, and the text you display on top of it is white, thus drowning in the background image? You could set the tile text to black, but then what happens if the image is dark? And if it has a lot of texture in it, the text still gets very unreadable. Since you might not know up front what the image looks like, whether it’s dark or bright, or textures, we will need a way to ensure the text will still look good on top of the image.

image

Unfortunately full WriteableBitmap support in WinRT isn’t there to help us out modifying the image, but we do get low-level access to the pixel buffer of the image, so we could fairly simple darken or brighten the bottom a bit to ensure the image looks good as a backdrop for the text.

I wrote a little utility that loads the image, gradually darkens the bottom 40% of the image before saving it back. I’ve found that doing a slight graduated darkening on photos isn’t too noticeably, while making the text in front of it much more readable. So with out further ado, here’s my simple image pixelbuffer modifier:

private async static Task DarkenImageBottom(string filename, string outfilename)
{
    var file = await ApplicationData.Current.LocalFolder.GetFileAsync(filename);
    BitmapDecoder decoder = null;
    byte[] sourcePixels = null;
    using (IRandomAccessStream fileStream = await file.OpenReadAsync())
    {
        decoder = await BitmapDecoder.CreateAsync(fileStream);
        // Scale image to appropriate size 
        BitmapTransform transform = new BitmapTransform();
        PixelDataProvider pixelData = await decoder.GetPixelDataAsync(
            BitmapPixelFormat.Bgra8,
            BitmapAlphaMode.Straight,
            transform,
            ExifOrientationMode.IgnoreExifOrientation, // This sample ignores Exif orientation 
            ColorManagementMode.DoNotColorManage
        );
        // An array containing the decoded image data, which could be modified before being displayed 
        sourcePixels = pixelData.DetachPixelData();
        fileStream.Dispose();
    }
    if (decoder != null && sourcePixels != null)
    {
        for (uint col = 0; col < decoder.PixelWidth; col++)
        {
            for (uint row = (uint)(decoder.PixelHeight * .6); row < decoder.PixelHeight; row++)
            {
                uint idx = (row * decoder.PixelWidth + col) * 4;
                if (decoder.BitmapPixelFormat == BitmapPixelFormat.Bgra8 ||
                    decoder.BitmapPixelFormat == BitmapPixelFormat.Rgba8)
                {
                    var frac = 1 - Math.Sin(((row / (double)decoder.PixelHeight) - .6) * (1 / .4));
                    byte b = sourcePixels[idx];
                    byte g = sourcePixels[idx + 1];
                    byte r = sourcePixels[idx + 2];
                    sourcePixels[idx] = (byte)(b * frac);
                    sourcePixels[idx + 1] = (byte)(g * frac);
                    sourcePixels[idx + 2] = (byte)(r * frac);
                }
            }
        }

        var file2 = await ApplicationData.Current.LocalFolder.CreateFileAsync(outfilename, CreationCollisionOption.ReplaceExisting);

        var str = await file2.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite);
        BitmapEncoder enc = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, str);
        enc.SetPixelData(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, decoder.PixelWidth, decoder.PixelHeight,
            decoder.DpiX, decoder.DpiY, sourcePixels);
        await enc.FlushAsync();
        str.Dispose();
    }
}

So we can call this utility prior to creating the secondary tile request. Compare the before(left) and after (right) here:

imageimage

The image difference is barely noticeable, but the text is much more readable.

You can download the tile utility class and sample app here.

Tags:

Windows Runtime

Rotating Elements in XAML While Maintaining Proper Flow

by Morten 3. October 2012 09:07

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.

Tags:

XAML | Windows Runtime

Linking to Your Windows Store App

by Morten 11. September 2012 08:07

I just got my first app published in the Windows Store, and I wanted to create a direct link from the game homepage to the entry in the Windows Store. For this you can use the ms-windows-store protocol on your links, as described on msdn. To set it up, the first thing you’ll need to do is open up your project in Visual Studio, then open the Package.appxmanifest file. If your app has been associated with the Windows Store (this will happen the first time you create the publication package), the “Package family name” field should be populated under the “Packaging��� tab:

image

Copy this package family name, and prefix it to “ms-windows-store:PDP?PFN=”

Example: ms-windows-store:PDP?PFN=57398MortenNielsen.Bao_9qs9wzj9xadrg

This should open my game up directly in the Windows Store App if you are on Windows 8 (and while you’re at it, please download it and throw it a good review – it’s free and goes for a good cause :-).

You can also link directly to the review page by adding REVIEW to the prefix.

Example: ms-windows-store:REVIEW?PFN=57398MortenNielsen.Bao_9qs9wzj9xadrg (and please leave a good review while you’re at it :-)

It’s also possible to link to a website that shows the same overview. This is nice if the user doesn’t have Windows 8 and you just want to tease them, or you prefer showing a webpage first in any case. However you won’t be able to get this link until the app has been published. Sign in to the App Store Developer Portal, click the “Details” link for your app listing, and scroll down. You’ll find a link under “Link to [APPNAME]",

image

Here’s the link as an example what the Windows Store Webpage looks like: http://apps.microsoft.com/webpdp/en-US/app/bao/dbe2f3a7-2deb-40d5-9a69-2995f14d6706
(and if you didn’t download the app yet, here’s your second chance :-)

You can also integrate your application into the IE10 Metro browser. Here’s what that looks like prior to installing the app:

image

And after install:

image

This would be a great experience if you offer both a website and a app version as well, allowing the user to quickly switch from one to the other. IE10 passes the url to your app so you can jump to a specific feature in your app, or you can add a third metatag with the arguments. You can read more about this feature here. Again you can try this experience at http://bao.win-rt.com (and this’ll be your 3rd chance to download my app :-).

Here’s the metatag you’ll need to add to the header:

<meta name="msApplication-ID" content="App"/>
<meta name="msApplication-PackageFamilyName" content="57398MortenNielsen.Bao_9qs9wzj9xadrg"/>.

The PackageFamilyName is the same, but the Application-ID you get by opening up the package.appmanifest in a text editor. Under the <Application> tag you’ll find the ID:

    <Applications>
        <Application Id="App" Executable="$target…

References:

Tags:

Windows Runtime

The Windows Store Submission Process

by Morten 8. September 2012 18:25

I recently got access to the Windows Store, and submitted my first app, “The game of Bao”, a simple and fun board game I learned when we visited Malawi, Africa during our honeymoon (any money the game makes will be donated back to an organization working on improving the lives of the kids that taught us this game, so please be kind and play it a lot and give some great reviews :-).

I recorded the steps that I have had to go through so you can see what you need to have ready if you need to submit an app yourself.

*Note: Currently access to the Windows Store is limited to either companies and people who goes through an “App Excellence Lab”. Once your app gets the “seal of approval” from a Microsoft Engineer, you’ll get an invite code so you can create an account for the Windows Store.

When you sign into the windows store, the first thing you’re greeted with is the dashboard, where you can submit an app.

image

Clicking “Submit an app” brings you to a list of the steps you have to go through. You work your way through them from top to bottom (you can always go back and change stuff as long as you haven’t submitted yet):

image

First step is to give you application a name. This is a unique name, so if someone else already published an app with that name, you’ll have to come up with a different name. Also note the mention that your app’s manifest must have the exact same DisplayName set. You can also reserve your app name this way, and later finish the app submission process when your app is ready.image

The next step is the selling details. There’s quite a lot to fill out here, but still pretty straightforward:

image

The next page allows you to configure in-app purchase (you can add as many as you want, ranging from $1.49 up to $999.99):

image

The next step is the age rating. Make sure you read the “small” print. If your app has access to the internet, chances are you can’t go with the lowest rating, no matter how PG your app is. Also note that for some countries a rating certificate is required to be able to publish there (I have no clue how to get these though):

image

Next step is declaring whether your app uses any form of cryptography (there’s a lot of export restrictions on that technology). You either say yes or no. If you pick yes, you’ll be asked a few more questions about this:

image

Next step is to upload your app package. In Visual Studio, select “Project –> Store –> Create App Packages…”

image

Pick for Windows Store.

image

You’ll then be asked to sign in. It’ll find the app name you reserved in the first step and then generate the .appxupload package that you’ll need in the next step:

image

Next is the app description. You’ll need 1-8 screenshots (1366x768), Promotional Images (846x468,558x756,414x468,414x80) keywords, app features, Description, web-link to Privacy Policy (if you have internet-enabled your app), description of all in-app purchace options to name a few.

image

Last step is to optionally include some notes to the testers:

image

When you’re done, you should be back at the overview page with all check-marks:

image

Either review your data, or hit “Submit for certification”. All you can do now is sit back and wait for the app to go through. There’s an estimate listed of how long each step usually takes.

image

Tags:

Windows Runtime

Running a Storyboard as a Task

by Morten 5. September 2012 18:08

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’.

Tags:

Windows Phone | WPF | Windows Runtime | Silverlight | XAML

Code snippet for reading files in a Windows Store App

by Morten 1. September 2012 10:58

Here’s a little useful code snippet for opening up a file stream from either you local data store, or from the application folder in a Windows Store/WinRT/Metro/[insert name of the day] app:

using System;
using System.IO;
using System.Threading.Tasks;
using Windows.Storage;
using Windows.Storage.Streams;
using System.Runtime.InteropServices.WindowsRuntime;
//[...]
public static async Task<Stream> ReadFile(string filename)
{
    StorageFolder folder = null;
    if (filename.StartsWith("ms-appx:///"))
    {
        filename = filename.Substring(11);
        folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
    }
    else
    {
        folder = Windows.Storage.ApplicationData.Current.LocalFolder;
    }
    while (filename.Contains("/"))
    {
        var foldername = filename.Substring(0, filename.IndexOf('/'));
        filename = filename.Substring(foldername.Length + 1);
        folder = await folder.GetFolderAsync(foldername).AsTask().ConfigureAwait(false);
    }
    var file = await folder.GetFileAsync(filename);
    IInputStream stream = await file.OpenReadAsync();
    DataReader reader = new DataReader(stream);
    return await file.OpenStreamForReadAsync();
}

This allows you to get access to a stream from your application. Ie. if you have a file called “About.txt” in your project inside the folder “Assets” (remember to set build action to ‘content’), you would access it like this:

using (var stream = await ReadFile("ms-appx:///Assets/About.txt"))
{
    //TODO
}

Note that the ms-appx:/// is the standard prefix for a uri to files within the application folder. If you want to get access to a file in your app data folder, just leave this off.

Tags:

Windows Runtime

Creating a DirectX XAML control using C++/CX

by Morten 26. April 2012 20:02

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.

Tags: , , ,

XAML | Windows Runtime

My API Design Mantras

by Morten 19. April 2012 10:35

This morning I read an interesting article by Charlie Kindel: “Don’t build API’s”. He talks about some of the issues with customers using your API in ways that you never thought they would be using it, and how you forever are stuck with supporting these ‘almost unsupported’ use-cases. I wouldn’t go as far as saying you shouldn’t be building an API at all. After all if your product is an SDK, this is what you would have to do Smile.

I love working on API design and have been fortunate enough to be able to do this for several years now on a daily basis. I’ve gotten caught by similar issues that Kindel experienced as well. So over time, I have built myself a couple of mantras when I work on an API, and it generally is about how ‘tight’ or ‘loose’ you design your API. A very tight API has very few public methods and extensibility points, where a very loose API exposes everything and allows everything to be extended. My mantras are:

Unless there’s a solid and strong use-case for it:

    • …don’t make any methods, events or properties public.
    • …don’t allow people to create instances of a class (keep your constructor internal or private).
    • …seal your classes to prevent inheritance.

In other words: ‘private’ and ‘sealed’ are the keywords I think of first, next ‘internal’, next ‘protected’ (if class isn’t sealed), and lastly (after a lot of thought) ‘public’. ‘virtual’ comes even later. An example of this could be an event argument for an event that only your control will be raising. There’s rarely a reason to create a public constructor1. The class won’t be inherited from, so mark it sealed. Lastly the properties rarely will have any public setters either (the common use-case there is the .Handled property you can set to prevent bubbling). A great side-effect of tightening your API is that your API is smaller, leaner and meaner. The user of your API won’t have to browse a gazillion members to find the method he needs to use. It’ll be easier for him to understand your API, hit the things he’s supposed to hit, and stay out of the parts that could shoot himself in the foot.

I’m not saying you shouldn’t make anything public (it wouldn’t be an API if you didn’t). What I’m saying is that there needs to be a great and well-understood use-case for each and every one. As Kindel points out, you have to be VERY aware that any public method WILL be used in a way you didn’t think of. And the moment you made it public, you will have to support it forever.

So what I’m saying is that if I can’t think of a solid real-world use-case, making something publicly accessible wouldn’t be my first choice. You can always come up with random use-cases, but are they real-world scenarios? Are they best practices? Would the be a better way to achieve a certain use-case? If you can’t think of any, I would recommend keeping it tight, until that use-case shows up and you can get to understand it. Unless it saves a lot of customers a lot of time (which is essentially the purpose of an API), “Nice-to-have” features are unimportant. Focus on the “must-haves” first.

Any private and internal code you have is used in a finite set of use-cases2. You know the code that calls these methods, and they are in your full control. If a customer comes to you and wants access to these parts of the code, I generally first:

  1. Try to fully understand what the user is trying to achieve. Is there a better way / best practice? Is he really just trying to work around a feature that’s missing from your API, and if so would it be better to provide that instead of opening up an internal API? (generally internal methods are merely a set of helper/utility methods that helps supporting the public API). This is why it’s so important to fully understand the use-case.
  2. If you loosen existing internal parts your API, remember that so far this part of your code has only been used by you. When it was designed it might not have gone through the thought process that it requires for being used for any number of unknown use-cases. Using it wrong could very likely destabilize your code. Perhaps your code wasn’t originally designed for this type of use at all (we of course try, but everyone cuts corners now and then, or avoids unnecessary checks for performance reasons). Also do you need to do some MAJOR refactoring first? Is it worth the risk and is the demand large enough? Ie if there’s a huge risk and small demand, is there a workaround the customer can use as an alternative?

Let me say it again: You will have to support your public API forever! No more refactoring. No more major reworking to increase performance. No more major code cleanup. What you just did is now forever.

--------------------------------------------------------------------------------

1 In some unit-testing scenarios being able to create types are useful (luckily .NET lets you do this through reflection, and Visual Studio’s test suite helps you do it). Generally though you should be unit-testing your code, and your customer should just be testing their code.

2 Your internal API is also important - Keep things private unless ‘internal’ is really warranted, and try and make sure it can’t be misused - again as software evolves, your internal use might change and you will use your software in ways you didn’t originally think of - but at least here you’re not tied by ‘forever’ supporting it.

Tags:

TiltEffect for Windows 8 Metro XAML

by Morten 2. March 2012 19:17

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)

Tags:

Windows Runtime | XAML

About the author

Morten Nielsen

Silverlight MVP

Morten Nielsen
<--That's me
E-mail me Send mail

Twitter @dotMorten 

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2005-2014

Month List

Recent Comments

Comment RSS