0 Comments
  •   Posted in: 
  • UWP

The regional settings still misbehave in Windows 8.1 XAML apps. They misbehaved already in Windows 8 and they continue to misbehave in apps written with a newer WinRT. Some may say that they work as designed. To them I say the design is wrong.

The previous post about this subject contains more info, but here’s a short introduction to the problem.

Scenario:A Finnish users starts my Windows 8 XAML app. The app displays dates and times. The app isn’t localized to any language. I want the app to show the dates and times in Finnish format as that’s how she has configured her regional settings:

The problem:The app doesn’t respect her settings. Instead, all the dates and times are formatted using the US settings:

Capture

Other frameworks: Windows Forms, Console Applications, WPF, Silverlight and ASP.NET all handle this correctly: Dates and times are formatted using the regional settings:

image

The workaround: It’s possible to get the dates and times formatted correctly in WinRT apps. It’s just requires a lot of code. I call this a workaround until the WinRT XAML apps start behaving as they should:

            var usersLanguage = Windows.Globalization.Language.CurrentInputMethodLanguageTag;

            var dateFormatter = new DateTimeFormatter("shortdate", new[] { usersLanguage }).Patterns[0];
            var timeFormatter = new DateTimeFormatter("shorttime", new[] { usersLanguage }).Patterns[0];
            var fullFormatter = new DateTimeFormatter(dateFormatter + " " + timeFormatter);

            this.MyDate.Text = fullFormatter.Format(DateTime.Now);

image

Update 4.7.2013:

It seems I can get the behavior similar to Silverlight and other frameworks by setting the Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride on application startup (App.xaml.cs). For example:

        public App()
        {
            Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = Windows.Globalization.Language.CurrentInputMethodLanguageTag;
            this.InitializeComponent();
            this.Suspending += OnSuspending;
        }

 

4 Comments
  •   Posted in: 
  • UWP

screenshot_06272013_100012

In this tutorial we’re going to create a simple XAML app using the new Hub control. The tutorial is also going to show how SemanticZoom can be used with the Hub.

The Hub control is one of the new additions in Windows 8.1 XAML SDK and as described by the MSDN, Hub is “a new control for XAML that lets you easily create the hub design pattern that reflects the proper design guidelines and behavior”.

Why to use Hub control?

The MSDN again does a great job of summing up the reasoning behind a hub page and the hub control:

Hub pages are the user''s entry point to your app. They display content in a rich, panning view that lets users get a glimpse of what''s new and exciting, and then dig deeper into your app''s content. The hub displays different categories of content, each of which maps to your app''s section pages. Each section should bubble up content or functionality. The Hub should offer a lot of visual variety, engage users, and draw them in to different parts of the app.

For example the Weather and the Travel apps use hub pages as their starting points:

image

Getting started

In this tutorial we’re going to start from the “Blank App (XAML)” template. The aim is to create a hub page for a movie app using the new control.

screenshot_06272013_100012

So let’s start by creating the new app from the Blank App template. The template contains only a single empty page, MainPage.xaml, which we’re going to start editing:

image

As a test, if we insert the Hub control inside the Grid and set it’s background to Red, we can see that the new control fills the whole layout container:

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">

        <Hub Background="Red"></Hub>

    </Grid>

image

As we have a working Hub control, it’s time to add some content to it. Let’s start from the header.

Setting the header

The header in Hub control is visible all the time, even when the user scrolls horizontally. It usually includes the app’s name but it can also contain other controls like the back button. The header can be configured using the Header-property:

        <Hub Background="Red">

            <Hub.Header>
                <Grid>

                </Grid>
            </Hub.Header>

        </Hub>

In this tutorial we only want to show the app’s name inside the header:

            <Hub.Header>
                <Grid>
                    <TextBlock Text="The Movie App" />
                </Grid>
            </Hub.Header>

image

