Sunday, June 5, 2011

Create a Panorama Application for Windows Phone 7 – [Part-6]

 

In this article we will discuss about how to develop panorama application for Windows Phone 7. Panorama is a compiling control of windows phone 7.

What is panorama?
Lets us know about Panorama, Its mean capturing a series of images to create a pictures wider than, in a single image by "Stitching" the photographs together.

Why panorama’s view?
Panoramic experiences offer a unique way to view data, controls and services by using a long horizontal canvas that extends beyond the confines of the screen.

Objective of this application is to display my friend’s data and it will show my different –different social networks (like Google+, Facebook, LinkedIn and Twitter) friends list on the panorama screen.

Let’s come to the application development part, here we go.

In this post I will show you how to create a panorama application in Windows Phone 7. This post illustrates the following steps:

Step:-1 Open Visual Studio 2010 Ultimate or Express for Windows Phone from the Start menu.

Step:-2 Create a new project by selecting the File menu and click on New Project.

Step:-3 New Project dialog window will be displayed. Expand the Visual C# templates, and then select the Silverlight for Windows Phone templates –> Select “Windows Phone Application” and enter the project name.

WP_01

Step:-4 New project will be created with MainPage.xaml page and it will be opened in the Visual Studio2010 IDE. Now right-click on project in Solution Explorer and click on Add then click on New Item. Select Windows Phone Panorama Page.

WP_02

WP_03

And now enter your desired name of panorama page (in this project I have used default name of PanoramaPage1.xaml) and click on Add bottom. PanoramaPage1 will come up with the default background image. And keep this page in view directory.

Step:-5 add an image (I have used PanoramaBackground.png) to display panorama page background. After add this image it will automatically become a resource image of the application. To check the build action select the PanoramaBackground.png image and press F4 key and see Build Action property is Resource only.

WP_05

Step:-6 now set the panorama control’s background. See below xaml code snippet.

   1: <controls:Panorama.Background>
   2:     <ImageBrush ImageSource="/WP_PanoramaApp;component/PanoramaBackground.png"/>
   3: </controls:Panorama.Background>


Then you are able to view background image at design time in IDE see below picture.




WP_06


Important: You must be aware about how to use resource files in the Windows Phone 7 application. See here

Note: For the time being I have used some static data. To display the data, I have used MVVM (Model View ViewModel) pattern (MVVM pattern we will discussed later in this series).

Step:-7 To display, friends pictures on the panorama control I have added different – different social network friend’s pictures in this application and set Build Action type Content instead of Resource to all pictures property.

WP_07

Step: -8 create a generic class to access the all social networks friend’s data like (name, details and imagepath) I have created an ItemViewModel class which will responsible to provide friend’s data to view. This class basically derived with an INotifyPropertyChanged interface and it is implemented an event name is PropertyChangedEventHandler; and this event call by each property.



   1: public class ItemViewModel : INotifyPropertyChanged
   2: {
   3:     private string _name;
   4:     private string _imagePath;
   5:     private string _details;
   6:  
   7:     public string Name
   8:     {
   9:         get { return _name; }
  10:         set
  11:             {
  12:                 if (value != _name)
  13:                 {
  14:                     _name = value;
  15:                     NotifyPropertyChanged("Name");
  16:                 }
  17:             }
  18:     }
  19:  
  20:     public string ImagePath
  21:     {
  22:         get { return _imagePath; }
  23:         set
  24:         {
  25:             if (value != _imagePath)
  26:             {
  27:                 _imagePath = value;
  28:                 NotifyPropertyChanged("ImagePath");
  29:             }
  30:         }
  31:     }
  32:  
  33:     public string Details
  34:     {
  35:         get { return _details; }
  36:         set
  37:         {
  38:             if (value != _details)
  39:             {
  40:                 _details = value;
  41:                 NotifyPropertyChanged("Details");
  42:             }
  43:         }
  44:     }
  45:  
  46:     #region INotifyPropertyChanged Members
  47:  
  48:     public event PropertyChangedEventHandler PropertyChanged;
  49:  
  50:     private void NotifyPropertyChanged(String propertyName)
  51:     {
  52:         PropertyChangedEventHandler handler = PropertyChanged;
  53:         if (null != handler)
  54:         {
  55:             handler(this, new PropertyChangedEventArgs(propertyName));
  56:         }
  57:     }
  58:     #endregion
  59: }

