Menu Close

Loading data during WP7 Page navigation – the slow, the fast and the incremental

by Andreas Hammar

To show data to the user you have to load data and bind data – but which one is the slow part? Answer: It depends on the nature of your data and the complexity of your UI. This post will show you that data can be loaded on the UI thread or the background thread, and data can be bound all at once or a few items at a time. These data handling techniques can be used together to create one of the most important concepts in Windows Phone 7 – perceived performance. Full source with demo app showing the scenarios can be found at the bottom.

 

Visualizzazione codice C# negli articoli di Joomla

Per inserire del codice formattato mantenendo la formattazione  il singolo codice deve essere diviso tra:

<pre class=”brush: csharp;”>
CODICE C#
</pre>
<pre class=”brush: xml;”>
CODICE XAML
</pre>
e poi inserire infondo all’HTML dell’articolo:
<p>
{codecitation class=&quot;brush: xml; gutter: false;&quot; width=&quot;0px&quot; }
{/codecitation} 
{codecitation class=&quot;brush: c-sharp; gutter: false;&quot; width=&quot;0px&quot; }
{/codecitation}
</p>
Cosi funziona dopo l’installazione della Estensione CodeCitation.

Windows Phone HubTile in depth| Part2: Data Binding

by WindowsPhoneGeek

This is the second article about the new HubTile control from the latest release of Windows Phone Toolkit – August 2011 (7.1 SDK). This time I am going to talk about data binding and using HubTile in more complex scenarios.

NOTE:  In Part1 we talked about key properties, methods, events and the main features of the Windows Phone HubTile control. You can take a look at it for reference.

 

Windows Phone HubTile in depth| Part1: key concepts and API

by WindowsPhoneGeek

Recently a new version of the Windows Phone Toolkit was released: Windows Phone Toolkit – August 2011 (7.1 SDK) . Previously we covered all toolkit components in our 21 WP7 Toolkit in Depth articles covering all controls so it is time to continue this series with a few more posts related to the new components that come with Windows Phone Toolkit – August 2011 (7.1 SDK) .

We’ll start with two posts that cover all about the Windows Phone HubTile control in details. In Part1 I am going to talk about key properties, methods, events and the main features of the Windows Phone HubTile control.

 

Windows Phone Marketplace Test Kit

source: MSDN

The Windows Phone Marketplace Test Kit provides a suite of automated, monitored, and manual tests to help make sure that your applications are accepted in the Marketplace the first time you submit them. The test kit enables you to identify and fix issues prior to Marketplace submission, which saves time in the submission process. You can use the test kit to evaluate applications that target Windows Phone OS 7.1 or later.

Windows Phone Mango change, Listbox: How to detect compression(end of scroll) states ?

By MSDN

[Update: This is available after Beta2(Trial) build. Wait for RC/RTM builds]

If you’ve ever used a ListBox or ScrollViewer control and wanted to implement “infinite scrolling”, great news: in Mango you can easily detect both the end of scroll and compression states.

Infinite scrolling is a nice concept used when the data for a Listbox control is fetched from a server. Many web services let you fetch the data in chunks by specifying a starting location and number of records to retrieve in order to implement paging

A lot of web services are designed for a client to fetch ~40 items. Then, as the end user scrolls to the bottom of the list, client code detects that the end of the scrolling region has been reached (when the list compresses), and then fetches the next 40 odd items from the server.

Obviousy it isn’t a true infinite scrolling list – memory concerns can prop up, but it’ll feel infinite to most users if you implement a reasonable maximum.

How to detect the end of scrolling

On Windows Phone 7.0, the developer community came up with a bunch of hacks that worked in some situations, but we wanted to really offer this functionality in the platform for Mango and feel that it’s a much cleaner implementation as a result. Less hacking required!

So in Mango, throw away your old code – we’ve made this very easy and 100% reliable!

The attached sample shows all the various events that can be hooked to when scrolling on a WP7.1 application.

5810.image_5F00_4759BCBA[1]

We addressed this problem by introducing two new VisualStateGroups: HorizontalCompression andVerticalCompression.

