Wednesday, April 24, 2013

Detect the screen resolution for Windows Phone OS 7.1 applications

    As you probably know Windows Phone 7.1 applications run perfectly on Windows Phone 8 devices. This means that your application/s could run on multiple display resolutions (which are the resolutions supported by Windows Phone 8 devices). If you want to take advantage of the new resolutions (for example downloading higher quality images for higher resolutions devices, fix some minor UI anomalies on higher resolutions) you will need to know the ScaleFactor of the device. The property is only available in the Windows Phone 8.0 SDK, but the good news is that you can access it using reflection.

Solution:
We retrieve the Get method of the ScaleFactor property and invoke it only if the application is running on an Windows Phone 8 device.

Here is the source code:
  public static Size DisplayResolution  
     {  
       get  
       {  
         if (Environment.OSVersion.Version.Major<8)  
           return new Size(480,800);  
         int scaleFactor=(int) GetProperty(Application.Current.Host.Content, "ScaleFactor");  
         switch (scaleFactor)  
         {  
           case 100:  
             return new Size(480, 800);  
           case 150:  
             return new Size(720, 1280);  
           case 160:  
             return new Size(768, 1280);  
         }  
         return new Size(480, 800);  
       }  
     }  
     private static object GetProperty(object instance, string name)  
     {  
       var getMethod= instance.GetType().GetProperty(name).GetGetMethod();  
       return getMethod.Invoke(instance, null);  
     }  

I am also attaching a small sample Windows Phone OS 7.1 test project.


SOURCE CODE

P.S. I think Telerik could use this method to fix this RadToolTip visual anomaly (the 1 pixel width lines that I have filled with blue for contrast) :


NAMASTE

Wednesday, April 17, 2013

3 ways to force the WebBrowser control to logout from Facebook

     Decided to write this post because it took me some time to find the answer. Maybe you already know that if you use OAuth Facebook connect inside your Windows Phone application there is one step where you use the WebBrowser control to let the user authenticate on the Facebook server and authorize your app. The "problem" presents itself when you want to link another user because the WebBrowser control has already memorized the old credentials and will automatically use them. What needs to be done is to logout the old user from the WebBrowser without actually telling the user to go on the web page and click logout. I have found 3 easy ways to do that: the first two will work on both Windows Phone 7.x and Windows Phone 8 and are Facebook specific and the third one will only work on Windows Phone 8 (generic method for OAuth providers). The 3 methods can use the WebBrowser control headless (you don't actually have to show the WebBrowser control to the user and don't even have to have the webbrowser attached to a Page):  

Method 1: described by Rene Schulte in this blog post  
The method constructs the logout Uri using your AppId and a SessionKey that is obtained from the AccessToken you got when the user authenticated.

Get the SessionKey:
  private static string ExtractSessionKeyFromAccessToken(string accessToken)  
     {  
       if (!String.IsNullOrEmpty(accessToken))  
       {  
         var parts = accessToken.Split('|');  
         if (parts.Length > 2)  
         {  
           return parts[1];  
         }  
       }  
       return String.Empty;  
     }  

Obtain the logout Uri:
  public Uri GetLogoutUri(FacebookCredentials credentials)  
     {  
       var sessionkey = ExtractSessionKeyFromAccessToken(credentials.AccessToken);  
       var url = String.Format("http://facebook.com/logout.php?app_key={0}&session_key={1}&next={2}", EndpointData.FacebookAppId, sessionkey, EndpointData.FacebookLogoutCallbackUrl);  
       return new Uri(url);  
     }  

Make the WebBrowser navigate to the logout Uri:
 Browser.Navigate(FacebookService.GetLogoutUri(EndpointData.Settings.Facebook));  

Method 2:
If for some reason you don't have the Facebook AppId available (my case) you can use the WebBrowser to navigate to the Logout page https://www.facebook.com/logout.php and after the page gets loaded you just execute the script document.forms['logout_form']:
 wb.LoadCompleted += wb_LoadCompleted;  
 wb.Navigate(new Uri("https://www.facebook.com/logout.php"));  
Once the page gets loaded:
 void wb_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)  
     {  
       wb.LoadCompleted -= wb_LoadCompleted;  
       if (wb.SaveToString().Contains("logout_form"))  
         wb.InvokeScript("eval", "document.forms['logout_form'].submit();");  
     }  

Method 3:
This is the easiest one, but will only work on Windows Phone 8: call the new WebBrowser async method ClearCookiesAsync(). This method works for every OAuth provider (Dropbox, Box, Skydrive, Picasa, Flickr, Google Drive... infinite list).

NAMASTE

Tuesday, April 2, 2013

