WinRT: How to properly implement ISupportIncrementalLoading with navigation

BestComparator is about to publish its new Windows 8 application, and I ran into a really weird and frustrating issue when implementing ISupportIncrementalLoading.

Supporting infinite scrolling pagination

The best way to support infinite scrolling, is to use a GridView or a ListView and bind it an ObservableCollection that implements the ISupportIncrementalLoading.

You will probably end with a class like this one:

public class PaginatedCollection : ObservableCollection, ISupportIncrementalLoading
{
    private Func<uint, Task<IEnumerable>> load;
    public bool HasMoreItems { get; protected set; }

    public PaginatedCollection(Func<uint, Task<IEnumerable>> load)
    {
        HasMoreItems = true;
        this.load = load;
    }

    public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
    {
        return AsyncInfo.Run(async c => {
            var data =  await load(count);

            foreach (var item in data) {
                Add(item);
            }

            HasMoreItems = data.Any();

            return LoadMoreItemsResult() {
                Count = data.Count,
            };
        });
    }
}

Then you can simply create a bindable collection for your GridView or ListView in you ViewModel this way:

// in your view model
Items = new PaginatedCollection(async count => {
    var result = // your logic to load more items asynchronusly
    return result;
});

At binding time, the control will automatically detect that you binded a ISupportIncrementalLoading collection and will automatically call the LoadMoreItemsAsync when needed.

The incomprehensible AccessViolationException

Everything seems to work fine but if you happen to navigate in and out of a page using this interface you might get this exception for apparently no reason: AccessViolationException. You will get no stack trace to debug. Basically, the platform crash at a very low level around the C++ layer. Apparently, the asynchronous loading get bugged when you leaved the page and it is destroyed.

The almost easy workaround

I was stuck on this issue for quite a long time. I event though of manually implementing the infinite scrolling the way I did it in wp7, which I was not found of because it was quite hack (I was listening to the compress state of the scroller in order to detect when the end of the list was reached). Then I got the idea of caching the pages at a low level using the NavigationCacheMode of the Page control. It is simply done in the LayoutAwarePage constructor:

public LayoutAwarePage()
{
    NavigationCacheMode = NavigationCacheMode.Enabled;
    // the rest of the logic…
}

By doing so, you tell the framework to keep the page in the memory and directly use it when navigating forth and back to the page. This way, because the page still lives in memory, your asynchronous request to get more items continues to behave properly when navigating.

The hidden issue behind page caching

But, the fix is not complete yet. By using page caching, it is not properly regenerated when you navigate to a page already loaded but with a different context. Let’s take an example: BestComparator has a homepage listing different categories of products. When selecting the smartphones category, you navigate to a CategoryPage with the id of the category as a parameter. This was the smartphones category is completely fetched with its corresponding products. But if you go back to the homepage and then navigate to the laptops category, the framework will use the previously cached CategoryPage which was loaded with smartphones… and won’t trigger the load of the laptops.

The fix here is quite subtle, what you need to do is to trigger the LoadState procedure not only when the page is new, but also when navigating forward, mimicking the windows phone 7 navigation system. Just go to the OnNavigatedTo method of the LayoutAwarePage and add in the first line a test concerning the NavigationMode:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    // Returning to a cached page through navigation shouldn't trigger state loading
    if (this._pageKey != null && e.NavigationMode == NavigationMode.Back) return;
    // The rest of the logic...
}

And here it is, you completely support infinite scrolling with no bug, and won a nice page caching strategy on the way.

Wrap up

The new interface ISupportIncrementalLoading provided in WinRT can be very useful but its behavior when asynchronously loading items and navigating is quite bugged. What you have to do is activate a Page caching strategy and don’t forget to tweak the loading state process and everything should run smoothly.

Advertisements

Force validation of RIA entities

Force validation of RIA entities

As I am currently developing a Silverlight Application using RIA Services (and Prism), I ran into some little tricks that can really help the developer’s life.

One of the common needs is to force the validation of all fields of an exposed entity in one time, and not just one field just after it has been updated.
This is very important especially when you want to insure our object is strictly validated before submitting changes.

The trick is to create a ValidationContext and manually validate the whole object. The thing to be careful of is not to forget to update the ValidationErrors list of the entity.

