,

Marketplace App List Sample

The built-in Marketplace app presents apps in a flat list. This example groups a set of mock items using a LongListSelector.

The custom MarketplaceApp class defines an app as having a name, description, image, price, and marketplace category. The marketplace category and its price are used to group a list of randomly generated MarketplaceApp objects. First, the example briefly looks at the MarketplaceApp class and how to generate a list of MarketplaceApp objects; this will increase your understanding as you move further through the example.

MarketplaceApp defines an array of hard-coded categories and prices. The array of category names is called categories, and is defined as follows:

static readonly string[] categories
    = { "Games", "Photo", "Social", "Business", "Tools", "Travel" };

The array of prices is defined as shown:

static readonly double[] prices
    = { 0.99, 1.99, 2.99, 5.99 };

A category and price are randomly selected for each new MarketplaceApp using a System.Random.

The MarketplaceApp class includes a static method called CreateRandomApp that instantiates a MarketplaceApp and populates it with random data. The LoremIpsumGenerator class, borrowed from the Toolkit examples, produces random text. The LoremIpsumGenerator code is not covered in this book, but the code is available in the downloadable sample code for this book.

public static MarketplaceApp CreateRandomApp()
{
    string name = LoremIpsumGenerator.GetWords(
                    random.Next(1, 5),
                    LoremIpsumGenerator.Capitalization.AllWords);
    string description = LoremIpsumGenerator.GetParagraph(random.Next(3, 7));
    string category = categories[random.Next(6)];
    double price = prices[random.Next(4)];
    MarketplaceApp result = new MarketplaceApp(
        name, description, category, price,
        "/ControlExamples/LongListSelector/MarketplaceAppList
            /Images/MarketplaceAppIcon.png");
    return result;
}

To generate more than one MarketplaceApp object at a time, another static method called CreateRandomApps accepts an integer value and returns the specified number of instances. Although fairly arbitrary, this method is shown in the following excerpt because it is referred to later in this section:

public static IEnumerable<MarketplaceApp> CreateRandomApps(int numberToCreate)
{
    ArgumentValidator.AssertGreaterThan(0, numberToCreate, "numberToCreate");
    for (int i = 0; i < numberToCreate; i++)
    {
        yield return CreateRandomApp();
    }
}

The viewmodel for this sample is called AppListViewModel. It contains a list of grouped MarketplaceApp objects.

When presenting grouped items, the LongListSelector depends on each item in the source collection implementing IEnumerable<TItem>. You could, therefore, place each MarketplaceApp object in a List<MarketplaceApp>, and the LongListSelector would happily display them. However, doing so would not provide a means of displaying a group title for each group within the LongListSelector; you need a way to associate a name with each group. For this we turn to the System.Linq.IGrouping interface. The IGrouping interface has just what you need; it is IEnumerable<TItem> and contains a Key property that you can use as each group’s title by binding to it in XAML (see Figure 10.3).

Image

FIGURE 10.3 The IGrouping<TKey, TElement> interface extends IEnumerable interfaces.

The sample contains an implementation of IGrouping called CustomGrouping (see Listing 10.2). Rather than passing through a generic attribute for the IGrouping TKey attribute, the key type is defined as object to allow greater flexibility when switching collections within the viewmodel.

LISTING 10.2. CustomGrouping Class


public class CustomGrouping<TElement> : List<TElement>, IGrouping<object, TElement>
{
    readonly object key;

    public CustomGrouping(object key, IEnumerable<TElement> items)
    {
        this.key = ArgumentValidator.AssertNotNull(key, "key");
        AddRange(ArgumentValidator.AssertNotNull(items, "items"));
    }

    public object Key
    {
        get
        {
            return key;
        }
    }

    public bool HasItems
    {
        get
        {
            return items.Any();
        }
    }

    public override bool Equals(object obj)
    {
        var otherGrouping = obj as CustomGrouping<TElement>;
        return otherGrouping != null && Key.Equals(otherGrouping.Key);
    }

    public override int GetHashCode()
    {
        return Key.GetHashCode();
    }
}


The AppListViewModel contains a list of CustomGrouping objects, as shown:

IEnumerable<CustomGrouping<MarketplaceApp>> appGroupings;

public IEnumerable<CustomGrouping<MarketplaceApp>> AppGroupings
{
    get
    {
        return appGroupings;
    }
    private set
    {
        Assign(ref appGroupings, value);
    }
}

LINQ is used to populate AppGroupings. The MarketplaceApp.CreateRandomApps method generates many MarketplaceApp objects, which are then grouped by the MarketplaceApp.Category property, as shown:

void GroupByCategory()
{
    AppGroupings = (from app in MarketplaceApp.CreateRandomApps(appCount)
            group app by app.Category into grouping
            select new CustomGrouping<MarketplaceApp>(
                 grouping.Key, grouping.AsEnumerable())).ToList();
}


Note

Conversion of the resulting IEnumerable<T> to a List<T> is done to avoid deferred execution, which would otherwise produce incorrect ordering and behavior.


The viewmodel allows the marketplace apps to be sorted either by category or by price. When sorted by price, the LINQ expression relies on the fact that the CustomGrouping.Key property is of type object, allowing you to reassign the AppGrouping property despite using the MarketplaceApp.Price property, which is of a different type to the MarketplaceApp.Category.

Grouping items by price is performed by the GroupByPrice method, as shown in the following excerpt:

void GroupByPrice()
{
    AppGroupings = (from app in MarketplaceApp.CreateRandomApps(appCount)
            group app by app.Price into grouping orderby grouping.Key
            select new CustomGrouping<MarketplaceApp>(
                grouping.Key, grouping.AsEnumerable())).ToList();
}

To allow the user to specify how items are grouped, the viewmodel includes a list of valid AppGroups:

readonly static IEnumerable<AppGroup> appGroups = new List<AppGroup>
                                            {
                                                AppGroup.Category,
                                                AppGroup.Price
                                            };

public IEnumerable<AppGroup> AppGroups
{
    get
    {
        return appGroups;
    }
}

How the items are grouped is determined by the viewmodel’s GroupBy property. In the following excerpt, if the base class Assign method succeeds in setting the field value, then depending on the new value, the GroupByPrice or GroupByCategory method is called:

AppGroup groupBy = appGroups.First();

public AppGroup GroupBy
{
    get
    {
        return groupBy;
    }
    set
    {
        if (Assign(ref groupBy, value) == AssignmentResult.Success)
        {
            switch (value)
            {
                case AppGroup.Price:
                    GroupByPrice();
                    break;
                default:
                    GroupByCategory();
                    break;
            }
        }

    }
}

For more information regarding the custom ViewModelBase.Assign method, see Chapter 2, “Fundamental Concepts in Windows Phone Development.”

The view XAML contains a ListPicker that allows the user to switch how items are grouped. The ListPicker’s ItemsSource property is bound to the viewmodel’s AppGroups property. The ListPicker.SelectedItem property has a two way data binding to the viewmodel’s GroupBy property:

<toolkit:ListPicker
    Header="group by"
    ItemsSource="{Binding AppGroups}"
    SelectedItem="{Binding GroupBy, Mode=TwoWay}" />

When the user selects an item from the ListPicker, the viewmodel’s GroupBy property is updated, which in turn calls one of the group by methods (see Figure 10.4).

Image

FIGURE 10.4 The group by property is able to be changed via a ListPicker.

The LongListSelector.ItemsSource property is bound to the AppGroupings property of the viewmodel.

The LongListSelector includes a ListHeader, GroupHeaderTemplate, JumpListStyle, and an ItemTemplate. The ItemTemplate presents each MarketplaceApp object. See the following excerpt:

<phone:LongListSelector
        ItemsSource="{Binding AppGroupings}"
        IsGroupingEnabled="True"
        Grid.Row="1">
    <phone:LongListSelector.ListHeader>
        <TextBlock Text="latest apps"
                    Style="{StaticResource PhoneTextTitle1Style}"/>
    </phone:LongListSelector.ListHeader>

    <phone:LongListSelector.GroupHeaderTemplate>
        <DataTemplate>
            <Border Background="{StaticResource PhoneAccentBrush}"
                    Margin="{StaticResource PhoneTouchTargetOverhang}"
                    Padding="{StaticResource PhoneTouchTargetOverhang}">
                <TextBlock Text="{Binding Key}"
                           Style="{StaticResource PhoneTextTitle2Style}"/>
            </Border>
        </DataTemplate>
    </phone:LongListSelector.GroupHeaderTemplate>

    <phone:LongListSelector.JumpListStyle>
        <Style TargetType="phone:LongListSelector">
            <Setter Property="LayoutMode" Value="List" />
            <Setter Property="ItemTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <Border Background="{StaticResource PhoneAccentBrush}"
                           Margin="{StaticResource PhoneTouchTargetOverhang}"
                           Padding="{StaticResource PhoneTouchTargetOverhang}">
                            <TextBlock Text="{Binding Key}"
                                 Style="{StaticResource PhoneTextLargeStyle}"/>
                        </Border>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </phone:LongListSelector.JumpListStyle>

    <phone:LongListSelector.ItemTemplate>
        <DataTemplate>
            <Grid Margin="{StaticResource PhoneTouchTargetOverhang}">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Image Source="{Binding ImageUrl}"
                        Width="110" Height="150"
                        VerticalAlignment="Top"/>
                <StackPanel Grid.Column="1" VerticalAlignment="Top">
                    <TextBlock Text="{Binding Name}"
                                Style="{StaticResource PhoneTextLargeStyle}"
                      FontFamily="{StaticResource PhoneFontFamilySemiBold}"
                                TextWrapping="Wrap" Margin="12,-12,12,6" />
                    <TextBlock Text="{Binding Description}"
                                Style="{StaticResource PhoneTextNormalStyle}"
                                TextWrapping="Wrap"
                       FontFamily="{StaticResource PhoneFontFamilySemiLight}"/>
                </StackPanel>
            </Grid>
        </DataTemplate>
    </phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>


Note

When the LongListSelector resided in the Silverlight Toolkit, it included a GroupItemTemplate property. This has since been superseded by the JumpListStyle property.


When the user taps a group header, each grouping key is presented using the ItemTemplate property of the long list selector’s JumpListStyle. With Category selected as the group by property, each category is presented, allowing the user to jump to a specific category (see Figure 10.5).

Image

FIGURE 10.5 LongListSelector displaying the group picker when grouped by category.

With price selected as the group by property, the groups are presented from lowest to highest (see Figure 10.6). Tapping on a price takes the user to the list of apps of that price.

Image

FIGURE 10.6 LongListSelector displaying the group picker when grouped by price.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.149.235.63