Smooth scrolling content on Windows Phone

     Gotta say that I am not 100% satisfied about the title of this blog post, but since I haven't found a better one I will use this one (don't get it wrong windows phone has smooth scrolling implemented). This post is focusing on how to smooth scroll the content of a ScrollViewer. If you are using the ScrollViewer you know that it already has the method ScrollToVerticalOffset that can be used to manually scroll the content but this method doesn't have any animation implemented so you will see only a fast redraw of the new content without getting the "feeling" that the content scrolled to the new position. The easiest way to achieve this task would be using a StoryBoard with an Animation on the property VerticalOffset of the ScrollViewer, but VerticalOffset is a read-only property so it cannot be set and therefore cannot be used for animation.
     The solution I found was to build a custom control and add a custom property that can be used as a target for a DoubleAnimation. The attached sample (see the link at the end of the post) is using a ListBox as the content of my Custom Control but you can use anything else inside the control (a better approach for the ListBox would be to create a custom control derived directly from ListBox and use the built-in ScrollViewer). 
      Let's start from the XAML part of the User Control:

  <ScrollViewer x:Name="scroller">  
     <ContentPresenter Content="{Binding ContentArea, ElementName=userControl}"/>  
  </ScrollViewer>  

    So we have a ScrollViewer which inside has a ContentPreseter that has its content binded to the control's property ContentArea. Now let us have a look at the .cs code.

 public static readonly DependencyProperty VerticalOffsetProperty = DependencyProperty.Register("VerticalOffset",  
       typeof(double), typeof(SmoothScroller), new PropertyMetadata(VerticalOffsetPropertyChanged));  
     public double VerticalOffset  
     {  
       get { return (double)this.GetValue(VerticalOffsetProperty); }  
       set { this.SetValue(VerticalOffsetProperty, value); }  
     }  
     private static void VerticalOffsetPropertyChanged(object sender, DependencyPropertyChangedEventArgs args)  
     {  
       SmoothScroller cThis = sender as SmoothScroller;  
       cThis.scroller.ScrollToVerticalOffset((double)args.NewValue);  
     }  
     public static readonly DependencyProperty ContentAreaProperty = DependencyProperty.Register("ContentArea", typeof(object), typeof(SmoothScroller), null);  
     public object ContentArea  
     {  
       get { return (object)GetValue(ContentAreaProperty); }  
       set { SetValue(ContentAreaProperty, value); }  
     }  

     The property that we will use for animation is the VerticalOffset that uses the method VerticalOffsetPropertyChanged to scroll to a vertical offset inside the control's scroller. The property VerticalOffset can be animated and we will use it to smooth scroll the ListBox content.
     Here is the content of the MainPage.xaml

  <uc:SmoothScroller x:Name="smoothScroller">  
         <uc:SmoothScroller.ContentArea>  
         <ListBox x:Name="lstItems" ItemsSource="{Binding Items}" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemTemplate="{StaticResource DataTemplate}" >  
           <ListBox.ItemContainerStyle>  
             <Style TargetType="ListBoxItem">  
               <Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>  
             </Style>  
           </ListBox.ItemContainerStyle>  
         </ListBox>  
         </uc:SmoothScroller.ContentArea>  
       </uc:SmoothScroller>  

     So we have the SmoothScroller control which inside its ContentArea has a ListBox (the ListBox has it's scrollviewer disabled). What the sample does is it is changing the selected item every second (incrementing the selectedindex) and scrolls the content so that the newly SelectedItem is centered in the ScrollViewer. Here is the code used for scrolling:

  void dt_Tick(object sender, EventArgs e)  
     {  
       ((ListBox)smoothScroller.ContentArea).SelectedIndex = idx;  
       var container = ((ListBox)smoothScroller.ContentArea).ItemContainerGenerator.ContainerFromIndex(idx) as FrameworkElement;  
       var transform = container.TransformToVisual(smoothScroller.scroller);  
       var elementLocation = transform.Transform(new Point(0, 0));  
       double newVerticalOffset = elementLocation.Y + smoothScroller.scroller.VerticalOffset - smoothScroller.scroller.ActualHeight / 2 ;  
       //Animate transition  
       DoubleAnimation verticalAnimation = new DoubleAnimation();  
       verticalAnimation.From = smoothScroller.scroller.VerticalOffset;  
       verticalAnimation.To = newVerticalOffset;  
       verticalAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(500));  
       var sb = new Storyboard();  
       sb.Children.Add(verticalAnimation);  
       Storyboard.SetTarget(verticalAnimation, smoothScroller);  
       Storyboard.SetTargetProperty(verticalAnimation, new PropertyPath(SmoothScroller.VerticalOffsetProperty));  
       sb.Begin();  
       idx++;  
       if (idx >= 56)  
         dt.Stop();  
     }  

     Pretty basic: select the new index in the ListBox, calculate the new VerticalOffset so that the newly selected item is centered in our scrollviewer and create and start a 500ms animation for the SmoothScroller.VerticalOffsetProperty. Anyway I am sure that you will better understand how it works when you will try the sample code.
     The sample is far from perfect (before starting a new animation I should check if the old one finished, should not automatically scroll when the user is manipulating the list,...).
     Here is a screenshot from the sample:

As usual let me know if you need help. The code works on both Windows Phone 7.1 and Windows Phone 8 SDK.

SOURCE CODE