[csharp]
public static void Validate(this Entity entity)
{
// prepare the result
var validationResults = new List<ValidationResult>();
// create a validation context
var validationContext = new ValidationContext(entity, null, null);
// validate
Validator.TryValidateObject(entity, validationContext, validationResults);
// reset the validation errors of the entity
entity.ValidationErrors.Clear();
foreach (var error in validationResults)
entity.ValidationErrors.Add(error);
}
[/csharp]

As you can see, I made this method as an extension to the Entity type. So that you can easily use it on every entity you have.

A map picker for windows phone 7

A map picker for windows phone 7

For my end of study project, I am developing a windows phone 7 app with a team. We are using the geolocation features and recently needed a way for the user to select a place on the map.

Thus I made an implementation of a map picker, let’s see it.

New project
Let’s create a new project and simple change the basic grid to a map control.

New project, map instead of grid
New project, map instead of grid

[xml]
<!– /MainPage.xaml –!>

xmlns:my="clr-namespace:Microsoft.Phone.Controls.Maps;assembly=Microsoft.Phone.Controls.Maps"
<!– … –!>
<my:Map x:Name="MapControl" Grid.Row="1"/>
[/xml]

I also like to make some improvements to the map, let’s customize it. We also need to add a pushpin that will designate the selected place:
[xml]
<!– /MainPage.xaml –!>

<my:Map x:Name="MapControl" Grid.Row="1"
LogoVisibility="Collapsed" ScaleVisibility="Visible"
CopyrightVisibility="Collapsed" ZoomBarVisibility="Visible">
<my:Pushpin Name="Pushpin" />
</my:Map>
[/xml]

Support selection
In order to make the map tappable, I use the toolkit for windows phone 7 that you can find in codeplex: http://silverlight.codeplex.com/releases/view/55034. Don’t forget to add a reference.

You can add the tappable behavior like that:
[xml]
<!– /MainPage.xaml –!>

xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
<!– … –!>
<my:Map x:Name="MapControl" Grid.Row="1"
LogoVisibility="Collapsed" ScaleVisibility="Visible"
CopyrightVisibility="Collapsed" ZoomBarVisibility="Visible">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener Tap="GestureListener_Tap"/>
</toolkit:GestureService.GestureListener>
<my:Pushpin Name="Pushpin" />
</my:Map>
[/xml]

Now, you can go to the code behind. We need here to translate the screen position where the use tap and translate it to a geolocation:
[csharp]
// /MainPage.xaml.cs

private void GestureListener_Tap(object sender, GestureEventArgs e)
{
// get the tapped position relative to the map
var point = new Point(e.GetPosition(MapControl).X, e.GetPosition(MapControl).Y);
// get the geolocation of that position
var location = MapControl.ViewportPointToLocation(point);

// move the pushpin
Pushpin.Location = location;
}
[/csharp]

The thing here is that the gesture event returns the X and Y position relative to the top left of the screen. You first need to get the position relative to the map control, and then ask the map to translate it to a geolocation (longitude and latitude).
With this location you can move the pushpin to the selected place.

Selected place
Selected place

Display the selected address
Now that the user can pick a position on the map, I would like to tell him the address he selected. In order to do that we will use the Bing API located at this url: http://dev.virtualearth.net/webservices/v1/geocodeservice/geocodeservice.svc/mex.

You will also need to get a Bing API key here: https://bingmapsportal.com/.

Now you can add the service reference:

Service reference
Service reference

In our code we just need to code the ReverseGeocode method on the service using the location and the API key:
[csharp]
// /MainPage.xaml.cs

private void GestureListener_Tap(object sender, GestureEventArgs e)
{
// get the tapped position relative to the map
var point = new Point(e.GetPosition(MapControl).X, e.GetPosition(MapControl).Y);
// get the geolocation of that position
var location = MapControl.ViewportPointToLocation(point);

// move the pushpin
Pushpin.Location = location;
Pushpin.Content = "loading…";

// get the address
// prepare the request
var request = new ReverseGeocodeRequest()
{
Location = location,
Credentials = new Credentials()
{
ApplicationId = "Your bing API code here"
}
};
// prepare the service
var service = new GeocodeServiceClient();
service.ReverseGeocodeCompleted += service_ReverseGeocodeCompleted;
// make the request
service.ReverseGeocodeAsync(request);
}

void service_ReverseGeocodeCompleted(object sender, ReverseGeocodeCompletedEventArgs e)
{
// if there is any address
if (e.Result.Results.Count > 0)
// use the first one
Pushpin.Content = e.Result.Results[0].Address.FormattedAddress;
// else show invalid position
else
Pushpin.Content = "Invalid";
}
[/csharp]

