PETZOLD BOOK BLOG

Charles Petzold on writing books, reading books, and exercising the internal UTM


Recent Entries
< PreviousBrowse the ArchivesNext >
Subscribe to the RSS Feed

Orientation Strategies for Windows Phone 7

June 16, 2010
Roscoe, N.Y.

I've recently been thinking about ways to deal with orientation changes in Windows Phone 7. (That's when the user turns the phone sideways from portrait mode to landscape mode or back again.) I've also been working on the way-overlong chapter on data binding in my forthcoming book Programming Windows Phone 7, and it occurred to me that I might deal with orientation using data binding and data conversion techniques.

The sample program I'll be discussing is called ColorScroll, and it goes way back. The first version was named COLORSCR and appeared in the May 1987 issue of Microsoft Systems Journal (which later became MSDN Magazine):

This first version of the program implemented a rather crude (and heavily arithmetic) version of dynamic layout. To quote the article, "Whenever you resize the COLORSCR window, the sizes of the child windows change proportionally. This is particularly interesting for the scroll bars. Depending on the dimensions of COLORSCR's window, the scroll bars can be long and thin or short and stubby.

By the time I adapted the program for the Windows Presentation Foundation in my book Applications = Code + Markup, the dynamic layout was handled in the environment, but for a few brief moments I was hoping to implement the entire program in XAML using data bindings. Simple, right? First, give each ScrollBar a name, like so:

<ScrollBar Name=redScrollBar ... />

Then define a binding to the appropriate property of the Color object of the SolidColorBrush used to display the resultant color:

<SolidColorBrush>
    <SolidColorBrush.Color>
        <Color R="{Binding ElementName=redScrollBar, Path=Value} ... />
    </SolidColorBrush.Color>
</SolidColorBrush>

Well that won't work. As we all know, the targets of data bindings must be dependency objects, so let's instead give the Color object a name:

<Color x:Name="color" />

And now define a binding on the ScrollBar that flips the data back to the binding source:

<ScrollBar Value="{Binding ElementName=color, Path=R, Mode=OneWayToSource}" ... />

And the problem with that is the Color structure, which provides no notification mechanism so nobody knows when one of its properties is changed. To make this work, I had to supply some code in the form of an IMultiValueConverter class that converted the red, green, and blue values from the ScrollBar into a single Color or SolidColorBrush. Although the program couldn't be done entirely in XAML, it redeemed itself by becoming a great example for WPF multibinding!

In the Silverlight book that no publisher ever asked me to write, I wasn't able to use a multibinding because Silverlight doesn't support them. Instead, I created a chunk of code I sometimes think of as a "binding server" — a class (called RgbColor in this case) that implements INotifyPropertyChanged and which exists solely to be accessed through data bindings and assist XAML with some crunching. Here's the ColorScroll for Silverlight source code from that hypothetical book, or just play with the program right here:

Get Microsoft Silverlight

This program uses two features new in Silverlight 4: implicit styles and the always handy StringFormat option on Binding. Notice I've switched from ScrollBar controls to Slider, primarily because the Slider works better with keyboard navigation in Silverlight and it doesn't get as wide as its container.

When I started porting this program to Silverlight for Windows Phone (which doesn't support either of those two new Silverlight 4 featues), I immediately ran into a problem that never existed before. With Windows Phone 7 we're dealing with a fixed-size screen, and I thought the Slider controls should be positioned at the top like this:

Now what happens when the user tips the phone sideways? You have a couple choices. If you leave the SupportedOrientations property of PhoneApplicationPage to its default value, then your display doesn't change:

This seemed unsatisfactory to me because the text labels and — worse — the hexadecimal values are now sideways. Surely I want to set SupportedOrientations to support both Portrait and Landscape modes. But now look what happens:

For the Silverlight program, changing phone orientation is just like changing a window size. All the controls and panels adjust to the new size. But that's not what I wanted. What I really wanted was for everything to stay in approximately the same place:

And so I asked myself? What do I need to do to make this happen?

Well, one solution is simply to have parallel page definitions for portrait and landscape. But that seemed to me not the best solution. I wanted a single chunk of markup for both configurations. So certain things have to happen. For example, the Slider controls need to change from a horizonal orientation to a vertical orientation when the MainPage changes from a portrait to a landscape mode. To me, this implied a data binding. I gave the MainPage a name of this (a common technique when doing ElementName bindings in WPF and which I'm sure will become popular in Silverlight):

<phoneNavigation:PhoneApplicationPage 
        ...
        Name="this">

The PhoneApplicationPage has a property named Orientation that indicates if the orientation of the phone is portrait or landscape, and which way it's tilted. I bound this property to the Orientation property of the Slider with a converter:

<Slider ...
        Orientation="{Binding ElementName=this, 
                              Path=Orientation, 
                              Converter={StaticResource orientationConverter},
                              ConverterParameter=False}" />

The PageOrientationToOrientation class referenced by that StaticResource converts the Orientation property of the PhoneApplicationPage to the Orientation property of the Slider. Here's the Convert method:

public object Convert(object value, Type targetType,
                        object parameter, CultureInfo culture)
{
    bool isAligned = true;

    if (parameter is string)
        Boolean.TryParse(parameter as string, out isAligned);

    bool isPortrait = ((PageOrientation)value & PageOrientation.Portrait) != 0;

    return isAligned ^ isPortrait ? Orientation.Horizontal : Orientation.Vertical;
}

I figured the common case would be Portrait mode converted to Vertical orientation, so that's what happens by default. Use a converter parameter of "False" to switch it as in this program.

I also wanted to switch the direction of the sliders when the phone was in landscape mode so another converter handled that:

<Slider ...
    IsDirectionReversed="{Binding ElementName=this,
                              Path=Orientation,
                              Converter={StaticResource isLandscapeConverter}}"
        ... />

