Monday, 24 February 2014

Using the IncrementalUpdateBehavior to implement smooth scrolling

A common scenario in Windows Store apps is to use a GridView or ListView control to display a large number of data items. This can have a performance impact, which can be partially mitigated through UI virtualization. However, when displaying complex data items there can still be problems displaying the data items smoothly when scrolling.

This problem can be further addressed by using the IncrementalUpdateBehavior to incrementally update data items displayed by a GridView or ListView control. This behaviour promotes a smooth scrolling experience by deferring updates to some of the elements in the ItemTemplate until there is render time available.

This behaviour is triggered when the data being displayed by a GridView or ListView control changes. The order in which to update elements in the ItemTemplate on screen can be specified by adding the IncrementalUpdateBehavior to each element in the DataTemplate to be displayed, and setting its Phase property. The Phase property is used to set the priority of the incremental update in relation to other items in the DataTemplate.

<DataTemplate>
    <Image Source="{Binding Image}"
           Stretch="UniformToFill">
        <Interactivity:Interaction.Behaviors>
            <Core:IncrementalUpdateBehavior Phase="2"/>
        </Interactivity:Interaction.Behaviors>
    </Image>
    <TextBlock Text="{Binding Title}">
        <Interactivity:Interaction.Behaviors>
            <Core:IncrementalUpdateBehavior Phase="1"/>
        </Interactivity:Interaction.Behaviors>
    </TextBlock>
    <TextBlock Text="{Binding Price}">
        <Interactivity:Interaction.Behaviors>
            <Core:IncrementalUpdateBehavior Phase="1"/>
        </Interactivity:Interaction.Behaviors>
    </TextBlock>
</DataTemplate>

This DataTemplate specifies that the Title and Price for each data item will be displayed in the first rendering phase, with the Image being displayed in the second rendering phase. This helps to promote a smoother scrolling experience when scrolling through a data set that contains a large amount of data. If you require better performance than is provided by the IncrementalUpdateBehavior you should instead consider handling the ContainerContentChanging event in code.

For more information, including handling the ContainerContentChanging event in code, and a full downloadable code example, see Incremental loading Quickstart for Windows Store apps using C# and XAML, which we produced as part of Prism for the Windows Runtime for Windows 8.1.

Monday, 17 February 2014

Saving and restoring service class state using Prism for the Windows Runtime

Previously I wrote about how Prism for the Windows Runtime can be used to save and restore view state. This is achieved by overriding the SaveState and LoadState methods in a page that derives from the VisualStateAwarePage class, and then saving the desired state. I extended the sample photo viewer app so that the user will see the page content scrolled to the exact location it was at prior to termination or navigation, regardless of whether the page orientation has changed in between termination and reactivation.

Less well known is that Prism provides support for saving state from other classes, such as service classes. Therefore, in this blog post I’ll explain how state can be saved from a service class so that it survives termination, and how it can be restored upon reactivation.

Implementation

Suspend

In order for a service class to persist state to survive termination it must use an instance of the SessionStateService class, which implements the ISessionStateService interface. Therefore, the OnInitialize method in the App class needs to register the types with a dependency injection container.

protected override void OnInitialize(IActivatedEventArgs args)
{
    ...
    _container.RegisterInstance<ISessionStateService>(SessionStateService);
}

The code above registers the instance of the SessionStateService that’s created in the MvvmAppBase class with the ISessionStateService interface. The container will cache the instance on behalf of the app, with the lifetime of the instance being tied to the lifetime of the container.

The SomeService class has the SessionStateService instance injected as a dependency when the SomeService class is created.

public class SomeService
{
    private readonly ISessionStateService _sessionStateService;
 
    private const string SomeValue1Key = "SomeValue1";
    private const string SomeValue2Key = "SomeValue2";
    private string _someValue1, _someValue2;
 
    public SomeService(ISessionStateService sessionStateService)
    {
        _sessionStateService = sessionStateService;
        ...
    }
     
    ...
}

The constructor simply stores the SessionStateService instance in a private field. Then to save some service class state the SaveState method should be called.

private void SaveState(string someValue1, string someValue2)
{
    _sessionStateService.SessionState[SomeValue1Key] = someValue1;
    _sessionStateService.SessionState[SomeValue2Key] = someValue2;
}

The SaveState method shows how the SomeService class persists two string values so that they’ll survive termination. The required values are stored in the SessionState dictionary of the SessionStateService instance. When the app suspends, or page navigation occurs, these values will be written to the _sessionState.xml file.

Resume

When an app resumes from suspension it continues from where it was when it was suspended, as the app is still stored in memory. Therefore,no special behaviour is associated with resuming from suspension.

Activation

Windows may terminate an app after it’s been suspended, if the system is low on resources. If a service class has persisted state to survive termination, it must be restored when the app reactivates. This can be achieved in the constructor for the SomeService class.

public SomeService(ISessionStateService sessionStateService)
{
    _sessionStateService = sessionStateService;
 
    if (_sessionStateService != null)
    {
        if (_sessionStateService.SessionState.ContainsKey(SomeValue1Key))
        {
            _someValue1 = _sessionStateService.SessionState[SomeValue1Key].ToString();
        }
        if (_sessionStateService.SessionState.ContainsKey(SomeValue2Key))
        {
            _someValue2 = _sessionStateService.SessionState[SomeValue2Key].ToString();
        }
    }
}

The code simply checks that the SessionState dictionary contains the appropriate keys, and if it does, it restores the values of those keys from the _sessionState.xml file.

Summary

