Your SlideShare is downloading. ×
Porting iPhone Apps to Windows Phone 7
Porting iPhone Apps to Windows Phone 7
Porting iPhone Apps to Windows Phone 7
Porting iPhone Apps to Windows Phone 7
Porting iPhone Apps to Windows Phone 7
Porting iPhone Apps to Windows Phone 7
Porting iPhone Apps to Windows Phone 7
Porting iPhone Apps to Windows Phone 7
Porting iPhone Apps to Windows Phone 7
Porting iPhone Apps to Windows Phone 7
Porting iPhone Apps to Windows Phone 7
Porting iPhone Apps to Windows Phone 7
Porting iPhone Apps to Windows Phone 7
Porting iPhone Apps to Windows Phone 7
Porting iPhone Apps to Windows Phone 7
Porting iPhone Apps to Windows Phone 7
Porting iPhone Apps to Windows Phone 7
Porting iPhone Apps to Windows Phone 7
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Porting iPhone Apps to Windows Phone 7

602

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
602
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
3
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Porting an iPhone Application to Windows Phone 7 Introduction Developers of iPhone applications possess the fundamentals and key understanding for building applications for small form factor devices. When creating a mobile application for Windows Phone 7 however, the means for developing the application changes. This platform is a considerable departure from Microsoft’s previous mobile operating systems so this article will help describe what you’ll encounter porting an existing iPhone application to Windows Phone 7. Whether it’s the difference between Objective-C vs .Net, or the iOS SDK vs the Windows Phone 7 SDK, a number of differences exist which will be explained throughout this article. We’re going to walk through our own process of porting an internal iPhone application, Slalom Cards, into a comparable version for Windows Phone 7. The goal of this article is not only provide you with the knowledge necessary to port an existing application to Windows Phone 7, but to also better understand the platform a whole for new development. About the Team Rob Howard is an experienced software engineer and engineering lead. He has ten years of industry experience with published mobile applications for several platforms including iPhone, WebOS, and Blackberry. He has a career in both Consulting and Startups, building software from the ground up and taking a project to the latest technologies or methodologies. Rob strives to make solutions simple, understandable, and easily extendable. Dan Maycock is a technology solutions consultant, helping advise fortune 500 companies on how to work with new and emerging technologies, primarily focused around mobile. Prior to working for Slalom Consulting, Dan worked at The Boeing Company, where he helped shape the direction for enterprise mobility and successfully pioneered a number of initiatives focused around successfully utilizing mobile technologies to help solve business challenges. Greg Martin has been a consultant at Slalom Consulting for over 7 years and is currently the mobility development lead. Greg is a talented software engineer and consultant with experience in a wide variety of technologies and industries. He has spent much of his career delivering solutions in the mobile space. Beyond his deep technical knowledge, Greg also excels in the entire lifecycle of a project with an uncanny ability to break a problem down into the most elegant solution. Slalom Consulting Slalom Consulting is a business and technology consulting firm that helps clients win by building local teams with a deep understanding of the art and science of business success. Slalom drives client ROI in
  • 2. areas such as cloud computing, business intelligence, portals, mobility, project management and process design. Slalom's consultants are handpicked experts who stay ahead of the curve by always finding the next innovative advantage. Headquartered in Seattle, Slalom employs more than 800 consultants across eight cities in the United States. Slalom Cards The application listed in this article was built to serve as a dynamic corporate directory, complete with profile photos, background information and a feature set focused on finding people based on many characteristics. Originally built for the iPhone, it has since been ported to Android and Windows Phone 7, as well as being extended to a web-based platform. Getting Ready Resources Windows Phone 7 applications are built and tested utilizing Visual Studio. All the tools to get started can be downloaded at http://developer.windowsphone.com/windows-phone-7/ as well as guides and tips to get up to speed with the Windows Phone 7 development environment. As a (fairly obvious) note, the development environment DOES require the Windows Operating System (Windows Vista or Windows 7), so having either a standalone machine, or a VM with the OS will be required before you can utilize the Windows Phone 7 development toolset. You will need to download the developer tools on this website. They are a free download and it includes the following: a. Visual Studio 2010 Express for Windows Phone Beta b. Windows Phone Emulator Beta c. Silverlight for Windows Phone Beta d. Microsoft Expression Blend for Windows Phone Beta e. XNA Game Studio 4.0 Beta f. The UI Design and Interaction Guide for Windows Phone 7 can be found linked on the Windows Phone developer site at http://go.microsoft.com/?linkid=9713252 Documentation Since we are jumping from one platform to another, it’s important to map out the ins and outs of your existing application. This might include everything from doing a high-level outline, to writing pseudo- code as a reverse engineering exercise. Regardless, knowing how the application is laid out will help further down the road once you get deep into the code. Construction of the Application The Easy things
  • 3. Migration of the Data Model Since the languages support similar features (both object-oriented c-like languages that support things like properties and methods) porting most of the model items will be pretty straightforward with a one to one mapping of fields and methods. Note: C# is currently the only supported programming language for Development for Windows Phone 7. Networking Windows Phone 7 allows the developer to use Windows Communication Foundation (WCF), HttpWebRequest, and WebClient. WCF works very well with SOAP web services. It is very simple to set up a connection that would generate all of the networking code and object classes that it uses. For RESTful services, WCF is also very useful but we will have to do a little bit more work deserializing the data into objects. There are many ways to do this; .Net provides some simple DataContract Serializers and Deserializers that work well with XML and JSON. User Interface Elements Windows Phone 7 provides a few ways to author and edit the user interface. One can use the preview pane within the IDE for layout and addition to controls. This is very similar to the Interface Builder application that is part of the iOS SDK. Users of Interface Builder will become easily familiar with this method of UI authoring and manipulation. Also in the IDE is a view of the XAML that can be very useful for a developer to see and modify. This code behind the presentation is an easy way to see the output of the UI layout engine, and gives a chance to add function handlers, custom properties on classes, and to fine tune your code. There is also a version of Expression Studio for the Windows Phone. Like Expression for web based Silverlight applications or WPF implementations, this provides a more designer focused interface which allows you to creating templates, behaviors, animations, and many other custom UI. Page Hierarchy Like most mobile phone operating systems, Windows Phone 7 provides a stack based navigation system along with application buttons that can be used, like in the iPhone, as a tabbed based navigation system. The API provides NavigatedTo and NavigatedFrom methods that are similar to the ViewDidAppear, and ViewDidDisappear methods that the iPhone supports. The Difficult and / or Not so clear things
  • 4. This is a list of things that aren’t as simple as the first list. Differences in hardware, operating systems, and API are the contributing factor to getting an item in this list. Data storage Unlike previous versions of Windows Mobile operating systems, Windows Phone 7 currently does not have an API for a client-side database which developers can use. What is provided is access to isolated data storage where your application can save settings or files. Here you can roll your own data storage mechanism or use a third party database with the caveat that an application can only access its own data. This is very similar to those familiar with iPhone development and is another break away from previous versions of Windows Mobile operating systems. A resource video for developing occasionally connected applications can be found here: http://www.msteched.com/2010/NorthAmerica/WPH306 Page Transitions While the navigation between pages in the Windows Phone 7 environment is similar to iPhone, the familiar animation transitions are not left up to the developer to implement. Built-in screen transitions and animations are system-reserved and developers cannot access them but may mimic them. If developers want to implement transitions or animations within their application, they must use Silverlight or the XNA Framework to create them (see page 64 of the UI Design guide). Transitions within your application must be implemented on your own. Contrary to the iPhone, there currently isn’t a defined standard for the types of transitions one should use. A Channel9 video of implementation can be seen here: http://channel9.msdn.com/posts/SlickThought/Simplify-Page-Transitions-in-Windows-Phone-7- Silverlight-Applications/ Windows Phone 7 Has Themes There is a large selection of highlight colors including light and dark for background colors. One must be aware that the user could have any one of those themes set for their phone. The application should be aware of the settings and use them throughout the user experience. Background images and UI elements presented above them should take in to account the possibility of the different themes. For example, if you use a particularly dark image for a background, the light theme with black button borders may not show up very well against the image. Setting the opacity of
  • 5. the image to show some of the white background is one solution to this problem. Digging Deeper The following are some examples that we used in Slalom Cards. We chose these examples because we felt that they are things that aren’t obvious to most developers and take some research to find a solution. We also feel that they are things that pretty much any application for the phone would need. Some are simplified versions of examples that others have created or ones that we fixed due to the SDK changes in the Windows Phone 7 in its push to production. In our samples, we try to find a simple solution to the problems while providing the best user experience. Porting the Data Model – The following is simple port of a small class from Objective-C to C#. This would be part of a class that would represent the data behind user interface elements. It could be created in several different ways, like being fetched from storage, from an external API, or being generated by the application at runtime. In the example, the extra methods for those means of creation or fetching have been omitted to keep the code short: Person.h @interface Person : NSObject { } @property (nonatomic, retain) NSString * firstName; @property (nonatomic, retain) NSString * lastName; @property (nonatomic, retain) NSString * office; Person.m #import "Person.h" @implementation Person @synthesize firstName; @synthesize lastName; @synthesize office; -(void)dealloc { [firstName release]; [lastName release]; [office release]; [super dealloc]; } @end Person.cs public class Person { public String FirstName { get; set; } public String LastName { get; set; } public String Office { get; set; } }
  • 6. C# also provides an easy way to port Observable objects. The following code is an update of the Person class to notify observers of updates to the data. public class Person : INotifyPropertyChanged { private String firstName; public event PropertyChangedEventHandler PropertyChanged; private void NotifyChanged(String changeProperty) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(changeProperty)); } } public String FirstName { get { return firstName; } set { if (value != firstName) { firstName = value; NotifyChanged("FirstName"); } } } … Navigation – Moving from page to page in your application is different than iPhone, but fairly simple. Instead of pushing and popping view controllers to your scene, the navigation system behaves more like a browser where you navigate forward and back through the pages of the application. Also, data is passed to the pages through the querystring where the navigating page can read and perform operations based on the input. This is shown in the following examples: A typical navigation operation in iPhone PersonListViewController * personList = [[PersonListViewController alloc] initWithNibName:@"PersonList" bundle:nil]; [[self navigationController] pushViewController: personList animated:YES]; [personList release]; Doing the same in code on Windows Phone 7 private void HyperlinkButton_Click(object sender, RoutedEventArgs e) { NavigationService.Navigate(new Uri("/PersonListPage.xaml?office=Seattle", UriKind.Relative)); } A different way, with XAML <HyperlinkButton Content="Seattle" NavigateUri="/PersonListPage.xaml?office=Seattle" /> <HyperlinkButton Content="Los Angeles" NavigateUri="/PersonListPage.xaml?office=Los Angeles" /> Reading passed in values on the new page
  • 7. protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { base.OnNavigatedTo(e); PersonList people = CardsDatabase.Instance.PersonListTable; string office; if (NavigationContext.QueryString.TryGetValue("office", out office) == false) { office = "National"; // default value } PersonList.ItemsSource = from p in people where p.Office == office // filter to the selected office orderby p.FirstName, p.LastName select p; } Navigating back to the previous page is either done with the user clicking on the back hardware button or you can programmatically perform this with the following code: NavigationService.GoBack(); Page Transitions – As stated earlier, the Windows Phone 7 SDK leaves it up to the developer to create animations and transitions while navigating between pages. A simple way to add these transitions to your application is to use the TransitioningContentControl in the Microsoft Silverlight Toolkit found at http://silverlight.codeplex.com/. The steps to add these transitions are as follows: 1. Download and install the toolkit. 2. Add a reference in your project to System.Windows.Controls.Layout.Toolkit.dll (for example after installation, it was found in: Program Files (x86)Microsoft SDKsSilverlightv4.0ToolkitApr10BinSystem.Windows.Controls.Layout.Toolk it.dll) 3. In your App.xaml file, create a Style for the application frame that includes a TransitioningContentControl <Application x:Class="Cards.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:tcc ="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit" > <Application.Resources> <Style x:Key="mainFrameStyle" TargetType="phone:PhoneApplicationFrame"> <Setter Property="Template"> <Setter.Value> <ControlTemplate> <Border x:Name="ClientArea" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
  • 8. Background="{TemplateBinding Background}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}"> <tcc:TransitioningContentControl x:Name="TransitioningControl" Content="{TemplateBinding Content}" Style="{StaticResource TransitioningStyle}"/> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> Also in this file, create the transition templates for the page transitions. For the example, a SwingOpen transition for navigating forward and a SwingClosed transition for backward navigation. <Style x:Key="TransitioningStyle" TargetType="tcc:TransitioningContentControl"> <Setter Property="Transition" Value="SwingOpen" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="layout:TransitioningContentControl"> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="2"> <VisualStateManager.VisualStateGroups> <VisualState x:Name="SwingOpen"> <Storyboard> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)" Storyboard.TargetName="PreviousContentPresentationSite"> <EasingDoubleKeyFrame KeyTime="0" Value="0"/> <EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="90"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="PreviousContentPresentationSite"> <EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="1"/> <EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="0"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.CenterOfRotationX)" Storyboard.TargetName="PreviousContentPresentationSite" /> <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.CenterOfRotationX)" Storyboard.TargetName="CurrentContentPresentationSite" />
  • 9. <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="CurrentContentPresentationSite"> <EasingDoubleKeyFrame KeyTime="0" Value="0"/> <EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="1"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="SwingClosed"> <Storyboard> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="PreviousContentPresentationSite"> <EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="1"/> <EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="0"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.CenterOfRotationX)" Storyboard.TargetName="PreviousContentPresentationSite" /> <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.CenterOfRotationX)" Storyboard.TargetName="CurrentContentPresentationSite" /> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)" Storyboard.TargetName="CurrentContentPresentationSite"> <EasingDoubleKeyFrame KeyTime="0" Value="90"/> <EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="0"/> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="CurrentContentPresentationSite"> <EasingDoubleKeyFrame KeyTime="0" Value="0"/> <EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="1"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups>
  • 10. <Grid> <ContentPresenter x:Name="PreviousContentPresentationSite" Content="{x:Null}" ContentTemplate="{TemplateBinding ContentTemplate}"> <ContentPresenter.RenderTransform> <TransformGroup> <ScaleTransform /> <SkewTransform /> <RotateTransform /> <TranslateTransform /> </TransformGroup> </ContentPresenter.RenderTransform> <ContentPresenter.Projection> <PlaneProjection /> </ContentPresenter.Projection> </ContentPresenter> <ContentPresenter x:Name="CurrentContentPresentationSite" Content="{x:Null}" ContentTemplate="{TemplateBinding ContentTemplate}" > <ContentPresenter.RenderTransform> <TransformGroup> <ScaleTransform /> <SkewTransform /> <RotateTransform /> <TranslateTransform /> </TransformGroup> </ContentPresenter.RenderTransform> <ContentPresenter.Projection> <PlaneProjection /> </ContentPresenter.Projection> </ContentPresenter> </Grid> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> In the app.xaml.cs, set the style of the root frame to the new style created in the previous step. RootFrame = new PhoneApplicationFrame() { // Use a style to use the Template with the TransitioningContentControl Style = (Style)Resources["mainFrameStyle"] }; Right now, this is all that one would need to do to implement a transition between pages. However, it will show the same “SwingOpen” transition navigating forward and back. But, like the transitions in iPhone, it is a clearer user experience to show a different transition for backward navigation than forward. This can be accomplished with the following steps: Extend the TransitioningContentControl class, set up a Setter for the transition that would be used: public class CardsTransitioningContentControl : TransitioningContentControl
  • 11. { private static String _currentTransition = "SwingOpen"; public static void SetBackTransition() { _currentTransition = "SwingClosed"; } public static void SetForwardTransition() { _currentTransition = "SwingOpen"; } protected override void OnContentChanged(object oldContent, object newContent) { Transition = _currentTransition; base.OnContentChanged(oldContent, newContent); SetForwardTransition(); // reset to the default } } In the PhoneApplicationPage class, capture the back button press and update the transition protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e) { CardsTransitioningContentControl.SetBack(); base.OnBackKeyPress(e); } Orientation Transitions – Like page transitions, it is up to the developer to implement a transition for orientation changes. This can be done by overriding the application frame class and registering an event listener for the OrientationChanged event. The Cards implementation is a simplified version of the sample from: http://blogs.msdn.com/b/delay/archive/2010/07/13/spin-spin-sugar-updated-code-to- easily-animate-orientation-changes-for-any-windows-phone-application.aspx. This example is nice because it will size the content as it rotates providing a fluid transition between states. First, create a new subclass of PhoneApplicationFrame and have the App.xaml.cs instantiate it when it creates the frame. In the InitializePhoneApplication method of App.xaml.cs RootFrame = new CardsApplicationFrame() Then fill in the details of the PhoneApplicationFrame subclass public class CardsApplicationFrame : PhoneApplicationFrame { private readonly RotateTransform _rotateTransform = new RotateTransform(); private readonly Storyboard _orientationStoryboard = new Storyboard(); private readonly DoubleAnimation _orientationAnimation = new DoubleAnimation(); private readonly OrientationState _fromOrientationState = new OrientationState(); private readonly OrientationState _toOrientationState = new OrientationState(); private UIElement _clientArea; private Size _lastSize; public CardsApplicationFrame() { RenderTransform = _rotateTransform; RenderTransformOrigin = new Point(0.5, 0.5);
  • 12. _orientationAnimation.From = 0; _orientationAnimation.To = 1; _orientationAnimation.Duration = new Duration(TimeSpan.FromSeconds(.4)); _orientationAnimation.EasingFunction = new QuarticEase(); Storyboard.SetTarget(_orientationAnimation, this); Storyboard.SetTargetProperty(_orientationAnimation, new PropertyPath("OrientationProgress")); _orientationStoryboard.Children.Add(_orientationAnimation); SizeChanged += new SizeChangedEventHandler(HandleSizeChanged); OrientationChanged += new EventHandler<OrientationChangedEventArgs>(HandleOrientationChanged); } private static readonly DependencyProperty ProgressProperty = DependencyProperty.Register( "OrientationProgress", typeof(double), typeof(CardsApplicationFrame), new PropertyMetadata(0.0, OnProgressChanged)); private static void OnProgressChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) { ((CardsApplicationFrame)o).OnProgressChanged((double)e.NewValue); } private void OnProgressChanged(double newValue) { _rotateTransform.Angle = _fromOrientationState.Angle + (newValue * (_toOrientationState.Angle - _fromOrientationState.Angle)); var width = _fromOrientationState.Width + (newValue * (_toOrientationState.Width - _fromOrientationState.Width)); var height = _fromOrientationState.Height + (newValue * (_toOrientationState.Height - _fromOrientationState.Height)); var size = new Size(Math.Round(width), Math.Round(height)); if (size != _lastSize) { _lastSize = size; InvalidateMeasure(); } } public override void OnApplyTemplate() { base.OnApplyTemplate(); _clientArea = base.GetTemplateChild("ClientArea") as UIElement; } private void HandleSizeChanged(object sender, SizeChangedEventArgs e) { _fromOrientationState.Width = e.NewSize.Width; _fromOrientationState.Height = e.NewSize.Height; _lastSize = e.NewSize; InvalidateMeasure(); } private void HandleOrientationChanged(object sender, OrientationChangedEventArgs e) { _fromOrientationState.Angle = _rotateTransform.Angle; _fromOrientationState.Width = _lastSize.Width; _fromOrientationState.Height = _lastSize.Height; _orientationStoryboard.Stop(); // Determine new angle
  • 13. switch (e.Orientation) { case PageOrientation.PortraitUp: _toOrientationState.Angle = 0; break; case PageOrientation.LandscapeLeft: _toOrientationState.Angle = 90; break; case PageOrientation.LandscapeRight: _toOrientationState.Angle = -90; break; case PageOrientation.PortraitDown: _toOrientationState.Angle = 180; break; default: throw new NotSupportedException("Unknown PageOrientation value."); } // Determine new size var actualWidth = ActualWidth; var actualHeight = ActualHeight; var toPortrait = (0 == (_toOrientationState.Angle % 180)); _toOrientationState.Width = toPortrait ? actualWidth : actualHeight; _toOrientationState.Height = toPortrait ? actualHeight : actualWidth; _orientationStoryboard.Begin(); } protected override Size MeasureOverride(Size availableSize) { if (null != _clientArea) { // Adjust measure size to transition size var newValue = (double)GetValue(ProgressProperty); var width = _fromOrientationState.Width + (newValue * (_toOrientationState.Width - _fromOrientationState.Width)); var height = _fromOrientationState.Height + (newValue * (_toOrientationState.Height - _fromOrientationState.Height)); _clientArea.Measure(new Size(width, height)); } // Return default size return availableSize; } protected override Size ArrangeOverride(Size finalSize) { if (null != _clientArea) { var newValue = (double)GetValue(ProgressProperty); var width = _fromOrientationState.Width + (newValue * (_toOrientationState.Width - _fromOrientationState.Width)); var height = _fromOrientationState.Height + (newValue * (_toOrientationState.Height - _fromOrientationState.Height)); _clientArea.Arrange(new Rect((finalSize.Width - width) / 2, (finalSize.Height - height) / 2, width, height)); } return finalSize; } private class OrientationState {
  • 14. public double Width { get; set; } public double Height { get; set; } public double Angle { get; set; } } } Networking – The following is an example of a base request class that is used to send an asynchronous request to a server. It allows for different request methods, and will call handler methods upon completion of the request. public abstract class CardsRequestBase { … public void SendRequestToService() { String url = GetURL(); _request = (HttpWebRequest)WebRequest.Create(url); // set any headers like authentication, cache options, etc SetRequestHeaders(_request); _request.Method = GetMethod(); // Is it a request that requires data to be added? if (_request.Method.Equals("POST") || _request.Method.Equals("PUT")) { _request.BeginGetRequestStream(new AsyncCallback(SendDataToStream), _request); } else { SendRequest(); } } private void SendDataToStream(IAsyncResult asynchronousResult) { HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState; Stream postStream = request.EndGetRequestStream(asynchronousResult); String postData = GetContentData(); byte[] byteArray = Encoding.UTF8.GetBytes(postData); postStream.Write(byteArray, 0, postData.Length); postStream.Close(); SendRequest(); } private void SendRequest() { IAsyncResult result = _request.BeginGetResponse(new AsyncCallback(HandleResponse), this); ThreadPool.RegisterWaitForSingleObject( result.AsyncWaitHandle, new WaitOrTimerCallback(RequestTimeoutCallback), this, (GetTimeoutSeconds() * 1000), true); } protected virtual String GetContentData() { return ""; } protected virtual void SetRequestHeaders(HttpWebRequest request) { }
  • 15. private void RequestTimeoutCallback(Object state, bool timedOut) { if (timedOut) { CancelRequest(); } } protected virtual void HandleResponse(IAsyncResult result) { try { HttpWebResponse response = (HttpWebResponse)_request.EndGetResponse(result); using (Stream responseStream = response.GetResponseStream()) { HandleResponseStream(responseStream); // extra processing option for subclasses // this is here to take advantage of performing // needed operations (like parsing) on the background thread PostResponseProcessing(); } } catch (Exception e) { _error = e; } if (_requestHandler != null) { if (_error == null) { _requestHandler.RequestCompletedWithResults(_results, this); } else { _requestHandler.RequestCompletedWithError(_error, this); } } } // Broke this out to its own method so that classes can override as needed protected virtual void HandleResponseStream(Stream responseStream) { using (StreamReader reader = new StreamReader(responseStream)) { _results = reader.ReadToEnd(); reader.Close(); responseStream.Close(); } } Data Serialization – The server for Slalom Cards provides a RESTful service for the data that the client consumes. We took advantage of the XMLSerializer to parse the responses from the server, and to store data in the Isolated Storage on the device. The service’s responses were in XML, but a JSON response would be just as easy to handle with the DataContractJsonSerializer class. The following snippets of code are examples of the use of the XMLSerializer in SlalomCards: The Collection Class // Parse a collection of People objects, the root of the collection will be the element "People"
  • 16. // like <People>... people list .. </People> [XmlRoot(ElementName = "People")] public class PersonList : ObservableCollection<Person> { } The Person Class: Note the INotifyPropertyChanged interface. This is used to notify clients, like binding clients of updates. (Like KVO in iPhone). // Will Parse into a Person Object where the Element name is "P" [XmlRootAttribute("P",Namespace="", IsNullable = false)] public class Person : INotifyPropertyChanged { private Guid _ID; private String _action; public Person() { } public event PropertyChangedEventHandler PropertyChanged; private void NotifyChanged(String changeProperty) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(changeProperty)); } } [XmlAttribute(AttributeName="id")] public Guid ID { get { return _ID; } set { if (value != _ID) { _ID = value; NotifyChanged("ID"); } } } [XmlAttribute(DataType = "string", AttributeName = "ac")] public String Action { get { return _action; } set { if (value != _action) { _action = value; NotifyChanged("Action"); } } } …
  • 17. Reading the PersonList object data from a stream. This could be a HTTP Response Stream, a File Stream, Memory Stream, etc. using (stream) { // Read the personList object from the stream XmlSerializer ser = new XmlSerializer(typeof(PersonList)); _personListTable = (PersonList)ser.Deserialize(stream); } Data Storage – The Slalom Cards application persists data by taking advantage of data serialization, isolated storage, and LINQ to fetch, sort, and filter the data. A resource video for developing occasionally connected applications that was the inspiration for the example can be found at: http://www.msteched.com/2010/NorthAmerica/WPH306 First create a Singleton for Database Management sealed class CardsDatabase { private PersonList _personListTable = null; private CardsDatabase() { } private static CardsDatabase _staticDB = new CardsDatabase(); public static CardsDatabase Instance { get { return _staticDB; } } Then Create the Table members of the Database Class that will fetch the data, (in the same CardsDatabase class) private PersonList _personListTable = null; public PersonList PersonListTable { get { if (_personListTable == null) { using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) { Stream stream = null; if (store.FileExists(_personListFile)) { stream = store.OpenFile(_personListFile, FileMode.Open); using (stream) { // Read the personList object from the stream XmlSerializer ser = new XmlSerializer(typeof(PersonList)); _personListTable = (PersonList)ser.ReadObject(stream); } } } } return _personListTable;
  • 18. } } Finally, create a LINQ query to fetch the data as your application needs it: PersonList people = CardsDatabase.Instance.PersonListTable; ListBox.ItemsSource = from p in people where p.Office == "Seattle" orderby p.FirstName, p.LastName select p; … Concluding Thoughts There are many things with Windows Phone 7 that an iPhone developer will find familiar and be comfortable with, but a few things that have a bit of a learning curve. Since the capabilities of the devices are so similar, functionality can be mirrored from iPhone to WP7. However, they are two different worlds and so there is still work associated with your first ported application. We hope this article will help clarify some of these differences, and will help you to develop Windows Phone 7 applications in a more efficient, streamlined, manner.

×