Step: - 9 create a PanoramaViewModel class to store the static data; the purpose of this class View-Model is responsible for exposing the data objects from the Model in such a way that those objects are easily managed and consumed. Here I have added some static data of different -2 social network’s friend.

See below code snippet:






   1: public class PanoramaViewModel
   2: {
   3:  
   4:     public PanoramaViewModel()
   5:     {
   6:         this.Items = new ObservableCollection<ItemViewModel>();
   7:         this.GooglePlusItems = new ObservableCollection<ItemViewModel>();
   8:         this.FacebookItems = new ObservableCollection<ItemViewModel>();
   9:         this.LinkedIn = new ObservableCollection<ItemViewModel>();
  10:         this.Twitter = new ObservableCollection<ItemViewModel>();
  11:     }
  12:  
  13:     /// <summary>
  14:     /// A collection for ItemViewModel objects.
  15:     /// </summary>
  16:     public ObservableCollection<ItemViewModel> Items { get; private set; }
  17:  
  18:     public bool IsDataLoaded {get; private set; }
  19:     
  20:     /// <summary>
  21:     /// Creates and adds a few ItemViewModel objects into the Items collection.
  22:     /// </summary>
  23:     public void LoadData()
  24:     {
  25:         // Sample data; here you can replace with real data
  26:         this.Items.Add(new ItemViewModel() { Name = "Google+", ImagePath = 
  27:         "/Networks/Facebook/1.jpg", Details = "" });
  28:         this.Items.Add(new ItemViewModel() { Name = "Facebook", ImagePath = 
  29:         "/Networks/Facebook/2.jpg", Details = "" });
  30:         this.Items.Add(new ItemViewModel() { Name = "LinkedIn", ImagePath = 
  31:         "/Networks/Facebook/3.jpg", Details = "" });
  32:         this.Items.Add(new ItemViewModel() { Name = "Twitter", ImagePath = 
  33:         "/Networks/Facebook/4.jpg", Details = "" });
  34:         this.IsDataLoaded = true;
  35:     }
  36:  
  37:     /// <summary>
  38:     /// A collection for ItemViewModel objects.
  39:     /// </summary>
  40:     public ObservableCollection<ItemViewModel> GooglePlusItems { get; private set; }
  41:  
  42:     /// <summary>
  43:     /// Creates and adds a few ItemViewModel objects into the Items collection.
  44:     /// </summary>
  45:     public void LoadGooglePlusData()
  46:     {
  47:         // Sample data; replace with real data
  48:         this.GooglePlusItems.Add(new ItemViewModel() { Name = "Pinal Dave", ImagePath = "/Networks/GoolgePlus/1.jpg", Details = "MVP" });
  49:         this.GooglePlusItems.Add(new ItemViewModel() { Name = "Abhishek Kumar", ImagePath = "/Networks/GoolgePlus/2.jpg", Details = "SSE" });
  50:         this.GooglePlusItems.Add(new ItemViewModel() { Name = "Gaurav Arora", ImagePath = "/Networks/GoolgePlus/3.jpg", Details = "MVP" });
  51:         this.GooglePlusItems.Add(new ItemViewModel() { Name = "Sachin Kapse", ImagePath = "/Networks/GoolgePlus/4.jpg", Details = "SSE" });
  52:         this.GooglePlusItems.Add(new ItemViewModel() { Name = "Mitesh", ImagePath = "/Networks/GoolgePlus/5.jpg", Details = "SSE" });
  53:         this.IsDataLoaded = true;
  54:     }
  55:  
  56:     /// <summary>
  57:     /// A collection for ItemViewModel objects.
  58:     /// </summary>
  59:     public ObservableCollection<ItemViewModel> FacebookItems { get; private set; }
  60:  
  61:     /// <summary>
  62:     /// Creates and adds a few ItemViewModel objects into the Items collection.
  63:     /// </summary>
  64:     public void LoadFacebookData()
  65:     {
  66:         // Sample data; replace with real data
  67:         this.FacebookItems.Add(new ItemViewModel() { Name = "Vinod Kumar", ImagePath = "/Networks/Facebook/6.jpg", Details = "MVP" });
  68:         this.FacebookItems.Add(new ItemViewModel() { Name = "Dhananjay Kumar", ImagePath = "/Networks/Facebook/1.jpg", Details = "MVP" });
  69:         this.FacebookItems.Add(new ItemViewModel() { Name = "Kunal Chowdhury", ImagePath = "/Networks/Facebook/2.jpg", Details = "MVP" });
  70:         this.FacebookItems.Add(new ItemViewModel() { Name = "Malleswar", ImagePath = "/Networks/Facebook/7.jpg", Details = "MVP" });
  71:         this.FacebookItems.Add(new ItemViewModel() { Name = "Mohsin", ImagePath = "/Networks/Facebook/3.jpg", Details = "SSE" });
  72:         this.FacebookItems.Add(new ItemViewModel() { Name = "Sawkat Ali", ImagePath = "/Networks/Facebook/4.jpg", Details = "SSE" });
  73:         this.FacebookItems.Add(new ItemViewModel() { Name = "Karan Singh", ImagePath = "/Networks/Facebook/5.jpg", Details = "SSE" });
  74:         this.IsDataLoaded = true;
  75:     }
  76:  
  77:     /// <summary>
  78:     /// A collection for ItemViewModel objects.
  79:     /// </summary>
  80:     public ObservableCollection<ItemViewModel> LinkedIn { get; private set; }
  81:  
  82:  
  83:     /// <summary>
  84:     /// Creates and adds a few ItemViewModel objects into the Items collection.
  85:     /// </summary>
  86:     public void LoadLinkedInData()
  87:     {
  88:         // Sample data; replace with real data
  89:         this.LinkedIn.Add(new ItemViewModel() { Name = "Daniel Vaughan", ImagePath = "/Networks/LinkedIn/1.jpg", Details = "MVP" });
  90:         this.LinkedIn.Add(new ItemViewModel() { Name = "Pavan Pareta", ImagePath = "/Networks/LinkedIn/2.jpg", Details = "MVP" });
  91:         this.LinkedIn.Add(new ItemViewModel() { Name = "Boryana Miloshevska", ImagePath = "/Networks/LinkedIn/3.jpg", Details = "MVP" });
  92:         this.LinkedIn.Add(new ItemViewModel() { Name = "Dhananjay Kumar", ImagePath = "/Networks/LinkedIn/4.jpg", Details = "MVP" });
  93:         this.LinkedIn.Add(new ItemViewModel() { Name = "Laurent Bugnion", ImagePath = "/Networks/LinkedIn/5.jpg", Details = "MVP" });
  94:         this.IsDataLoaded = true;
  95:     }
  96:  
  97:     /// <summary>
  98:     /// A collection for ItemViewModel objects.
  99:     /// </summary>
 100:     public ObservableCollection<ItemViewModel> Twitter { get; private set; }
 101:  
 102:     /// <summary>
 103:     /// Creates and adds a few ItemViewModel objects into the Items collection.
 104:     /// </summary>
 105:     public void LoadTwitterData()
 106:     {
 107:         // Sample data; replace with real data
 108:         this.Twitter.Add(new ItemViewModel() { Name = "Vesko Kolev", ImagePath = "/Networks/Twitter/0.jpg", Details = "SSE" });
 109:         this.Twitter.Add(new ItemViewModel() { Name = "Joel Ivory Johnson", ImagePath = "/Networks/Twitter/1.jpg", Details = "MVP" });
 110:         this.Twitter.Add(new ItemViewModel() { Name = "Rajesh Rao", ImagePath = "/Networks/Twitter/2.jpg", Details = "iPhone Dev Expert" });
 111:         this.Twitter.Add(new ItemViewModel() { Name = "Harish Ranganathan", ImagePath = "/Networks/Twitter/3.jpg", Details = "Evangelist, Microsoft India" });
 112:         this.Twitter.Add(new ItemViewModel() { Name = "Jouni Miettunen", ImagePath = "/Networks/Twitter/4.jpg", Details = "MVP" });
 113:         this.Twitter.Add(new ItemViewModel() { Name = "Babina Sebastian", ImagePath = "/Networks/Twitter/5.jpg", Details = "..." });
 114:         this.Twitter.Add(new ItemViewModel() { Name = "Rahul", ImagePath = "/Networks/Twitter/6.jpg", Details = "Teacher" });
 115:         this.Twitter.Add(new ItemViewModel() { Name = "Anand", ImagePath = "/Networks/Twitter/7.jpg", Details = "Teacher" });
 116:         this.Twitter.Add(new ItemViewModel() { Name = "Daniel Vaughan", ImagePath = "/Networks/Twitter/8.png", Details = "MVP" });
 117:         this.Twitter.Add(new ItemViewModel() { Name = "Ashish", ImagePath = "/Networks/Twitter/9.jpg", Details = "Lead" });
 118:         this.Twitter.Add(new ItemViewModel() { Name = "Paul Diston", ImagePath = "/Networks/Twitter/10.jpg", Details = "SSE" });
 119:         this.IsDataLoaded = true;
 120:     }
 121: }

