Windows 8’s ComboBox and the CarouselPanel

By | April 12, 2013

Something you may or may not have noticed in your Windows 8 development is that the ComboBox uses a pretty interesting control new to Windows 8, the CarouselPanel.

What the CarouselPanel brings to us is the ability to, as the name suggests, roll continuously through the list of items, looping back to the beginning or end as you go forward or backward (respectively). It’s a pretty neat trick with one little annoyance (in my opinion): it doesn’t behave this way everywhere. In addition, I had a client recently to actually wrote it up as a bug and made me come up with a way to get rid of it. I’m sure I’m not alone here, and finding the solution involved a lot of Binging, but in the end it was me poking around and figuring it all out on my own as nobody had a really straightforward solution.

Here is the problem, illustrated. Using the following snippet of code in page:

            <ComboBox Height="32"
                      Margin="100">
                <TextBlock Text="one"
                           Margin="10" />
                <TextBlock Text="two"
                           Margin="10" />
                <TextBlock Text="three"
                           Margin="10" />
                <TextBlock Text="four"
                           Margin="10" />
                <TextBlock Text="five"
                           Margin="10" />
                <TextBlock Text="six"
                           Margin="10" />
                <TextBlock Text="seven"
                           Margin="10" />
                <TextBlock Text="eight"
                           Margin="10" />
                <TextBlock Text="nine"
                           Margin="10" />
                <TextBlock Text="ten"
                           Margin="10" />
                <TextBlock Text="eleven"
                           Margin="10" />
            </ComboBox>

You can pop open the simulator and hit the ‘Basic touch mode’ button on the toolbar to see:

image

Touch-mode: Combobox listing wraps due to CarouselPanel

then tap out of the combobox and switch to ‘Mouse mode’, click the Combobox and you’ll be met with:

image

Mouse-mode (non-touch-enabled): Combobox has “normal” behavior due to CarouselPanel

Rather than attempt to convince the client that this is for ease of use of a touch interface – since they weren’t even familiar with Windows 8 to begin with – I took it upon myself to make scenario #2 happen outright, all the time.

Let’s have a look at the relevant part of the ComboBox default template as defined by MSDN:

    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <CarouselPanel />
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>

Herein lies the culprit. The ItemsPanelTemplate explicitly says that it should use a CarouselPanel to do its job. We need to get that outta there.

If you know about XAML and Control styling, then you probably already know where I’m going with this. But for those of you that don’t, here’s how I went about it:

            <ComboBox Height="32"
                      Margin="100">
                <ComboBox.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Vertical" />
                    </ItemsPanelTemplate>
                </ComboBox.ItemsPanel>
            </ComboBox>

As you can see what this does is replaces the ItemsPanel’s CarouselPanel with a normal, everyday, StackPanel. Resulting in the following display in touch mode:

image

Touch-mode: CarouselPanel removed from ComboBox, replaced with StackPanel, no longer wraps

And voila! You’ve got the same experience on touch devices as you do on non-touch ones. For better or worse.

It is worth noting that one caveat I’ve found to this implementation is that you lose inertia within the scroll area. This means there’s no “flicking” to get to the first or last element as there is in the standard ComboBox implementation (using a CarouselPanel) on a touch-enabled device.

If you are able to get inertia built in to this (i.e.: smarter than me) then please pass on your solution!