The default style for the ScrollViewer does not include these new visual states – if you’re using them in your app, make sure to add a style to the app’s resources to expose these new VisualStateGroups.

Here’s the style:

    <Style TargetType="ScrollViewer"> 
            <Setter Property="VerticalScrollBarVisibility" Value="Auto"/> 
            <Setter Property="HorizontalScrollBarVisibility" Value="Auto"/> 
            <Setter Property="Background" Value="Transparent"/> 
            <Setter Property="Padding" Value="0"/> 
            <Setter Property="BorderThickness" Value="0"/> 
            <Setter Property="BorderBrush" Value="Transparent"/> 
            <Setter Property="Template"> 
                <Setter.Value> 
                    <ControlTemplate TargetType="ScrollViewer"> 
                        <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBindingBorderThickness}" 
Background="{TemplateBinding Background}"> 
                            <VisualStateManager.VisualStateGroups> 
                                <VisualStateGroup x:Name="ScrollStates"> 
                                    <VisualStateGroup.Transitions> 
                                        <VisualTransition GeneratedDuration="00:00:00.5"/> 
                                    </VisualStateGroup.Transitions> 
                                    <VisualState x:Name="Scrolling"> <Storyboard> 
                                            <DoubleAnimation Storyboard.TargetName="VerticalScrollBar" 
Storyboard.TargetProperty="Opacity" To="1" Duration="0"/> 
                                            <DoubleAnimation Storyboard.TargetName="HorizontalScrollBar" 
Storyboard.TargetProperty="Opacity" To="1" Duration="0"/> 
                                        </Storyboard> 
                                    </VisualState> 
                                    <VisualState x:Name="NotScrolling"> 
                                    </VisualState> 
                                </VisualStateGroup> 
                                <VisualStateGroup x:Name="VerticalCompression"> 
                                    <VisualState x:Name="NoVerticalCompression"/> 
                                    <VisualState x:Name="CompressionTop"/> 
                                    <VisualState x:Name="CompressionBottom"/> 
                                </VisualStateGroup> 
                                <VisualStateGroup x:Name="HorizontalCompression"> 
                                    <VisualState x:Name="NoHorizontalCompression"/> 
                                    <VisualState x:Name="CompressionLeft"/> 
                                    <VisualState x:Name="CompressionRight"/> 
                                </VisualStateGroup> 
                            </VisualStateManager.VisualStateGroups> 
                            <Grid Margin="{TemplateBinding Padding}"> 
                                <ScrollContentPresenter x:Name="ScrollContentPresenter" Content="{TemplateBinding Content}" 
ContentTemplate="{TemplateBinding ContentTemplate}"/> 
                                <ScrollBar x:Name="VerticalScrollBar" IsHitTestVisible="False" Height="Auto" Width="5" 
HorizontalAlignment="Right" VerticalAlignment="Stretch" Visibility="{TemplateBindingComputedVerticalScrollBarVisibility}" 
IsTabStop="False" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0" Value="{TemplateBindingVerticalOffset}" 
Orientation="Vertical" ViewportSize="{TemplateBinding ViewportHeight}" /> 
                                <ScrollBar x:Name="HorizontalScrollBar" IsHitTestVisible="False" Width="Auto" Height="5" 
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Visibility="{TemplateBindingComputedHorizontalScrollBarVisibility}" 
IsTabStop="False" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0" Value="{TemplateBindingHorizontalOffset}" 
Orientation="Horizontal" ViewportSize="{TemplateBinding ViewportWidth}" /> 
                            </Grid> 
                        </Border> 
                    </ControlTemplate> 
                </Setter.Value> 
            </Setter> 
        </Style>

If you compare this with the default style for ScrollViewer, you’ll see it’s really just the original PLUS the two additional VisualStateGroups.

As a reminder, the default style for each control can be found within the System.Windows.xaml file in the following location on a 64-bit machine: C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.1\Design\System.Windows.xaml