Of course the elephant in the room is the Grid. When the phone changes orientation, I want the Grid to basically swap all its rows and columns. Whatever was a RowDefinition now becomes a ColumnDefinition, and vice versa, and whatever was a Grid.Row attached property becomes and Grid.Column attached property. For some simple grids, I've seen this done in code but I wanted a more automated general-purpose solution. (The less code in the code-behind, the happier I am.)

Someday, perhaps, I will write an alternative Grid that performs this job in a very elegant manner. Right now, I have a kludge. It's called OrientableGrid and it derives from Grid and adds a property named SwapRowsAndColumns and whenever that property changes, it performs a brute force swap. This new property is, of course, another target of a data binding:

<petzold:OrientableGrid 
    DataContext="{Binding Source={StaticResource rgbColor}}"
    SwapRowsAndColumns="{Binding ElementName=this,
                             Path=Orientation,
                             Converter={StaticResource isLandscapeConverter}}">

I don't know if the approach I've shown here is the "correct" way to handle orientation changes on the phone. But it seems like the start of what could be a useful general-purpose technique for optimizing space no matter how the user wants to use the device. Here's the ColorScroll for Windows Phone source code.

Programming Windows Phone 7 Series
Programming Windows Phone 7 Series

Free ebook to be published later this year. Preview excerpts available now.

Comments:

This certainly sounds lot of work specially if you have a complex application :( . Besides how to deal with things like Pivot and Panaroma :( . If I change the orientation of those I think I might break UI guidelines for Windows Phone 7. Please confirm. I think to get precise control we will have to work both versions :(

Parag, Thu, 17 Jun 2010 01:38:36 -0400

I have read your interview:

http://dotnet.dzone.com/articles/interview-charles-petzold-wp7

where you say that it is not possible to use SL and XNA at the same time on WP7, which is a severe limitation compared to the availability of OpenGL on both the iPhone and Android plateforms IMO.

What do you think of an elegant workaround proposed on the SilverLight forum:

http://forums.silverlight.net/forums/p/168531/381489.aspx#381489

which consists in transferring the content of an XNA texture to a SL WriteableBitmap:

http://www.uta.fi/%7Etp79800/Silverlight/WindowsPhoneApplicationXNA.zip

This is done here by software and runs nicely in the emulator, but I have no idea of how it will run on a real phone.

Wouldn't a hardware-based transfer between an XNA texture and a WP7/SL Bitmap be sufficient to bridge the two technologies and give us access to a 3D engine in a WP7/SL, finally?

Also, since a 3D engine is anxiously awaited by a number of SL developers, including me, shouldn't it be based on XNA so as to be consistently available on all the SL flavors?

Philippe Monteil, Paris - France, Thu, 1 Jul 2010 05:49:55 -0400

Is there emulator for windows phone 7 that i can use to test the code?

— VV, Sun, 4 Jul 2010 10:42:21 -0400

The emulator is described in the preview edition of my book. — Charles

Real sorry my engglish no good.you tell how to develp coding for pone 7? because many times try code but every time run no good.let we explained really more what is happened here, i demand and hard try outlook to run on pone 7 but this is not very possible.Also tell royally how to movement all the appliccatons from iPhone3G to pone 7?Also can we wakeup use appliccatons from mobile 6.5 to pone 7 or it is not very possible.ending tell all how to reuse use the coding from .net (all and every versions) to phone 7. sorry 4-5 questions let you answer chose any 2 please.

Thank you very too much Mr Petzold!

— Naj, Sun, 4 Jul 2010 10:54:47 -0400

Windows Phone 7 runs applications written in C# using Silverlight or XNA. Details are covered in the preview edition of my book. — Charles

This sample is not working as described using the April CTP emulator. I hit the break points only the first time but never again. I assume you tested using the actually device and the emulator is not upto simulating the orientation change.

Thanks in advance.

Venkateswara Sunkara, Sun, 11 Jul 2010 20:14:08 -0400


Recent Entries
< PreviousBrowse the ArchivesNext >
Subscribe to the RSS Feed

(c) Copyright Charles Petzold
www.charlespetzold.com