Step: -10 code is ready to integrate with the panorama UI control, now we have to add required Panorama Items under the panorama control. For this application I have added 5 panorama items for index of social networks, Google+, Facebook, Linkedin and Twitter. See blow xaml code snippet.



   1: <controls:Panorama x:Name="pnrmNetwork" Title="my friend(s)">
   2:  
   3:     <controls:Panorama.Background>
   4:         <ImageBrush ImageSource="/WP_PanoramaApp;component/PanoramaBackground.png"/>
   5:     </controls:Panorama.Background>
   6:             <!--Panorama item one-->
   7:             <controls:PanoramaItem Header="My Networks" Foreground="Blue">
   8:                 <!--Double line list with text wrapping-->
   9:                 <ListBox Margin="0,0,-12,0" ItemsSource="{Binding Items}">
  10:                     <ListBox.ItemTemplate>
  11:                         <DataTemplate>
  12:                             <StackPanel Margin="0,0,0,5" Width="432" Height="78">
  13:                                 <TextBlock Text="{Binding Name}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
  14:                             </StackPanel>
  15:                         </DataTemplate>
  16:                     </ListBox.ItemTemplate>
  17:                 </ListBox>
  18:             </controls:PanoramaItem>
  19:  
  20:             <!--Panorama item two (Google+)-->
  21:             <!--Use 'Orientation="Horizontal"' to enable a panel that lays out horizontally-->
  22:             <controls:PanoramaItem Header="Goolge+" Foreground="Crimson">
  23:                 <!--Double line list with image placeholder and text wrapping-->
  24:                 <ListBox Margin="0,0,-12,0" ItemsSource="{Binding GooglePlusItems}">
  25:                     <ListBox.ItemTemplate>
  26:                         <DataTemplate>
  27:                             <StackPanel Orientation="Horizontal" Margin="0,0,0,17">
  28:                                 <Image Width="100" Height="100" Source="{Binding ImagePath}"></Image>
  29:                                 <StackPanel Width="311">
  30:                                     <TextBlock Text="{Binding Name}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
  31:                                     <TextBlock Text="{Binding Details}" TextWrapping="NoWrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
  32:                                 </StackPanel>
  33:                             </StackPanel>
  34:                         </DataTemplate>
  35:                     </ListBox.ItemTemplate>
  36:                 </ListBox>
  37:             </controls:PanoramaItem>
  38:  
  39:             <!--Panorama item three (LinkedIn)-->
  40:             <!--Use 'Orientation="Horizontal"' to enable a panel that lays out horizontally-->
  41:             <controls:PanoramaItem Header="LinkedIn" Foreground="SpringGreen">
  42:                 <!--Double line list with image placeholder and text wrapping-->
  43:                 <ListBox Margin="0,0,-12,0" ItemsSource="{Binding LinkedIn}">
  44:                     <ListBox.ItemTemplate>
  45:                         <DataTemplate>
  46:                             <StackPanel Orientation="Horizontal" Margin="0,0,0,17">
  47:                                 <Image Width="100" Height="100" Source="{Binding ImagePath}"></Image>
  48:                                 <!--Replace rectangle with image-->
  49:                                 <StackPanel Width="311">
  50:                                     <TextBlock Text="{Binding Name}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
  51:                                     <TextBlock Text="{Binding Details}" TextWrapping="NoWrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
  52:                                 </StackPanel>
  53:                             </StackPanel>
  54:                         </DataTemplate>
  55:                     </ListBox.ItemTemplate>
  56:                 </ListBox>
  57:             </controls:PanoramaItem>
  58:  
  59:             <!--Panorama item four (Twitter)-->
  60:             <!--Use 'Orientation="Horizontal"' to enable a panel that lays out horizontally-->
  61:             <controls:PanoramaItem Header="Twitter" Foreground="Coral">
  62:                 <!--Double line list with image placeholder and text wrapping-->
  63:                 <ListBox Margin="0,0,-12,0" ItemsSource="{Binding Twitter}">
  64:                     <ListBox.ItemTemplate>
  65:                         <DataTemplate>
  66:                             <StackPanel Orientation="Horizontal" Margin="0,0,0,17">
  67:                                 <!--Replace rectangle with image-->
  68:                                 <Image Width="100" Height="100" Source="{Binding ImagePath}"></Image>
  69:                                 <StackPanel Width="311">
  70:                                     <TextBlock Text="{Binding Name}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
  71:                                     <TextBlock Text="{Binding Details}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
  72:                                 </StackPanel>
  73:                             </StackPanel>
  74:                         </DataTemplate>
  75:                     </ListBox.ItemTemplate>
  76:                 </ListBox>
  77:             </controls:PanoramaItem>
  78:  
  79:             <!--Panorama item five (Facebook)-->
  80:             <!--Use 'Orientation="Horizontal"' to enable a panel that lays out horizontally-->
  81:             <controls:PanoramaItem Header="Facebook" Foreground="Aquamarine">
  82:                 <!--Double line list with image placeholder and text wrapping-->
  83:                 <ListBox Margin="0,0,-12,0" ItemsSource="{Binding FacebookItems}">
  84:                     <ListBox.ItemTemplate>
  85:                         <DataTemplate>
  86:                             <StackPanel Orientation="Horizontal" Margin="0,0,0,17">
  87:                                 <!--Replace rectangle with image-->
  88:                                 <Image Width="100" Height="100" Source="{Binding ImagePath}"></Image>
  89:                                 <StackPanel Width="311">
  90:                                     <TextBlock Text="{Binding Name}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
  91:                                     <TextBlock Text="{Binding Details}" TextWrapping="NoWrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
  92:                                 </StackPanel>
  93:                             </StackPanel>
  94:                         </DataTemplate>
  95:                     </ListBox.ItemTemplate>
  96:                 </ListBox>
  97:  
  98:         </controls:PanoramaItem>
  99:  
 100: </controls:Panorama>