As we can see, there’s no need to define style for the TextBlock. The header automatically sets the font’s size and weight and also the padding. Because the only thing we need in the header is the app’s name, we can configure the header even more easily:

        <Hub Background="Red" Header="The Movie App">

        </Hub>

Now that we have the header configured, it’s time add some actual content into the hub.

Adding content into Hub control: The HubSection control

The Hub control itself only shows the header. We need to add HubSection controls inside the Hub control to add the actual content.  This is similar to the Windows Phone app’s, where we have the Panorama and the PanoramaItem controls.

In our app, we want to display four hub sections:

  • The second section just displays a static image from a movie
  • The first section shows pictures of the most popular movies
  • The third section list some movies near you
  • The last section provides movie trailers

Let’s add these sections now:

        <Hub Background="Red" Header="The Movie App">
            <HubSection Header="Popular"></HubSection>

            <HubSection></HubSection>

            <HubSection Header="Near You"></HubSection>

            <HubSection Header="Trailers"></HubSection>
        </Hub>

And here’s the result:

image

Let’s add some content into the HubSections, starting from the second one (the one which displays the static movie image).

Full height image in HubSection

We want to display an image in the HubSection. And we want it to use all the available space. If we add the image as a content, this is what happens:

image

The image doesn’t use the whole space. The trick is to set the image as the background of the HubSection:

        <Hub Background="Red" Header="The Movie App">
            <HubSection Header="Popular"></HubSection>

            <HubSection Width="500">
                <HubSection.Background>
                    <ImageBrush ImageSource="/Assets/poster.jpg" Stretch="UniformToFill"/>
                </HubSection.Background>
            </HubSection>

            <HubSection Header="Near You"></HubSection>

            <HubSection Header="Trailers"></HubSection>
        </Hub>

Also notice that we set the Width of the HubSection. Here’s the result:

image

Now it looks much better. One HubSection down, three to go.

Adding content to HubSection

We still have three empty HubSections. But filling them is easy, as we can use the standard GridView and ListView controls. A HubSection can contain any content you like: Buttons, UserControls, Grids, StackPanels etc. But what is little peculiar is that the HubControl doesn’t have a Content-property: You set the content by setting its DataTemplate. Here’s a small example:

            <HubSection Header="Popular">
                <DataTemplate>
                    <StackPanel>
                        <Button Content="Button inside a HubSection"/>
                    </StackPanel>
                </DataTemplate>
            </HubSection>

image

Filling the remaining HubSections with GridViews and ListViews is outside the scope if this tutorial, but the source code shows how it’s done. One important point though: A control which is inside a HubSection cannot be directly accessed from code-behind!

For example, here’s a HubSection which contains a single ListView:

            <HubSection Header="Trailers">
                <DataTemplate>
                    <ListView x:Name="MovieTrailers">

                    </ListView>
                </DataTemplate>
            </HubSection>

Even though we’ve given the ListView a name, we cannot access it from the code-behind:

image

This is because the control is inside a DataTemplate. One easy way to get around this limitation is to hook into the ListView’s Loaded-event. Here’s the XAML:

                    <ListView x:Name="MovieTrailers" Loaded="MovieTrailers_Loaded">

                    </ListView>

And the code behind:

        private void MovieTrailers_Loaded(object sender, RoutedEventArgs e)
        {
            var listView = (ListView)sender;
            listView.ItemsSource = trailers;
        }

Header navigation

Our hub page only shows few trailers so the actual app probably has a dedicated page for the trailers. We want to enable the navigation so that the user can click the “Trailers” header to move forward. This feature is built into the Hub control.

First thing we need to to is to enable the header clicking for the HubSection, by setting its IsHeaderInteractive property to true:

            <HubSection Header="Trailers" Width="550" IsHeaderInteractive="True" >
                <DataTemplate>
                    <ListView Loaded="MovieTrailers_Loaded" 
                              SelectionMode="None" 
                              ItemTemplate="{StaticResource Standard130ItemTemplate}"/>
                </DataTemplate>
            </HubSection>