So the two additional VisualStateGroups are:

                                <VisualStateGroup x:Name="VerticalCompression"> 
                                    <VisualState x:Name="NoVerticalCompression"/> 
                                    <VisualState x:Name="CompressionTop"/> 
                                    <VisualState x:Name="CompressionBottom"/> 
                                </VisualStateGroup> 
                                <VisualStateGroup x:Name="HorizontalCompression"> 
                                    <VisualState x:Name="NoHorizontalCompression"/> 
                                    <VisualState x:Name="CompressionLeft"/> 
                                    <VisualState x:Name="CompressionRight"/> 
                                </VisualStateGroup>

The names are self explanatory; “CompressionLeft” means that the compression animation is happening on the ScrollViewer content towards the left side of the viewport.

There are eight combinations coming out of this: top, bottom, left, right, top-left (45 degree angle compression), top-right, bottom-left and bottom-right.

After overriding the default style, you can listen to the CurrentStateChanging event on the corresponding VisualStateGroup element.

To get to the ScrollViewer’s visual state group you need following (building on top of the standard WP7 project template):

private void MainPage_Loaded(objectsender, RoutedEventArgs e) 
     { 
         if(!App.ViewModel.IsDataLoaded) 
         { 
             App.ViewModel.LoadData(); 
         } 

         if(alreadyHookedScrollEvents) 
             return; 

         alreadyHookedScrollEvents = true; 
         MainListBox.AddHandler(ListBox.ManipulationCompletedEvent, (EventHandler<ManipulationCompletedEventArgs>)LB_ManipulationCompleted, true); 
         sb = (ScrollBar)FindElementRecursive(MainListBox, typeof(ScrollBar)); 
         sv = (ScrollViewer)FindElementRecursive(MainListBox, typeof(ScrollViewer)); 

         if(sv != null) 
         { 
             // Visual States are always on the first child of the control template 
            FrameworkElement element = VisualTreeHelper.GetChild(sv, 0) asFrameworkElement; 
             if(element != null) 
             { 
                 VisualStateGroup group = FindVisualState(element, "ScrollStates"); 
                 if(group != null) 
                 { 
                     group.CurrentStateChanging += newEventHandler<VisualStateChangedEventArgs>(group_CurrentStateChanging); 
                 } 
                 VisualStateGroup vgroup = FindVisualState(element, "VerticalCompression"); 
                 VisualStateGroup hgroup = FindVisualState(element, "HorizontalCompression"); 
                 if(vgroup != null) 
                 { 
                     vgroup.CurrentStateChanging += newEventHandler<VisualStateChangedEventArgs>(vgroup_CurrentStateChanging); 
                 } 
                 if(hgroup != null) 
                 { 
                     hgroup.CurrentStateChanging += newEventHandler<VisualStateChangedEventArgs>(hgroup_CurrentStateChanging); 
                 } 
             } 
         }           

     }
  private UIElement FindElementRecursive(FrameworkElement parent, Type targetType) 
       { 
           int childCount = VisualTreeHelper.GetChildrenCount(parent); 
           UIElement returnElement = null; 
           if (childCount > 0) 
           { 
               for (int i = 0; i < childCount; i++) 
               { 
                   Object element = VisualTreeHelper.GetChild(parent, i); 
                   if (element.GetType() == targetType) 
                   { 
                       return element as UIElement; 
                   } 
                   else 
                   { 
                       returnElement = FindElementRecursive(VisualTreeHelper.GetChild(parent, i) as FrameworkElement, targetType); 
                   } 
               } 
           } 
           return returnElement; 
       }
       private VisualStateGroup FindVisualState(FrameworkElement element, string name) 
       { 
           if (element == null) 
               return null; 

           IList groups = VisualStateManager.GetVisualStateGroups(element); 
           foreach (VisualStateGroup group in groups) 
               if (group.Name == name) 
                   return group; 

           return null; 
       }

This will be pretty easy to follow along with if you download and run the sample app. Let us know if this helps you complete your scrolling-related scenarios.

Other important points

  • VerticalCompression and HorizontalCompression VisualStateGroups are available ONLY for 7.1
  • Both are available ONLY for ManipulationMode = System,
  • These groups are not part of the default style, but are available to use.
  • You can read about Control Syles and Templates in detail here

Thanks !

SLMPerf