In this blog post I’ve shown how Prism can be used to save and restore state in a service class. This can be accomplished by injecting the SessionStateService into the service class, and saving the required data to the SessionState dictionary of that class. When the app reactivates, following termination, values can be retrieved from the dictionary in the service class constructor.

Wednesday, 12 February 2014

Prism for the Windows Runtime for Windows 8.1 available as an e-book

Prism for the Windows Runtime accelerates the development of Windows Store apps by providing support for Model-View-ViewModel (MVVM), loosely coupled communication, state management, navigation, validation of user input, data binding, commands, and settings.

Prism for the Windows Runtime for Windows 8.1 is now available as a free e-book and can be downloaded from here.

Monday, 10 February 2014

Saving and restoring view state using Prism for the Windows Runtime

Previously I’ve written about how Prism for the Windows Runtime can be used to save and restore view model state.To have data survive the suspend/terminate cycle in a Prism app all you have to do is mark any view model properties whose data you want to survive termination with the custom [RestorableState] attribute. When the app is reactivated, any properties that are marked with this attribute will have their values restored. All of this work is performed by the Prism.StoreApps library. For details of how Prism undertakes this operation see Handling suspend, resume, and activation in AdventureWorks Shopper.

Less well known is that Prism provides support for saving and restoring view state. Therefore, in this blog post I’ll extend the sample photo viewing app so that view state can be serialized during suspension, and de-serialized when the app reactivates. Specifically, the position of the ScrollViewer thumb in the GridView on the MainPage will be serialized/de-serialized so that when the app reactivates following termination, the scroll position of the MainPage will be identical to when the app was suspended. Furthermore, the code will restore the correct scroll position even if the view state of the app changes in-between termination and reactivation.

An obvious question is why would you want to save view state? Surely any controls in the view will just bind to properties in the view model? While that’s often the case, many controls contain other controls buried deeply within their control template. An example of this is the GridView control, which contains a ScrollViewer control for scrolling purposes. Prism supports saving view state in order to easily support scenarios where you want to save the view state of a control that’s referenced through a control template.

Implementation

Suspend

The SaveAsync method of the SessionStateService class is responsible for writing the current session state to disk, and is called by the OnSuspending event handler in the MvvmAppBase class.

The SaveAsync method calls the GetNavigationState method of each registered Frame object in order to persist the serialized navigation history (the frame stack). In a Prism app there’s only one registered frame, and it corresponds to the rootFrame in the InitializeFrameAsync method in the MvvmAppBase class.

When the SaveAsync method calls the GetNavigationState method, it in turn invokes the OnNavigatedFrom method of each of the frame’s associated page objects. The OnNavigatedFrom method in the VisualStateAwarePage class then invokes the SaveState method of any page that derives from it, allowing pages to save view state such as the current scroll position of a control.

protected override void SaveState(Dictionary<string, object> pageState)
{
    if (pageState == null) return;
 
    base.SaveState(pageState);
 
    pageState["ScrollViewerOffsetProportion"] = ScrollViewerUtilities.GetScrollViewerOffsetProportion(_photosGridViewScrollViewer);
}

The SaveState method preserves the state associated with the MainPage, in this case being a value that reflects the proportion of scrolling that has occurred either horizontally or vertically, depending on view state, within the ScrollViewer of the GridView. This value is retrieved by the GetScrollViewerOffsetProportion method of the ScrollViewerUtilities class, and can be restored when reactivation occurs.

Resume

When an app resumes from suspension it continues from where it was when it was suspended, as the app is still stored in memory. Therefore, the sample app has no special behaviour associated with resuming from suspension.

Activation

Windows may terminate an app after it has been suspended, if the system is low on resources. When a Prism app is reactivated the OnLaunched method in the MvvmAppBase class calls the InitializeFrameAsync method, which in turn calls the RestoreFrameState method in the SessionStateService class.

The RestoreFrameState method calls the SetNavigationState method of each registered Frame object in order to restore the serialized navigation history (the frame stack). In the sample app there is only one registered frame, and it corresponds to the rootFrame in the InitializeFrameAsync method in the MvvmAppBase class.

When the RestoreFrameState method calls the SetNavigationState method, it in turn invokes the OnNavigatedTo method of each of the frame’s associated page objects. The OnNavigatedTo method in the VisualStateAwarePage class then invokes the LoadState method of any page that derives from it, allowing pages to restore view state such as the current scroll position of a control.

protected override void LoadState(object navigationParameter, Dictionary<string, object> pageState)
{
    if (pageState == null) return;
 
    base.LoadState(navigationParameter, pageState);
 
    if (pageState.ContainsKey("ScrollViewerOffsetProportion"))
    {
        _scrollViewerOffsetProportion = double.Parse(pageState["ScrollViewerOffsetProportion"].ToString(), CultureInfo.InvariantCulture.NumberFormat);
    }
}

The LoadState method restores state associated with the MainPage, in this case a value that reflects the proportion of horizontal or vertical scrolling that had occurred, depending on view state, within the ScrollViewer of the GridView. The ScrollViewer is set with the restored value by the ScrollToProportion method in the ScrollViewerUtilities class once the windows has rendered or changed its rendering size. Therefore, the user will see the page content scrolled to the exact location it was at prior to termination or navigation, regardless of whether the page orientation has changed in between termination and reactivation.

Summary

In this blog post I’ve further extended the sample photo viewer app so that along with view model state, view state can be serialized during suspension and de-serialized when the app reactivates following termination. This is achieved by overriding the SaveState and LoadState methods in a page that derives from the VisualStateAwarePage class, and then saving the desired state. In the sample app the user will see the page content scrolled to the exact location it was at prior to termination or navigation, regardless of whether the page orientation has changed in between termination and reactivation.

The sample app can be downloaded here.