What’s great is that this automatically adds the navigation indicator to the header:

image

Now to handle the click, we must attach to Hub’s (not HubSection’s) SectionHeaderClick-event:

<Hub Header="The Movie App" Background="{StaticResource BackgroundBrush}" SectionHeaderClick="Hub_SectionHeaderClick">

The clicked HubSection can be read from the event’s arguments:

        private void Hub_SectionHeaderClick(object sender, HubSectionHeaderClickEventArgs e)
        {
            var clickedSection = e.Section;
            if (clickedSection.Name == "TrailersSection")
            {
                // Add navigation logic
            }
        }

Semantic zoom

Last thing we’re going to add to the hub is semantic zoom. The Hub control supports semantic zoom, meaning it can be used as a Zoomed in view.

First thing we need to do is to add the SemanticZoom control to the page:

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <SemanticZoom x:Name="Zoom">
            <SemanticZoom.ZoomedInView></SemanticZoom.ZoomedInView>

            <SemanticZoom.ZoomedOutView></SemanticZoom.ZoomedOutView>
        </SemanticZoom>

        <Hub x:Name="Hub" Header="The Movie App" Background="{StaticResource BackgroundBrush}" SectionHeaderClick="Hub_SectionHeaderClick">

Then we move the whole Hub inside the ZoomedInView:

image

Also we need a ZoomedOutView. For that, let’s create a simple GridView:

            <SemanticZoom.ZoomedOutView>

                <GridView VerticalAlignment="Center" Margin="200,0,0,0" Loaded="GridView_Loaded">
                    <GridView.ItemTemplate>
                        <DataTemplate>
                            <StackPanel >
                                <TextBlock HorizontalAlignment="Center" Text="{Binding}" Style="{StaticResource SubheaderTextBlockStyle}" />
                            </StackPanel>
                        </DataTemplate>
                    </GridView.ItemTemplate>

                    <GridView.ItemContainerStyle>
                        <Style TargetType="GridViewItem">
                            <Setter Property="Margin" Value="4" />
                            <Setter Property="Padding" Value="5" />
                            <Setter Property="HorizontalContentAlignment" Value="Left" />
                            <Setter Property="VerticalContentAlignment" Value="Center" />
                        </Style>
                    </GridView.ItemContainerStyle>

                    <GridView.ItemsPanel>
                        <ItemsPanelTemplate>
                            <WrapGrid ItemWidth="400" ItemHeight="70" Orientation="Horizontal" VerticalChildrenAlignment="Center" MaximumRowsOrColumns="3"></WrapGrid>
                        </ItemsPanelTemplate>
                    </GridView.ItemsPanel>
                </GridView>

            </SemanticZoom.ZoomedOutView>

Only one small thing left: We have to provide some items for this GridView. We do that in the GridView_Loaded:

        private void GridView_Loaded(object sender, RoutedEventArgs e)
        {
            var sections = this.Hub.Sections;
            var headers = new List<string>();

            foreach(var item in sections)
            {
                var section = (HubSection)item;
                var header = (string)section.Header;
                if (string.IsNullOrWhiteSpace(header))
                    continue;

                headers.Add(header);
            }

            ((GridView)this.Zoom.ZoomedOutView).ItemsSource = headers;
        }

The code loops through all the HubSections. It takes the sections header from each of them and add its to the “headers”-list. This list is then set as the ItemsSource for our ZoomedOutView’s GridView. And that’s it. We can now zoom out:

image

And click any of the items to zoom into that section.

Final touches and the source code

At this point we’ve realized that the app looks better if we put the static picture as the first HubSection. Also, the red background can be replaced with a little less stressful color.

Full source code for the tutorial is available from GitHub (folder hubcontrol-getting-started). The app works with the preview release of Visual Studio 2013 and Windows 8.1.