Loading Data when Scrolls to the End of List in WP7

by danielvaughan.org

Most phone users are concerned about network usage. Network traffic comes at a premium, and a user’s perception of the quality of your app depends a lot on its responsiveness. When it comes to fetching data from a network service, it should be done in the most efficient manner possible. Making the user wait while your app downloads giant reams of data doesn’t cut it. It should, instead, be done in bite-sized chunks.

To make this easy for you, I have created a ScrollViewerMonitor which uses an attached property to monitor a ListBox and fetch data as the user needs it. It’s as simple as adding an attached property to a control which contains a ScrollViewer, such as a ListBox, as shown in the following example:

<ListBox ItemsSource="{Binding Items}"
         u:ScrollViewerMonitor.AtEndCommand="{Binding FetchMoreDataCommand}" />

Notice the AtEndCommand. That’s an attached property that allows you to specify a command to be executed when the user scrolls to the end of the list. Easy huh! I’ll explain in a moment how this is accomplished, but first some background.

Background

For almost the last year, I’ve been building infrastructure for WP7 development. A lot has been going into the book I am writing, and even more is making its way into the upcoming Calcium for Windows Phone. I am pretty much at bursting point; wanting to get this stuff out there.

The chapter of Windows Phone 7 Unleashed, which discusses this code, demonstrates an Ebay search app that makes use of the Ebay OData feed (see Figure 1). It’s simple, yet shows off some really nice techniques for handling asynchronous network calls.

EbayApp

Figure 1: The Ebay Seach app from Windows Phone 7 Unleashed.

 

The Ebay app isn’t in the downloadable code for this post. But there is a simpler app that displays a list of numbers instead.

The way the ScrollViewerMonitor works is by retrieving the first child ScrollViewer control from its target (a ListBox in this case). It then listens to its VerticalOffset property for changes. When a change occurs, and the ScrollableHeight of the scrollViewer is the same as the VerticalOffset, the AtEndCommand is executed.

 

public class ScrollViewerMonitor
{
    public static DependencyProperty AtEndCommandProperty
        = DependencyProperty.RegisterAttached(
            "AtEndCommand", typeof(ICommand),
            typeof(ScrollViewerMonitor),
            new PropertyMetadata(OnAtEndCommandChanged));

    public static ICommand GetAtEndCommand(DependencyObject obj)
    {
        return (ICommand)obj.GetValue(AtEndCommandProperty);
    }

    public static void SetAtEndCommand(DependencyObject obj, ICommand value)
    {
        obj.SetValue(AtEndCommandProperty, value);
    }

    public static void OnAtEndCommandChanged(
        DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        FrameworkElement element = (FrameworkElement)d;
        if (element != null)
        {
            element.Loaded -= element_Loaded;
            element.Loaded += element_Loaded;
        }
    }

    static void element_Loaded(object sender, RoutedEventArgs e)
    {
        FrameworkElement element = (FrameworkElement)sender;
        element.Loaded -= element_Loaded;
        ScrollViewer scrollViewer = FindChildOfType<ScrollViewer>(element);
        if (scrollViewer == null)
        {
            throw new InvalidOperationException("ScrollViewer not found.");
        }

        var listener = new DependencyPropertyListener();
        listener.Changed
            += delegate
            {
                bool atBottom = scrollViewer.VerticalOffset
                                    >= scrollViewer.ScrollableHeight;

                if (atBottom)
                {
                    var atEnd = GetAtEndCommand(element);
                    if (atEnd != null)
                    {
                        atEnd.Execute(null);
                    }                    
                }
            };
        Binding binding = new Binding("VerticalOffset") { Source = scrollViewer };
        listener.Attach(scrollViewer, binding);
    }

    static T FindChildOfType<T>(DependencyObject root) where T : class
    {
        var queue = new Queue<DependencyObject>();
        queue.Enqueue(root);

        while (queue.Count > 0)
        {
            DependencyObject current = queue.Dequeue();
            for (int i = VisualTreeHelper.GetChildrenCount(current) - 1; 0 <= i; i--)
            {
                var child = VisualTreeHelper.GetChild(current, i);
                var typedChild = child as T;
                if (typedChild != null)
                {
                    return typedChild;
                }
                queue.Enqueue(child);
            }
        }
        return null;
    }
}

 

