Introduction
This article is meant for .net developer who are using windows 8 and Visual studio 2011 for developing metro style app. In this article ,I will explain brief information about the metro app and demonstrate the Sample metro app design.
What is Metro Apps
Metro style apps are full screen apps tailored to your users' needs, tailored to the device they run on, tailored for touch interaction, and tailored to the Windows user interface. Windows helps you interact with your users, and your users interact with your app." from MSDN.
All about developing for Windows 8: http://www.buildwindows.com/
When developing Metro apps you can chose from a variety of languages and technologies:
- HTML + JS + CSS
- XAML + (C# or VB)
- XAML + (C++ or C)
Prerequisites
About My Sample FaceBook PhotoAlbum Metro App
- This Sample Metro app have three screens ,first one 'Facebook Login' screen and next 'Album' screen and last one is 'Photo' screen
- As i like XMAL and C# hence i am developing this sample metro application in XMAL and C# .
- I am using the FaceBook C# SDK to get albums and photos from FaceBook.
Step 1 :Create Project
With the new VS 2011 Developer tool, you will be able to create Windows Metro Style App in C# ,XMAL , Javacsript ,VB . Here i am using C# Grid Template for designing sample FaceBook Photo Album metro style app.
Step 2 Add Client Internet Capabilities
As My Metro App fetch the data from FaceBook hence App need's client internet connection to fetch data from facebook.
To enable to internet capabilities in metro app , double click on Package.appxmanifest file and under the Capabilities tab ,mark internet(client) as checked.
Step 3: Add login page
This page is used to display facebook login dialogue box and authenticate the face book user.
LoginPage.xaml page have Login() method which is used to display the Facebook login dialogue box ,authenticate the Facebook user and fetch the albums ,photos from Facebook.
Below code display the FaceBook Login box
string faceBookAppId = "285516851528865";
string[] extendedPermissions = new[] { "user_about_me", "offline_access", "user_photos", "publish_stream", "friends_photos" };
string redirectUri = "https://www.facebook.com/connect/login_success.html";
System.Uri EndUri = new Uri(redirectUri);
var oauth = new FacebookClient { AppId = faceBookAppId };
var parameters = new Dictionary<string, object>
{
{"client_id",faceBookAppId},
{ "response_type", "token" },
{ "display", "popup" },
{"redirect_uri",redirectUri}
};
if (extendedPermissions != null && extendedPermissions.Length > 0)
{
var scope = new StringBuilder();
scope.Append(string.Join(",", extendedPermissions));
parameters["scope"] = scope.ToString();
}
Uri loginUrl = oauth.GetLoginUrl(parameters);
WebAuthenticationResult WebAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(
WebAuthenticationOptions.None,
loginUrl, EndUri
);
Below code shows that once FaceBook authentication is successful ,it will navigate to Album screen (GroupedItemsPage.xaml)
if (WebAuthenticationResult.ResponseStatus == WebAuthenticationStatus.Success)
{
FacebookOAuthResult fbAuthResult = oauth.ParseOAuthCallbackUrl(new Uri(WebAuthenticationResult.ResponseData.ToString()));
var fbClient = new FacebookClient(fbAuthResult.AccessToken);
dynamic fbAlbums = await fbClient.GetTaskAsync("/me/albums");
DataSource dataSource = new DataSource();
foreach (var a in fbAlbums.data)
{
var fbPhotos = await fbClient.GetTaskAsync(a.id + "/photos");
string albumPath="";
foreach (var p in fbPhotos.data)
{
albumPath = p.source;
break;
}
var album = new Album(a.name, albumPath);
foreach (var p in fbPhotos.data)
album.Photos.Add(new Photo("", p.source, album));
dataSource.Albums.Add(album);
}
Frame.Navigate(typeof(GroupedphotosPage), dataSource.Albums);
Step4 : Customize the GroupedItemsPage.xaml and ItemDetailPage.xaml file to display Albums and Photos
- GroupedItemsPage.xaml page is used to display Facebook user Albums.
- ItemDetailPage.xaml page is used to display Facebook user album photos.
GroupedItemsPage.xaml Preview of Album screen
When 'GroupEdItemPage' page loads store the passed data into DataViewModel["Albums"] , we will use this value in design page to display the User Album's
protected override void OnNavigatedTo(NavigationEventArgs e)
{
this.DefaultViewModel["Albums"] = e.Parameter;
}
Creating the UserControl ResourcesResources for Album collection , we will use this resource in GridView to display the Albums.
<UserControl.Resources>
<!-- Collection of grouped photos displayed by this page -->
<CollectionViewSource
x:Name="groupedphotosViewSource"
Source="{Binding Albums}"
IsSourceGrouped="False"
ItemsPath="Photos"
d:Source="{Binding Albums, Source={d:DesignInstance Type=data:DataSource, IsDesignTimeCreatable=True}}"/>
</UserControl.Resources>
Displaying the Albums in Gridview
<GridView
x:Name="itemGridView"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Face Book Photo Album"
Margin="116,0,40,46"
ItemsSource="{Binding Source={StaticResource groupedphotosViewSource}}"
ItemTemplate="{StaticResource Standard250x250ItemTemplate}"
SelectionMode="None"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid Orientation="Vertical" Margin="0,0,80,0"/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</GridView.GroupStyle>
</GridView>
When user click on Album , following method invoked which navigates to Photo screen.
void ItemView_ItemClick(object sender, ItemClickEventArgs e)
{
this.Frame.Navigate(typeof(ItemDetailPage), e.ClickedItem);
}
ItemDetailPage.xaml
Preview of photo screen
When 'ItemDetailPage' page loads store the Selected Album and Photos object into the DefaultViewModel , we will use these object to display the photos on screen
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var album = (Album)e.Parameter;
this.DefaultViewModel["Album"] = album;
this.DefaultViewModel["Photos"] = album.Photos ;
}
Creating static resource for photo, we will use this resource in FilpView to display the Photos
<UserControl.Resources>
<!-- Collection of items displayed by this page -->
<CollectionViewSource
x:Name="itemsViewSource"
Source="{Binding Photos}"
d:Source="{Binding Album[0].Photos, Source={d:DesignInstance Type=data:DataSource, IsDesignTimeCreatable=True}}"/>
</UserControl.Resources>
Displaying the Photos in FilpView
<FlipView
x:Name="flipView"
AutomationProperties.AutomationId="ItemsFlipView"
AutomationProperties.Name="Item Details"
Grid.Row="1"
Margin="0,-3,0,0"
ItemsSource="{Binding Source={StaticResource itemsViewSource}}">
<FlipView.ItemTemplate>
<DataTemplate>
<!--
UserControl chosen as the templated item because it supports visual state management
Loaded/unloaded events explicitly subscribe to view state updates from the page
-->
<UserControl Loaded="StartLayoutUpdates" Unloaded="StopLayoutUpdates">
<ScrollViewer x:Name="scrollViewer" Style="{StaticResource HorizontalScrollViewerStyle}" Grid.Row="1">
<!-- Content is allowed to flow across as many columns as needed -->
<common:RichTextColumns x:Name="richTextColumns" Margin="117,0,117,47">
<RichTextBlock x:Name="richTextBlock" Width="560" Style="{StaticResource ItemRichTextStyle}">
<Paragraph LineStackingStrategy="MaxHeight">
<InlineUIContainer>
<Image x:Name="image" MaxHeight="480" Margin="0,20,0,10" Stretch="Uniform" Source="{Binding Image}"/>
</InlineUIContainer>
</Paragraph>
</RichTextBlock>
<!-- Additional columns are created from this template -->
<common:RichTextColumns.ColumnTemplate>
<DataTemplate>
<RichTextBlockOverflow Width="560" Margin="80,0,0,0">
<RichTextBlockOverflow.RenderTransform>
<TranslateTransform X="-1" Y="4"/>
</RichTextBlockOverflow.RenderTransform>
</RichTextBlockOverflow>
</DataTemplate>
</common:RichTextColumns.ColumnTemplate>
</common:RichTextColumns>
<VisualStateManager.VisualStateGroups>
<!-- Visual states reflect the application's view state inside the FlipView -->
<VisualStateGroup>
<VisualState x:Name="FullScreenLandscape"/>
<VisualState x:Name="Filled"/>
<!-- Respect the narrower 100-pixel margin convention for portrait -->
<VisualState x:Name="FullScreenPortrait">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="richTextColumns" Storyboard.TargetProperty="Margin">
<DiscreteObjectKeyFrame KeyTime="0" Value="97,0,87,57"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="image" Storyboard.TargetProperty="MaxHeight">
<DiscreteObjectKeyFrame KeyTime="0" Value="400"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<!-- When snapped, the content is reformatted and scrolls vertically -->
<VisualState x:Name="Snapped">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="richTextColumns" Storyboard.TargetProperty="Margin">
<DiscreteObjectKeyFrame KeyTime="0" Value="17,0,17,57"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="scrollViewer" Storyboard.TargetProperty="Style">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource VerticalScrollViewerStyle}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="richTextBlock" Storyboard.TargetProperty="Width">
<DiscreteObjectKeyFrame KeyTime="0" Value="280"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="image" Storyboard.TargetProperty="MaxHeight">
<DiscreteObjectKeyFrame KeyTime="0" Value="160"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</ScrollViewer>
</UserControl>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
Step5: Set LoginPage.xmal page as startup page
Open the App.xmal.cs and set the LoginPage As startup paage, as shown below
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
var sampleData = new DataSource();
if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
}
var rootFrame = new Frame();
rootFrame.Navigate(typeof(LoginPage));
Window.Current.Content = rootFrame;
Window.Current.Activate();
}
Attached Code
SampleFaceBookPhoto.zip contain the all the my SampleFacebookPhotoalbumm Metro App files.
History
Keep a running update of any changes or improvements you've
made here.