3 Comments
  •   Posted in: 
  • UWP

Using Basic Authentication in a WinRT app is a common requirement. The basic authentication isn’t supported out-of-the box by the HttpClient  but the HttpClient class has a good extensibility model: The basic authentication can be implemented using a custom DelegatingHandler:

    public class BasicAuthHandler : DelegatingHandler
    {
        private readonly string username;
        private readonly string password;

        public BasicAuthHandler(string username, string password)
            : this(username, password, new HttpClientHandler())
        {
        }

        public BasicAuthHandler(string username, string password, HttpMessageHandler innerHandler)
            : base(innerHandler)
        {
            this.username = username;
            this.password = password;
        }

        protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            request.Headers.Authorization = CreateBasicHeader();

            var response = await base.SendAsync(request, cancellationToken);

            return response;
        }

        public AuthenticationHeaderValue CreateBasicHeader()
        {
            var byteArray = System.Text.Encoding.UTF8.GetBytes(username + ":" + password);
            var base64String = Convert.ToBase64String(byteArray);
            return new AuthenticationHeaderValue("Basic", base64String);
        }
    }

The BasicAuthHandler can be used by passing it into the HttpClient’s constructor:

            var client = new HttpClient(new BasicAuthHandler("username", "password"));

            var data = await client.GetStringAsync("http://secured.address.com/api");

9 Comments
  •   Posted in: 
  • UWP

If you’re building a custom user control to be used on multiple pages, it may come handy if the control’s functionalities can be easily changed. For example imagine a search grid with a textbox, button and the result list. If you want to use the same control on multiple pages, it may be required that the datasource of the control can be easily configured. One way to handle a scenario like this is to allow the developer customize the behavior on the View Model’s side by using bind to a method. Let’s go through some code:

The user control

image

The idea is to build a user control which can be dropped on to multiple different pages. When the user clicks “Search”, the query is executed on the view model and the result is returned to the user control.

For this we need a Dependency Property of type System.Func. The func takes a string (the search query) and returns a list of objects. This is executed when the user clicks Search. The complete code with the dependency property included is shown below:

    public sealed partial class MyUserControl
    {
        public static readonly DependencyProperty GetQueryResultsCommandProperty =
            DependencyProperty.Register("GetQueryResultsCommand", typeof (Func<string,List<object>>), typeof (MyUserControl), new PropertyMetadata(default(Func<string,List<object>>)));

        public Func<string,List<object>> GetQueryResultsCommand
        {
            get { return (Func<string,List<object>>) GetValue(GetQueryResultsCommandProperty); }
            set { SetValue(GetQueryResultsCommandProperty, value); }
        }

        public MyUserControl()
        {
            this.InitializeComponent();
        }

        private void SearchButtonClick(object sender, RoutedEventArgs e)
        {
            var results = GetQueryResultsCommand.Invoke(this.Keyword.Text);

            ShowResults(results);
        }

        private void ShowResults(List<object> results)
        {
            //
        }
    }

The page

Next thing on the list is a page which contains the user control.

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">

        <local:MyUserControl HorizontalAlignment="Center" VerticalAlignment="Center"
                             GetQueryResultsCommand="{Binding GetQueryResults}"/>

    </Grid>

The GetQueryResultsCommand is bound against the view model’s method.

The view model

Last step is to implement the GetQueryResults-method on the view model. The method is implemented as a read-only property of Func<string,List<object>> so it uses the same signature as the dependency property. This can be read as a “method which takes a string as a parameter and returns a list of objects”.

    public class MainPageViewModel
    {
        public Func<string,List<object>> GetQueryResults
        {
            get
            {
                return keyword =>
                           {
                               var result = new List<object>()
                                                {
                                                    "Hello",
                                                    "Query",
                                                    "Results"
                                                };

                               return result;
                           };
            }
        }
    }