When the service answers our request, we can simply update the pushpin text with the address.

Address completion
Address completion

Wrap up
We just saw here how to support selection on the map control and give a fancy feedback to the user, showing a pushpin and filling the address using the Bing API. Thus we made a very nice Map Picker.

You can download the sources here : MapPicker sources.

Slides about .NET, Linq, Entity Framework, Windows Phone 7

Slides about .NET, Linq, Entity Framework, Windows Phone 7

I just uploaded some slides I made for the preparation of a scholarship project. I made a quick overview of .NET, C#, Linq, Entity Framework, Windows Phone 7… for people who already have experienced Java and/or C++.
It’s in French. Feel free to react and to post me your comments.


Je viens juste d’uploader des slides que j’ai faits pour la préparation d’un projet scolaire. J’y fait un rapide aperçu de .NET, C#, Linq, Entity Framework, Windows Phone 7… pour les personnes ayant déjà une expérience en Java et/ou C++.
N’hésitez pas à réagir et à poster vos commentaires.

Support orientation with a listbox and rotate animation on windows phone 7

Support orientation with a listbox and rotate animation on windows phone 7

Today I will show how to simply implement a windows phone 7 app that supports orientation with transition. I will also go through a common issue with the list box control.

Setting up the project

For this post I’ll use the default DataBoundApplication, I will also use the transition provided by the brand new Silverlight for windows phone toolkit (second, released in November 2010) : http://silverlight.codeplex.com/releases/view/55034.

Well, let’s do basics. Create a new DataBoundProject :

Default DataBoundApplication
Default DataBoundApplication

First, let’s make our app support the various transition provided by the toolkit. First, add a reference to Microsoft.Phone.Controls.Toolkit and go to the App.xaml.cs file:

[csharp]
// /App.xaml.cs
//…
private void InitializePhoneApplication()
{
if (phoneApplicationInitialized)
return;

// Create the frame but don’t set it as RootVisual yet; this allows the splash
// screen to remain active until the application is ready to render.
RootFrame = new TransitionFrame();
RootFrame.Navigated += CompleteInitializePhoneApplication;

// Handle navigation failures
RootFrame.NavigationFailed += RootFrame_NavigationFailed;

// Ensure we don’t initialize again
phoneApplicationInitialized = true;
}
//…
[/csharp]

Then edit the main page to support both orientations. Go to the first tag and edit the SupportedOrientation property to PortraitOrLandscape :

[xml]
<!–MainPage.xaml–>
<phone:PhoneApplicationPage
x:Class="WindowsPhoneDataBoundApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008&quot;
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006&quot;
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
d:DataContext="{d:DesignData SampleData/MainViewModelSampleData.xaml}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<!– … –>
[/xml]

Now we have an app that can support orientation and transition. Let’s activate the rotate transition when we change the orientation.

Support rotation on orientation change

I will derive from the PhoneApplicationPage class in order to create a new one that can rotate automatically, and then I will change all my pages for them to derive the new class and thus inherit the new auto-rotation behavior.

So, we need to create our AutoRotatePage class. I override the OnOrientationChange method so when it occurs we perform a rotation transition:

[csharp]
public class AutoRotatePage : PhoneApplicationPage
{
/// <summary>
/// This varialb eis needed in order to now what was the previous orientation
/// and then choose the proper rotation mode
/// </summary>
private Nullable<PageOrientation> _previousOrientation = null;

/// <summary>
/// When the orientation changes perform a rotate transition
/// </summary>
/// <param name="e"></param>
protected override void OnOrientationChanged(OrientationChangedEventArgs e)
{
base.OnOrientationChanged(e);

if (_previousOrientation == null)
return;

RotateTransition transitionElement = new RotateTransition();

// counter clockwise rotation
if (_previousOrientation == PageOrientation.LandscapeRight &&
e.Orientation == PageOrientation.PortraitUp ||
_previousOrientation == PageOrientation.PortraitUp &&
e.Orientation == PageOrientation.LandscapeLeft ||
_previousOrientation == PageOrientation.LandscapeLeft &&
e.Orientation == PageOrientation.PortraitDown ||
_previousOrientation == PageOrientation.PortraitDown &&
e.Orientation == PageOrientation.LandscapeRight)
transitionElement.Mode = RotateTransitionMode.In90Counterclockwise;
// clockwise rotation
else if (_previousOrientation == PageOrientation.LandscapeLeft &&
e.Orientation == PageOrientation.PortraitUp ||
_previousOrientation == PageOrientation.PortraitDown &&
e.Orientation == PageOrientation.LandscapeLeft ||
_previousOrientation == PageOrientation.LandscapeRight &&
e.Orientation == PageOrientation.PortraitDown ||
_previousOrientation == PageOrientation.PortraitUp &&
e.Orientation == PageOrientation.LandscapeRight)
transitionElement.Mode = RotateTransitionMode.In90Clockwise;
// 180 rotation
else
transitionElement.Mode = RotateTransitionMode.In180Clockwise;

var transition = transitionElement.GetTransition((PhoneApplicationPage)(((PhoneApplicationFrame)Application.Current.RootVisual).Content));
transition.Completed += delegate { transition.Stop(); };
transition.Begin();

_previousOrientation = e.Orientation;
}

/// <summary>
/// When leaving the page, clearing the orientation
/// </summary>
/// <param name="e"></param>
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);

