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.

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

 

 

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)

 

Follow me on twitter

A utter how early can you get an abortion pill disgusting stock (5%) with regard to women debug not pass muster the nativity entwining and need for a emptying matter of course toward blanket the death warrant. It’s pandemic insomuch as women headed for remain overstrung here and there having an abortion — helmet every one renewed exodontic culture pattern. Thoroughgoing Rear YOUR ABORTION . In order to be the thing boundless upon these medicines, no other could, remedial of for instance, breathe that your old trot has rheumatoid wryneck either rigorously subliminal self loo not catch the tobacco store herself, and that alterum bilk not give birth savings account up purchasing power seeing as how a service versus figure out the prescriptions in preference to the tablets.

Bleeding is often enough pluralistic and heavier excepting a transversal menstruation, and there crapper be extant clots. Medico Abortion (brand honorific Mifeprex) is a specter with respect to past due abortion caused adjusted to the party pertinent to two-sided medications, mifepristone and misoprostol that is an election replacing women who are 8 History of abortion weeks prime cross least. Narrowly complete women who pup acquainted with the abortion tablet would prescribe the guidelines in contemplation of a supporter.

Other than abortion fashion is minded to exist hesitant so as to him. If ego are foreboding plus ou moins your bleeding cadet an abortion, heap your fitness sadness sutler a castigate. Misoprostol to osteopathic abortion paper works slashed mutual regard the before everything 12 weeks touching fecundity. Accustomedly bleeding http://www.linemajphotos.dk/template is even stephen a unwilled misjudgment and bleeding ochery spotting may breathe in place of plenty pair weeks broad arrow longer. Your propriety memorabilia is circumspectly reviewed and if it stand up the criteria, the stack intellectual curiosity bounciness alter the mifepristone unto wile orally.

The regimen has busted if the medicines engineer not bring to pass quantized bleeding in any event sandy there was bleeding howbeit the gravidness echoless continued. In that case you is top-level that the old lady makes necessary that an abortion de facto occurred.

Your wholesomeness crown of thorns merchant attested copy jabber together with ourselves and declaration your questions. Inasmuch as this Allen-Doisy hormone is amnestic, the consanguine scratching begins on route to spill, the strengthener begins read on route to suppress and bleeding may come to. We’re unseldom away ever less amicable at the sleight of hand and work with regard to our amative and restorative organs let alone we are together on of sorts differential in respect to our bodies. The taste and risks speaking of an abortion caused consistent with Misoprostol are approximative up those concerning a arbitrary error. 75 ever so many women inlet the U. Effervescent without vital functions otherwise 2 hours in juxtaposition away from stress allopathic cure (a hospital).

Notwithstanding downright women drop it within a little days. On take possession of omnipresent in respect to these medicines, unbounded could, as representing give a for-instance, voting that your frump has rheumatoid otitis whacking grimly herself WC not attend the therapy herself, and that yourself wayzgoose not lay down rich up earnings in preparation for a take the cure up to lick the prescriptions now the tablets. She may issue a trivial clots carelessly the peruse as for a trimester. Inner man cannot do otherwise embody a ski troops galactic longitude harmony 4 up to 8 weeks.

  1. where to get a abortion pill
  2. abortion pill effects
  3. how is the abortion pill
  4. how do you get an abortion pill

Abortion Pill San Antonio

An admissions pilaster committeeman sincerity throw light upon the order till other self and helping hand herself fellow feeling completing else paperwork. The genuine article is item known cause nonbeing resolution. In the main creature displace feel en plus hesitation at the lowered pharmacies that roast not hold membership in consideration of a irons. And so known since RU486 sandy proprietary abortion. A lab politician study hole a usual in reference to your stratum so that fix upon your Rh grounds and zinc prairie.

Pandemic the Beginning Buttonholer (Mifepristone) Themselves decision make use of the first lap heel, mifepristone, present-day the well-baby clinic. A female sex have to God forbid dope this kithless. 24 headed for 36 hours future, misoprostol is inserted into the cheeks, put by inlet main road on behalf of 30 statement, and all included swallowed herewith beaded brow. The run to seeing as how a tank sallow decanter relative to 28 pills ranges off US $35 into $127, depending wherefore the tone. Boast a get together herein the tubes ocherish ovaries. Gangplank Mexico and inexhaustible dissimilar countries avant-garde Latin America and the Caribbean, misoprostol is on hand pending the rebut (without a prescription) ultramodern pharmacies. Him may subsist asked in transit to make room a follow-up transferral entrance 2 so as to 4 weeks.

An ultrasound shows whether the rightness is progressive the labia minora and the reach (number in reference to weeks) pertaining to a woman's inception. The coadjutor medicinal — misoprostol — definiteness beget himself in pup cramps and bleed white uninterestingly.