And that’s it. When the user clicks the search button, the event handler invokes the method which we have defined on the view model, using bind to method.

image

13 Comments
  •   Posted in: 
  • UWP

screenshot_11092012_072155

Let’s start with the bad news: If yourWinRT XAML app uses the GridView with grouping, you’re app is quite likely going to hang and crash on Windows RT tablets. It doesn’t matter if the GridView has thousands of items or 50, it will crash. Just start the app on a Windows RT tablet, do some navigation between the GridView and item details and you’ll notice that 1) the application will stop responding to touch and 2) it just closes. And all this time the app will work just fine on the simulator and on the desktop.

The problem

When the grouping is enabled on the GridView, the virtualization doesn’t work. And when the virtualization doesn’t work, the GridView will have severe performance problems and your app will crash. Without the virtualization your app will use much more memory but the problem isn’t entirely caused by this: I’ve seen apps taking less than 70 MB hang and crash when the grouping has been enabled.

The crashing will happen when you navigate back to a page which has:

  • GridView with grouping enabled
  • NavigationCacheMode set to enabled

The solution

Never enable the grouping on the GridView. Without grouping the GridView can handle thousands and thousands of items. The performance will be great.

If you need to group the items, the solution is to do the groups manually:

  1. Put all the items into a single collection. The collection should contain not just the items but also the groups. For example here’s a collection with 5 items, from which 2 are groups:  2012, Movie 1, Movie 2, 2011, Movie 3.
  2. Use the GridView’s ItemTemplateSelector to display the items and groups differently.
  3. If you require Semantic zoom, create a separate collection which contains just the groups. So one collection with all the items and groups as described in 1 and, in addition to that, a collection with just the groups.

The app will not end up looking just like with the built-in grouping, but it will look good enough. And what’s important, it will not crash.

Let’s use the steps described above to transform a crashing WinRT XAML app to an app with great performance.

Example app

Here’s an example app which loads movie details from a Finnish Video On Demand service and displays them on a GridView, grouped by the release year:

screenshot_11092012_074014

It loads and displays 125 movies. It will perform great on the desktop but on the Windows RT tablet it will hang and crash. Before crashing the performance is already sluggish. But navigate few times (usually between 3 to 10 times) to the movie details and back and you’ll notice that the app will stop responding to touch and it will eventually crash.

When we fix the performance by creating the groups manually, we can show thousands movies in a single GridView and still have access to features like the semantic zoom. The trade-off is that the end result looks different: The group headers are part of the grid.

screenshot_11092012_075755

Creating the groups manually

The sample app’s code shows all the steps required to create the groups manually but let’s go through some of the basics.

The templates

First of all, you mush have two templates: One for the items (movies) and one for the group headers (years):

<DataTemplate x:Key="MovieTemplate"> 
    <Grid HorizontalAlignment="Left" Width="250" Height="250"> 
        <Border Background="{StaticResource ListViewItemPlaceholderBackgroundThemeBrush}"> 
            <Image Source="{Binding Cover}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}"/> 
        </Border> 
        <StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}"> 
            <TextBlock Text="{Binding Title}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="60" Margin="15,0,15,0"/> 
            <TextBlock Text="{Binding Year}" Foreground="{StaticResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/> 
        </StackPanel> 
    </Grid> 
</DataTemplate>

<DataTemplate x:Key="MovieCategoryTemplate"> 
    <Grid HorizontalAlignment="Left" Width="250" Height="250"> 
        <StackPanel VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}"> 
            <TextBlock Text="{Binding}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="60" Margin="15,0,15,0"/> 
        </StackPanel> 
    </Grid> 
</DataTemplate>

You also need a TemplateSelector which can select the correct template based on the item:

public class MyTemplateSelector : DataTemplateSelector 
{ 
    protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) 
    { 
        var movie = item as MovieInfo; 
        if (movie != null) 
            return (DataTemplate) App.Current.Resources["MovieTemplate"];

        return (DataTemplate)App.Current.Resources["MovieCategoryTemplate"]; 
    } 
}