_previousOrientation = null;
}

/// <summary>
/// When comming to the page, initiate the orientation
/// </summary>
/// <param name="e"></param>
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);

_previousOrientation = Orientation;
}
}
[/csharp]

You may notice that I always keep track of the previous orientation. It is very important because I use it to know if I need to perform a clockwise or a counter clockwise transition. Thus I use the OnNavigatedFrom and OnNavigatedTo method in order to set and clean my previous orientation value. I also do it this way for another reason.
If you are in the main page on a portrait up orientation and then go to the detail view and changhe the orientation to landscape. The detail view will rotate, but when you’ll go back the main page will detect a change in the orientation and then perform an unneeded rotate transition. In order to avoid that, I use the navigation methods to clean the previous orientation variable so that the OnOrientationChange methods can behave properly.

Now, you just need to make your pages derive this new AutoRotatePage class.

[csharp]
// /MainPage.xaml.cs
// …
public partial class MainPage : AutoRotatePage
// …
[/csharp]

Don’t forget the xaml, after declaring the local namespace :

[xml]
<!–MainPage.xaml–>
<local:AutoRotatePage
x:Class="WindowsPhoneDataBoundApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008&quot;
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006&quot;
xmlns:local="clr-namespace:WindowsPhoneDataBoundApplication1"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
d:DataContext="{d:DesignData SampleData/MainViewModelSampleData.xaml}"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
shell:SystemTray.IsVisible="True">

<!– … –>

</local:AutoRotatePage>
[/xml]

Now you can compile and test your application. Everything behaves properly.

Rotate transition
Rotate transition

Support a vertical stretch in the ListBox

Now you may want to align right some element of the list box, for example the detail textblock. Let’s do so.

Edit the concerned textblock in the xaml file:

[xml]
<!–MainPage.xaml–>
<!– … –>
<StackPanel Margin="0,0,0,17">
<TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}" HorizontalAlignment="Right"/>
</StackPanel>
<!– … –>
[/xml]

You have now a right alignment of your elements:

Right Aligment on portrait
Right Aligment on portrait

But, if you go to the landscape mode, you will find an error in the layout.

right aligment on landscape fails
right aligment on landscape fails

You notice a gap between the detail text and the right border of the screen.

In order to fix this, you will need to create a new resource and apply it to the ListBox. Let’s got the App.xaml and declare it:

[xml]
<!–App.xaml–>
<!– … –>
<Application.Resources>
<Style x:Key="ListBoxTemplate" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ContentControl ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalContentAlignment="Stretch"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
<!– … –>
[/xml]

As you can see, my resource access to the ListBox items and set the HorizontalContentAlignment to stretch.

Now, apply it to the ListBox:

[xml]
<!–MainPage.xaml–>
<!– … –>
<ListBox x:Name="MainListBox" Margin="0,0,-12,0" ItemsSource="{Binding Items}" SelectionChanged="MainListBox_SelectionChanged" ItemContainerStyle="{StaticResource ListBoxTemplate}">
<!– … –>
[/xml]

You can go back to the main page on Landscape mode and observe the correct right alignment.

right aligment on landscape ok
right aligment on landscape ok

Wrap up

Now you have everything set to have a nice Windows Phone 7 app that support both orientation with nice transitions and a proper ListBox.