WP_04

Step: - 11 double click on Panorama Application Button and write code in code behind use below code snippet for navigate the panorama page.



   1: private void btnPanoramaApplication(object sender, RoutedEventArgs e)
   2: {
   3:     this.NavigationService.Navigate(new Uri("/views/PanoramaPage1.xaml", 
   4:     UriKind.Relative));
   5: }

Important: Need to assign DataContext in the PanoramaPage1 constructor. The

DataContext allow a property that serves as a simple means of accessing individual instances of the ItemViewModel class through a collection declared to be of type ObservableCollection <ItemViewModel>.

Step:-12 Now run the application using F5 button and navigate the panorama application.

WP_09_13


Download Article and Code here



Thank you for your time.

8 comments:

gaurav said...

Really this is very manfully information about this device..interesting post..thanks for sharing here..
logo design perth

Movies Gallery 2011 said...

Nice one. Thanks for the share.
Android apps development| Android app development companies|

sindia said...

yeah,the post is really helpful but i want to know that is it possible for the button also to stretch between 2 screens like you have done with textblocks.
thanks

Deepika Ellur said...
This comment has been removed by the author.
Deepika Ellur said...

Thanks for sharing the article.It's helpful and works perfectly fine. Can each of the ItemViewModel be made clickable to navigate to any other xaml page?

Pavan Pareta said...

Yes @Deepika! it could be clickable, in that case you have to add an command action class to your project and add an event to list control then Bind it (e.i. selected index event) to view, then only you can able to write your own logic in ItemViewModel class to navigate the another page.

~ Pavan

Deepika Ellur said...

Well I'm a beginner @Pavan , I' ll see through what can be done. Thanks far such a quick response.

Uchiha Itachi said...

This make me recalls the UI panorama control in C#.