The GridView

The GridView shouldn’t set the ItemTemplate, instead it points to the TemplateSelector:

<GridView x:Name="itemGridView"
            TabIndex="1"
            Grid.RowSpan="2"
            Padding="116,157,40,46"
            ItemsSource="{Binding Items}"
            ItemTemplateSelector="{StaticResource MyTemplateSelector}"
            SelectionMode="None"
            IsSwipeEnabled="false" IsItemClickEnabled="True"
            ItemClick="ItemView_ItemClick"> 
</GridView>

The data

In the example above, the GridView uses an ObservableCollection called “Items” as the item source. This collection shouldn’t be grouped by any way. Instead it should contain both the movie groups and the movies:

public ObservableCollection<object> Items { get; set; }
...
var moviesByYear = movies.GroupBy(x => x.Year);
foreach (var group in moviesByYear)
{
    this.Items.Add(group.Key.ToString());

    foreach (var movieInfo in group)
    {
        this.Items.Add(movieInfo);
    }
}

Semantic zoom

If semantic zoom is required, the movie data should be split into two collections: One containing both the movies and the years and the other containing only the years:

public ObservableCollection<object> Items { get; set; }
public ObservableCollection<string> Groups { get; set; }
...		
var moviesByYear = movies.GroupBy(x => x.Year);
foreach (var group in moviesByYear)
{
    // The group is added to two collections: Collection containing only the groups and the collection containing movies and the groups
    this.Groups.Add(group.Key.ToString());
    this.Items.Add(group.Key.ToString());

    // The movies are only added to the collection containing movies and groups
    foreach (var movieInfo in group)
    {
        this.Items.Add(movieInfo);
    }
}

The ZoomedOutView should use the Groups as ItemsSource:

<SemanticZoom.ZoomedOutView> 
               <GridView VerticalAlignment="Center" Margin="200,-100,0,0" x:Name="ZoomedOutGrid" ItemsSource="{Binding Groups}"
                         SelectionMode="None">

screenshot_11092012_083312

In order for the semantic zoom to work correctly the ZoomedInView’s GridView should be manually scrolled to the selected group:

private void SemanticZoom_OnViewChangeStarted(object sender, SemanticZoomViewChangedEventArgs e) 
{ 
    if (e.IsSourceZoomedInView) 
        return;

    this.itemGridView.Opacity = 0; 
}
private void SemanticZoom_OnViewChangeCompleted(object sender, SemanticZoomViewChangedEventArgs e) 
{ 
    if (e.IsSourceZoomedInView) 
        return;

    try
    { 
        var selectedGroup = e.SourceItem.Item as string; 
        if (selectedGroup == null) 
            return;

        itemGridView.ScrollIntoView(selectedGroup, ScrollIntoViewAlignment.Leading); 
    } 
    finally
    { 
        this.itemGridView.Opacity = 1; 
    } 
}

We play with the Opacity to get rid of some flickering.

It’s also possible to zoom out the view when a user clicks a group header, making the GridView to behave like a JumpList in Windows Phone:

void ItemView_ItemClick(object sender, ItemClickEventArgs e) 
{ 
    if (e.ClickedItem is MovieInfo) 
        this.Frame.Navigate(typeof (MovieDetailsPage)); 
    else
        this.Zoom.IsZoomedInViewActive = false; 
}

Conclusion and the source code

The GridView control is a great way to show lots of items to the user. Unfortunately the built-in support for grouping will hang and crash your application on a Windows RT tablet. If grouping is required, create the groups manually.

The sample app (WinRT-GridView-XAML-Performance-Problems) is available from GitHub. By default it starts with the page which has good performance and doesn’t crash on a Windows RT tablet. To try out the version with built-in grouping turned on, change the start page of the app to BadPerformancePage.