Ready to Use List Controls for WP8.1 WinRT

ReadyToUseListControls

I’m excited to announce that I will be making available a class library I’ve been developing and using personally in my work. I will be maintaining this library and adding new controls and components as I deem them stable enough for others to use. For the first release, there will only be three controls geared towards lists presentation but I think it will be helpful to a lot of WP WinRT devs out there nonetheless.

Download QKit

The class library is a toolkit that will augment your development experience by providing implementations for complicated or commonly used in-app experiences. This is not meant to replace any other toolkits out there but, rather, to complement them. This toolkit will be available via Nuget and it is currently limited to only Windows Phone’s WinRT platform. You can search for this toolkit under the name “QKit” or by running “Install-Package QKit” in the Nuget package manager console.

What’s Included?

ListPlaceholder

The first, and most simple of the controls that are available is the ListPlaceholder control. For a good user experience, an empty list should let the user know why it is empty using a short bit of text rather than a blank screen. Something like the following screenshot or the leading image:

NativeListPlaceholder

With the ListPlaceholder control, you can place it anywhere on page (I recommend underneath the ListView or GridView you want it to work against in the same container) and point it to a ListViewBase control.

For example, let’s say I have a completed ListView. Naturally, it’s sitting in some panel. For my case, it’s in a Grid.

<Grid>
    <ListView x:Name="MyList" />
</Grid>

The first thing we need to do is drop in our new ListPlaceholder control and then point the ListPlaceholder control to the list we want to show and hide against when it’s empty.

<Grid>
    <q:ListPlaceholder ListTarget="{Binding ElementName=MyList}" />
    <ListView x:Name="MyList" />
</Grid>

Don’t forget to add the namespace for QKit in order to use this control. I’ve added it as “q” for brevity.

<Page ...
      xmlns:q="using:QKit">
      ...
</Page>

By default, the ListPlaceholder control will show a “Loading…” message when ItemsSource of the list is null and a “Nothing to show” message when ItemsSource is not null but the list is still empty. You can change these two messages using the LoadingPlaceholderContent and the EmptyPlaceholderContent properties to show custom messages or even custom displays using their corresponding template properties. Let’s see how we can set it to show our own custom message when the list is empty.

<Grid>
    <q:ListPlaceholder ListTarget="{Binding ElementName=MyList}"
                       LoadingPlaceholderContent="Looking for stuff, hang tight..."
                       EmptyPlaceholderContent="Nothing to see here... move along." />
    <ListView x:Name="MyList" />
</Grid>

Finally, if you don’t want the control to automatically decide which content to show (loading vs empty), you can set or bind the PlaceholderMode property to manually tell it which to show when the list is empty.

GenericJumpList + AlphaJumpList

By now, we should be accustomed to implementation of SemanticZoom to create a JumpList in WP8.1. However, our implementation can get cumbersome and complicated because it’s composed of many different parts. Furthermore, our latest attempt at making the perfect JumpList came a little short since the AlphaJumpList still doesn’t work properly in landscape orientation. Well, I’m happy to say that all of our woes are now solved with my new GenericJumpList and AlphaJumpList controls.

LandscapeAlphaPicker

Why should you migrate over to these controls rather than using the SemanticZoom/ListView combo? I’ve already mentioned the first reason and that reason was that it now works in landscape without any additional work after dropping it in and wiring it up. The next reason is because, now, the controls are a simple drop in and wraps around any standard ListView or GridView to turn it into a JumpList. This lets anyone convert existing lists in their apps to JumpList should they feel like it’s appropriate to do so. The last reason is because these two controls have performance considerations built in. I’ve included any required performance improvements needed for conventional usage.

Enough talk, let’s see how we can incorporate these controls into our existing lists. Let’s go back to our simple list example:

<Grid>
    <ListView x:Name="MyList"
              ItemsSource="{Binding MyItems}" />
</Grid>

Currently it’s just a ListView with its ItemsSource bound to a flat list. The first thing you need to do is group the items so it’s no longer a flat list. This is easy since the JumpListHelper class is included in QKit.

// Using extension method
var MyGroupedItems = MyItems.ToAlphaGroups(x => x.DisplayValue);

// or using static method
var MyGroupedItems = JumpListHelper.ToAlphaGroups(MyItems, x => x.DisplayValue);