Of course there is a little hocus pocus that goes on behind the scenes. The VerticalOffset property is a dependency property, and to monitor it for changes I’ve borrowed some of Pete Blois‘s code, which allows us to track any dependency property for changes. This class is called BindingListener and is in the downloadable sample code.

Sample Code

The ViewModel for the MainPage contains a FetchMoreDataCommand. When executed, this command sets a Busy flag, and waits a little while, then adds some more items to the ObservableCollection that the ListBox in the view is data-bound too.

Snippet

public class MainPageViewModel : INotifyPropertyChanged
{
    public MainPageViewModel()
    {
        AddMoreItems();

        fetchMoreDataCommand = new DelegateCommand(
            obj =>
                {
                    if (busy)
                    {
                        return;
                    }
                    Busy = true;
                    ThreadPool.QueueUserWorkItem(
                        delegate
                        {
                            /* This is just to demonstrate a slow operation. */
                            Thread.Sleep(3000);
                            /* We invoke back to the UI thread. 
                                * Ordinarily this would be done 
                                * by the Calcium infrastructure automatically. */
                            Deployment.Current.Dispatcher.BeginInvoke(
                                delegate
                                {
                                    AddMoreItems();
                                    Busy = false;
                                });
                        });

            });
    }

    void AddMoreItems()
    {
        int start = items.Count;
        int end = start + 10;
        for (int i = start; i < end; i++)
        {
            items.Add("Item " + i);
        }
    }

    readonly DelegateCommand fetchMoreDataCommand;

    public ICommand FetchMoreDataCommand
    {
        get
        {
            return fetchMoreDataCommand;
        }
    }

    readonly ObservableCollection<string> items = new ObservableCollection<string>();

    public ObservableCollection<string> Items
    {
        get
        {
            return items;
        }
    }

    bool busy;

    public bool Busy
    {
        get
        {
            return busy;
        }
        set
        {
            if (busy == value)
            {
                return;
            }
            busy = value;
            OnPropertyChanged(new PropertyChangedEventArgs("Busy"));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        var tempEvent = PropertyChanged;
        if (tempEvent != null)
        {
            tempEvent(this, e);
        }
    }
}

 

There’s a lot more infrastructure provided with the book code. But I tried hard to slim everything down for this post. The MainPage.xaml contains a Grid with a ProgressBar, whose visbility depends on the Busy property of the viewmodel.

Snippet

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <ListBox ItemsSource="{Binding Items}"
                u:ScrollViewerMonitor.AtEndCommand="{Binding FetchMoreDataCommand}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <Image Source="Images/WindowsPhoneExpertsLogo.jpg" 
                            Margin="10" />
                    <TextBlock Text="{Binding}" 
                                Style="{StaticResource PhoneTextTitle2Style}"/>                            
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    <Grid Grid.Row="1"
            Visibility="{Binding Busy, 
                Converter={StaticResource BooleanToVisibilityConverter}}">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <TextBlock Text="Loading..." 
                    Style="{StaticResource LoadingStyle}"/>
        <ProgressBar IsIndeterminate="{Binding Busy}"
                        VerticalAlignment="Bottom"
                        Grid.Row="1" />
    </Grid>
</Grid>

 

You may be wondering why there is a databinding for ProgressBar’s IsIndeterminate property. This is for performance reasons, as when indeterminate the ProgressBar is notorious for consuming CPU. Check out Jeff Wilcox’s blog for a solution.

Now, when the user scrolls to the bottom of the list, the FetchMoreDataCommand is executed, providing an opportunity to call some network service asynchronously (see Figure 2).

ScrollMonitor

Figure 2: Loading message is displayed when the user scrolls to the end of the list.

 

I hope you enjoyed this post, and that you find the attached code useful.

If you are interested in up-to-the-minute WP7 info, check out the Windows Phone Experts group on LinkedIn.

 

DanielVaughan.ScrollViewerMonitor.zip (126.56 kb)