The helper class will spit back a list of JumpListGroups that is compatible with the Generic and AlphaJumpLists. For demonstration purposes, I’ll expose the grouped items as a different property but you can just return the list of JumpListGroups in place of your flat list. Note that the grouped items no longer have to be in a CollectionViewSource. The JumpList controls will take care of that for you. Just a list of JumpListGroups is enough.

<Grid>
    <ListView x:Name="MyList"
              ItemsSource="{Binding MyGroupedItems}" />
</Grid>

Now, the last step is to simply wrap the ListView or GridView control with a JumpList control. That’s it. The control will take care of the rest.

<Grid>
    <q:AlphaJumpList>
        <ListView x:Name="MyList"
                  ItemsSource="{Binding MyGroupedItems}" />
    </q:AlphaJumpList>
</Grid>

Without going into too much detail, the JumpList controls pretty much hijacks the ItemsSource of the ListView and calls it its own. From there, it wraps that ItemSource into a CollectionViewSource automatically if it’s not already, and then modifies the ListView to look at CollectionViewSource and adds the appropriate group styles. Of course the JumpList controls automatically handles the SemanticZoom stuff so we don’t have to anymore.

Note: If the child ListViewBase’s ItemsSource is being set programmatically rather than through data binding, you need to call the ReleaseItemsSource method before setting the ListViewBase’s ItemsSource, and the ApplyItemsSource method after setting the ListViewBase’s ItemsSource on the JumpList control.

Why?

A few questions people might have that I want to address.

Q: First, why are you doing this?

A: Well, people have been having issues or missing certain steps when implementing my tutorial for JumpLists. I do not blame anyone. It is kind of complicated especially when you have to implement it over several areas or several apps. Also, packaging it into a class library lets me make it more complicated behind the scenes without hindering any developers while addressing issues like the orientation limitation.

Q: Why do the GenericJumpList and AlphaJumpList controls need a ListViewBase as a content rather having it built in as part of the control like LongListSelector in SL8.0?

A: This one was tough because I wanted to do something like the LongListSelector but I didn’t want to reimplement all of the events and properties of a ListViewBase like ItemClick or ItemTemplate. If I had derived from ListViewBase, I wouldn’t have to do that but then I couldn’t use a SemanticZoom control and a SemanticZoom is needed to create a JumpList experience. My solution was to let developers design using a ListView or GridView since they are probably comfortable and well versed in doing that. Then, let developers just wrap those ListViews and GridViews with my control for minimal code change. This also has the added benefit of exposing the ListViews and GridViews for events and property modifications and it even works with the ListPlaceholder control!

Q: Can I change the looks of the control?

A: Yes, they are templated custom controls. I’ve included the Generic.xaml file so you can peruse the styles and templates being used so you can adapt them to make it your own. I do have to say that I’ve spent many hours styling these controls to look as correct as possible so consider leaving them be if you want your app to look clean and proper.

Q: What if it breaks or doesn’t work with my code?

A: Well, you’re free to contact me either on this post or reach out to me at QDev@live.com for to notify me of any bugs but since this is a side project, I cannot guarantee timeliness in any fixes. I will eventually making the source code available so anyone can modify the code and fix any issues for themselves in their personal uses.

Advertisements

15 thoughts on “Ready to Use List Controls for WP8.1 WinRT

    1. Interesting. My JumpList controls use the SemanticZoom underneath. I’ll have to look into this to see why my controls do not have issue (or try solve it if it does).

  1. Hey

    first of all: thanks for your qkit! Just integrated it into one of my apps and its really easy to use and looks great so far =)
    I have problems where you might be able to help me:

    1. As far as I see I can’t add the qkit to a windows 8.1 project. Is that right or did I miss something? If so, it would be really great if you could add this compatiblity as well to support universal apps =)

    2. Is it possible that the generic jumplist will activate the SelectionChanged event? I had some issues with this. The problem was that after / while the loading of the page, the selectionChanged event was triggered with the first item selected. This tried to cause a navigation and since that wasn’t possible cause the page wasn’t finished loaded it caused pretty strange behaviors ^^
    As a work around I removed the selection Changed event handler. As a second monkey patch I might add some additional filters so that the code don’t get executed if the page isn’t rendered or so. But thought I tell you about this in case you now an easy way how to fix this =)

    Regards
    Nino

    1. 1. Yes unfortunately I did not make it available for Windows 8.1 WinRT. The reason for that is simply because I didn’t get around to coming up with the proper styles and templates that matches Windows yet. My focus is currently on WP since I believe the UX choices made by the team behind the phone OS were actually very smart and well thought out. I can’t particularly praise the same for the Windows version but I will get to it once I have some free time. In the meantime, the source code is available for download so you can build a version for Windows 8.1 if you need to. The only thing you’d have to worry about is creating the equivalent styles and templates. Also the MultiSelectListView won’t work without change since ListView’s multiselection properties are different between the phone and desktop version. Then again, Windows 8.1 doesn’t have the left edge selection ability… so there’s no need to include this except on phone versions.

      2. It’s very possible. There’s some weird ItemsSource juggling that it does to allows the JumpList controls to be so easy to use by devs. I haven’t tested for this so I’ll have to take a look when I get home tonight or when I’m able to next. However, if you’re trying to navigate to page after a user has tapped a single item, you should probably use the ItemClick event instead. This is what I use with my JumpLists and it causes no issues. You do need set IsItemClickEnabled to true and the ItemClickEventArgs.ClickedItem value it passes is actually the data of the tapped item rather than the visual container that you have to process.

  2. Hi, Thank you for the toolkit, it works very well. I ran into a small problem…My requirement is that when the user enters the page, the list is displayed in zoomed out state. How can I toggle active view in AlphaJumpList programatically? I’m looking for something like ToggleActiveView method on SemanticZoom control…. Is there any way to do this?

    Thank you,
    Jakub

    1. Currently, not easily. I think you can traverse the visual tree to obtain the SemanticZoom component of the control and then toggle the zoom view state but obviously it wouldn’t be ideal especially in MVVM. I will add either a method or a property to programmatically change the view in a future update.

  3. Hello, I am looking for a way to reverse the list of collection

    I am using this method :

    data = JumpListHelper.ToGroups(items,x => x.Book, x => x.FinishListened.Date);

    is it possible to reverse the list?
    thank you

    1. Reverse the list of groups? Or do you mean reverse the items in each group? Regardless, the result of the ToGroups method is just a list of lists so you can modify them as you please after the grouping is done. So if you want to reverse the list, I’m pretty sure you can just do a LINQ reverse on it: data.Reverse() or do the same by looping through each item in data (each item in data is a group).

  4. Does this control use any kind of virtualization? I have been using vanilla SementicZoom and ListView combo for my apps. But apparently, grouped data isn’t virtualized.

    1. I may be wrong but as far as I can see, even grouped ListViews are virtualized in WP8.1 so long as you don’t mess with the ItemsPanel property or during retemplating. I’m not sure about big Windows 8/8.1 though. What kind of scenario/issues are you seeing? Are you on the phone or pc? Are you on 8.0 or 8.1 if you’re on pc? Did you modify the template of the ListView?

      1. My issue is mainly on Windows Phone 8.1 (Universal) side. According to this thing on MSDN, virtualization is not supported for the grouped data. https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh780657.aspx?f=255&MSPPError=-2147217396
        The article doesn’t make it clear whether it applies to WP, though.
        And no, I’m not templating anything except the ItemTemplate. You can take a look at source code here: https://github.com/akshay2000/XBMCRemoteRT/blob/master/XBMCRemoteRT/XBMCRemoteRT.WindowsPhone/Pages/Audio/AllMusicPivot.xaml
        If the controls are indeed virtualized, then the problem must be with the how data is being loaded. I’m looking into that too.

      2. As far as I can tell, it should be virtualized even when grouped. Using a grouped ListView, I hooked up a ContainerContentChanging event handler and I can see it being triggered when scrolling down as well as up. This event happens when a container is being used for a new item coming into view that needs to be loaded to the UI. What I’m seeing is items are being reloaded into the UI if I return to them after scrolling far enough away. Behaves like UI virtualization to me.

        The link you provided looks a little out of date. I can confirm what that link says is completely true during the Windows 8.0 days with the mentioned VirtualizingStackPanel but in 8.1 (pc and phone), the default panel for ListViews have been changed to the newer ItemsStackpanel. This new panel is virtualized as well and I have a hunch that it NOW works with groups. Again, I may have to look into this further.

        How big of a data set are you using? I’m testing with roughly 700 items with imagery.

  5. Thanks for putting so much effort in that. I am loading 4000ish items. Some with images, some without. But the data is being loaded over network. So, maybe that huge network request is crashing the app. I’ll debug more and report back.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s