08 March 2011

Simple Windows Phone 7 / Silverlight drag/flick behavior

In this post I describe a behavior that will essentially make anything draggable and ‘flickable’, that is, you can drag a GUI element along with your finger and it seems to have a little inertia when you let it go. The behavior mimics part of the Microsoft Surface’s ScatterView functionality and will feature in the small children’s game for Windows Phone 7 game I am currently developing. As a bonus, you will see some generally applicable extension methods for creating storyboards and translation GUI elements too.

I have not tried this in Silverlight but I am not doing anything Windows Phone 7 specific as far as I am aware, so I guess it should work in plain Silverlight too.

Setting the stage

I created a simple solution containing three assemblies: a Windows Phone application, a class library “LocalJoost” holding my utilities including this behavior, and one containing Phone.Fx.Preview, not for the BindableApplicationBar this time, but because I make extensive use of its VisualTreeHelperExtensions. You will also need System.Windows.Interactivity.dll, which I nicked from the MVVMLight toolkit.

Extensions for FrameworkElement

First of all, I created a set of extension methods on FrameworkElement that allow me to easily find and manipulate an attached CompositeTransform from code. A CompositeTransform is only one of the many possibilities to manipulate a GUI element, but it basically is just a descriptor of how far from its original place the GUI element should be drawn, if it should be rotated, scaled, etc. I only use the translation attributes – to move it around.

To be able to translated and animated, the object must have a CompositeTransform. Well, at least it must for the solution I have chosen. You will see later that the behavior checks for this transform and if it’s not present, it simply makes it. But you can also create it in XAML, of course.

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Linq;
using Phone7.Fx.Preview;

namespace LocalJoost.Utilities
{
  /// <summary>
  /// Class to help animations from code using the CompositeTransform
  /// </summary>
  public static class FrameworkElementExtensions
  {
    /// <summary>
    /// Finds the composite transform either direct
    /// or as part of a TransformGroup
    public static CompositeTransform GetCompositeTransform(
       this FrameworkElement fe)
    {
      if (fe.RenderTransform != null)
      {
        var tt = fe.RenderTransform as CompositeTransform;
        if( tt != null) return tt;

        var tg = fe.RenderTransform as TransformGroup;
        if (tg != null)
        {
          return tg.Children.OfType<CompositeTransform>().FirstOrDefault();
        }
      }
      return null;
    }

    /// <summary>
    /// Gets the point to where FrameworkElement is translated
    /// </summary>
    public static Point GetTranslatePoint(this FrameworkElement fe)
    {
      var translate = fe.GetCompositeTransform();
      if (translate == null) 
         throw new ArgumentNullException("CompositeTransform");

      return new Point(
        (double) translate.GetValue(CompositeTransform.TranslateXProperty),
        (double) translate.GetValue(CompositeTransform.TranslateYProperty));

    }

    /// <summary>
    /// Translates a FrameworkElement to a new location
    /// </summary>
    public static void SetTranslatePoint(this FrameworkElement fe, Point p)
    {
      var translate = fe.GetCompositeTransform();
      if (translate == null) 
         throw new ArgumentNullException("CompositeTransform");

      translate.SetValue(CompositeTransform.TranslateXProperty, p.X);
      translate.SetValue(CompositeTransform.TranslateYProperty, p.Y);
    }

    /// <summary>
    /// Translates a FrameworkElement to a new location
    /// </summary>
    public static void SetTranslatePoint(
       this FrameworkElement fe, double x, double y )
    {
      fe.SetTranslatePoint(new Point(x, y));
    }

    public static FrameworkElement GetElementToAnimate( 
      this FrameworkElement fe)
    {
      var parent = fe.GetVisualParent();
      return parent is ContentPresenter ? parent : fe;
    }
  }
}

Note in the last method that the element to animated is either the element itself or a ContentPresenter that is its parent. I noticed that stuff created by databinding is always surrounded by a ContentPresenter, and that animating an object within its ContentPresenter does not work – logically. So then then the ContentPresenter is animated in stead – dragging its contents with it.

Extensions for StoryBoard

Next up, a set of extension methods to easily create translation animations, and add them to storyboard:

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace LocalJoost.Utilities
{
  public static class StoryboardExtensions
  {
    /// <summary>
    /// Create a animation with a default easing function
    /// </summary>
    public static Timeline CreateDoubleAnimation(this Storyboard storyboard,
      Duration duration, double from, double to)
    {
      return storyboard.CreateDoubleAnimation(duration, from, to,
        new SineEase
        {
          EasingMode = EasingMode.EaseInOut
        });
    }

    /// <summary>
    /// Create a animation with a custom easing function
    /// </summary>
    public static Timeline CreateDoubleAnimation(this Storyboard storyboard, 
      Duration duration, double from, double to, IEasingFunction easingFunction)
    {
      var animation = new DoubleAnimation
      {
        From = from,
        To = to,
        Duration = duration,
        EasingFunction = easingFunction
      };
      return animation;
    }

    /// <summary>
    /// Add an animation to an existing storyboard
    /// </summary>
    public static void AddAnimation(this Storyboard storyboard, 
      DependencyObject item, Timeline t, DependencyProperty p)
    {
      if (p == null) throw new ArgumentNullException("p");
      Storyboard.SetTarget(t, item);
      Storyboard.SetTargetProperty(t, new PropertyPath(p));
      storyboard.Children.Add(t);
    }

    /// <summary>
    /// Add a translation animation to an existing storyboard with a 
    /// default easing function
    /// </summary>
    public static void AddTranslationAnimation(this Storyboard storyboard, 
      FrameworkElement fe, Point from, Point to, Duration duration)
    {
      storyboard.AddTranslationAnimation(fe, from, to, duration, null);
    }

    /// <summary>
    /// Add a translation animation to an existing storyboard with a 
    /// custom easing function
    /// </summary>
    public static void AddTranslationAnimation(this Storyboard storyboard, 
      FrameworkElement fe, Point from, Point to, Duration duration,
      IEasingFunction easingFunction)
    {
      storyboard.AddAnimation(fe.RenderTransform,
             storyboard.CreateDoubleAnimation(duration, from.X, to.X, 
                                              easingFunction),
              CompositeTransform.TranslateXProperty);
      storyboard.AddAnimation(fe.RenderTransform,
            storyboard.CreateDoubleAnimation(duration, from.Y, to.Y, 
                                             easingFunction),
              CompositeTransform.TranslateYProperty);
    }
  }
}

You will probably only use the last two methods. Create an empty StoryBoard, pop in a FrameworkElement, the “from” and “to” point, the time it should take and optionally an easing function, then start your StoryBoard and off your GUI element goes.

An easing function, by the way, describes a bit about the way an objects starts, stops and moves. No easing function means the object moves from start to end with a constant speed. If you take a SineEase with an EaseInOut mode, it will first move slowly, than increase speed, and at the end it more or less slowly comes to a halt. This makes for a more fluid behavior. There are about a gazillion easing functions, and I encourage you to explore them with Expression Blend.

The DragFlickBehavior itself

Then finally the behavior itself, which is surprisingly simple now all the groundwork has been laid by the extension methods:

using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Media;
using System.Windows.Media.Animation;
using LocalJoost.Utilities;

namespace LocalJoost.Behaviors
{
  public class DragFlickBehavior: Behavior<FrameworkElement>
  {
    private FrameworkElement _elementToAnimate;
    
    protected override void OnAttached()
    {
      base.OnAttached();
      AssociatedObject.Loaded += AssociatedObjectLoaded;
      AssociatedObject.ManipulationDelta += 
         AssociatedObjectManipulationDelta;
      AssociatedObject.ManipulationCompleted += 
         AssociatedObjectManipulationCompleted;
    }
    
    void AssociatedObjectLoaded(object sender, RoutedEventArgs e)
    {
      _elementToAnimate = AssociatedObject.GetElementToAnimate();
      if (! (_elementToAnimate.RenderTransform is CompositeTransform))
      {
        _elementToAnimate.RenderTransform = new CompositeTransform();
        _elementToAnimate.RenderTransformOrigin = new Point(0.5, 0.5);
      }
    }

    void AssociatedObjectManipulationDelta(object sender, 
        ManipulationDeltaEventArgs e)
    {
      var dx = e.DeltaManipulation.Translation.X;
      var dy = e.DeltaManipulation.Translation.Y;
      var currentPosition = _elementToAnimate.GetTranslatePoint();
      _elementToAnimate.SetTranslatePoint(currentPosition.X + dx, 
         currentPosition.Y + dy);
    }

    private void AssociatedObjectManipulationCompleted(object sender, 
      ManipulationCompletedEventArgs e)
    {
      // Create a storyboard that will emulate a 'flick'
      var currentPosition = _elementToAnimate.GetTranslatePoint();
      var velocity = e.FinalVelocities.LinearVelocity;
      var storyboard = new Storyboard { FillBehavior = FillBehavior.HoldEnd };

      var to = new Point(currentPosition.X + (velocity.X / BrakeSpeed),
        currentPosition.Y + (velocity.Y / BrakeSpeed));
      storyboard.AddTranslationAnimation(
        _elementToAnimate, currentPosition, to, 
        new Duration(TimeSpan.FromMilliseconds(500)), 
        new CubicEase {EasingMode = EasingMode.EaseOut});
      storyboard.Begin();
    }


    protected override void OnDetaching()
    {
      AssociatedObject.Loaded -= AssociatedObjectLoaded;
      AssociatedObject.ManipulationCompleted -= 
          AssociatedObjectManipulationCompleted;
      AssociatedObject.ManipulationDelta-= 
          AssociatedObjectManipulationDelta;

      base.OnDetaching();
    }

    #region BrakeSpeed
    public const string BrakeSpeedPropertyName = "BrakeSpeed";

    /// <summary>
    /// Describes how fast the element should brake, i.e. come to rest,
    /// after a flick. Higher = apply more brake ;-)
    /// </summary>
    public int BrakeSpeed
    {
      get { return (int)GetValue(BrakeSpeedProperty); }
      set { SetValue(BrakeSpeedProperty, value); }
    }

    public static readonly DependencyProperty BrakeSpeedProperty = 
      DependencyProperty.Register(
      BrakeSpeedPropertyName,
      typeof(int),
      typeof(DragFlickBehavior),
      new PropertyMetadata(10));

    #endregion
  }
}

And half of it is a dependency property, too ;-). What this behavior does, is:

  • When attached, it checks which element to animate, checks for an CompositeTransform to be present and if not, simply create it.
  • While the element is being manipulated, change the translate point by the delta x and y of the drag event, therefore the element will follow your finger – and causing the element apparently to be ‘dragged’
  • When you stop dragging, it creates a simple storyboard that will move the element a bit further in the direction you last dragged it, seemingly causing a bit on inertia. It does that by looking at the FinalVelocities’s LinearVelocity property values. If you move it fast enough, it will move right out of the screen, never to return ;-). That’s more or less what I mean by ‘flick’. The BrakeSpeed property of the behavior determines how fast the element comes to a half. I find the default value 10 to have quite a natural feeling to it – on my phone, that is.

Demo

For the sample solution I fired up Expression Blend, dragged some elements on a Windows Phone 7 page and attached the behavior to everything - up to the page name and application name, as you can see in the demo video. That is not particularly useful in itself, but it drives home the point. Your designer can now have fun with this behavior ;-), and I hope I have showed you some little things on how to manipulate storyboard and elements from code in the process.

The DragFlickBehavior in action

05 March 2011

Easy access to WMAppManifest.xml App properties like version and title

Every Windows Phone 7 application must have an Application Manifest file called WMAppManifest.xml. In this you must state title, author, version and some other things. A quote from the link above:

“The primary purpose of this file is the following:

  • The Windows Phone Marketplace application submission process uses information from the manifest file. The manifest file supports the submission of applications to the Windows Phone Marketplace (including certification), device marketplace filtering, marketplace-to-device deployment, and device execution.
  • The information from the manifest file is used as the application metadata that will be stored in the application database.”

For some reason it’s not common knowledge that information in this file can accessed runtime as well. This can come in very handy, for example for showing a consistent app title and even more important, it’s version number. There are some examples of this to be found on the web but they are not very clear or pretty limited, so I cobbled together this little helper class to make retrieving attributes from the App tag a little easier:

using System.Collections.Generic;
using System.Xml.Linq;

namespace LocalJoost.Utilities
{
  /// <summary>
  /// A helper class to easily retrieve data from the WMAppManifest.xml
  /// App tag
  /// </summary>
  public class ManifestAppInfo
  {
    public ManifestAppInfo()
    {
    }

    static Dictionary<string, string> _properties;

    static Dictionary<string, string> Properties
    {
      get
      {
        if (null == _properties)
        {
          _properties = new Dictionary<string, string>();
          var appManifestXml = XDocument.Load("WMAppManifest.xml");
          using (var rdr = appManifestXml.CreateReader(ReaderOptions.None))
          {
            rdr.ReadToDescendant("App");
            if (!rdr.IsStartElement())
            {
              throw new System.FormatException(
                 "App tag not found in WMAppManifest.xml ");
            }
            rdr.MoveToFirstAttribute();
            while (rdr.MoveToNextAttribute())
            {
              _properties.Add(rdr.Name, rdr.Value);
            }
          }
        }
        return _properties;
      }
    }

    public string Version
    {
      get { return Properties["Version"]; }
    }

    public string ProductId
    {
      get { return Properties["ProductID"]; }
    }

    public string Title
    {
      get { return Properties["Title"]; }
    }

    public string TitleUc
    {
      get { return !string.IsNullOrEmpty(Title) ? 
                     Title.ToUpperInvariant() : null; }
    }

    public string Genre
    {
      get { return Properties["Genre"]; }
    }

    public string Description
    {
      get { return Properties["Description"]; }
    }

    public string Publisher
    {
      get { return Properties["Publisher"]; }
    }
  }
}

I got some feedback from Matthijs Hoekstra  on the Standard About Page that it actually showed the version number of the dll in which the AboutViewModel is stored, and not that of the app. This is because Assembly.GetExecutingAssembly() is used. There is also Assembly.GetCallingAssembly() but that shows the version of System.Windows.dll. What we need is Assembly.GetEntryAssembly() but that’s not available in the current version of the Windows Phone 7 framework. But we can now adapt the first part of the AboutViewModel as follows:

public class AboutViewModelBase : ViewModelBase
{
  private ManifestAppInfo _manifestAppInfo;
  public void LoadValuesFromResource<T>()
  {
    _manifestAppInfo = new ManifestAppInfo();
    var targetType = GetType();
    var sourceType = typeof(T);
    foreach (var targetProperty in targetType.GetProperties())
    {
      var sourceProperty = sourceType.GetProperty(targetProperty.Name, 
	     BindingFlags.Static | BindingFlags.Public);
      if (sourceProperty != null)
      {
        if (targetProperty.CanWrite)
        {
          targetProperty.SetValue(this, 
		    sourceProperty.GetValue(null, null), null);
        }
      }
    }
  }
  /// <Summary>A string value for the AppTitle</Summary>
  public string AppTitle
  {
    get
    {
      if (DesignerProperties.IsInDesignTool)
      {
        return "APPLICATION TITLE";
      }
      return _manifestAppInfo.Title;
      
    }
  }
  
  public string ApplicationVersion
  {
    get
    {
      if (DesignerProperties.IsInDesignTool)
        return "version x.x.x";

      var version = _manifestAppInfo.Version;
      return version.Substring(0, version.LastIndexOf("."));
    }
  }
}

And have the ViewModel show the version from the Application Manifest file regardless of actual assembly versions - as well as the title. You can even binding directly to its properties.

Now you might not want to use all of its properties directly in text – if your App Title shows up differently in different languages you still might want to get that from a resource file. That is why the LoadValuesFromResource method now checks if a property is writable. If you omit that check, it will try to write to every property for which a key with the same name can be found in the resource file – and if that’s now read-only, it will crash.

01 March 2011

Sharepoint Client Object Model: sites, roles, lists, documents, AD users and permissions

Recently I had my very first encounter with Sharepoint, and I cannot say it was a pleasant meeting. I was doing a proof of concept for a customer to manipulate Sharepoint from code using the new Sharepoint 2010 Client Object Model. Not that this is a particular unpleasant job in itself and neither is the API particulary bad (although definitely odd), but the MSDN documentation about the Client Object Model is far from self-explanatory, and lacks the – for me, at last –  most crucial part of educational material: simple how-to examples.

Most examples found elsewhere are either based on older API’s, incomplete and sometimes completely wrong. And you have to roam about half the internet to get pieces of code together. So I thought it would be a good idea to cobble together pieces from the POC into a comprehensive blog post with what I’ve learned, hoping to save other people the same quest.

Be aware that I learned this all just in the past few days so things are pretty crude at times. I am by no means a Sharepoint wizard - nor am I planning on becoming one :-).  The idea is just to show how it’s done. I think there are a lot of people out there who know how to do things better and more efficient than me: it just they don’t blog about it ;-)

This code was used to talk to a Sharepoint foundation on a domain controller outside the domain on which I actually ran the code.

Things covered in this post

  • Create a site
  • Retrieve a site by title
  • Retrieve a role by Role type
  • Retrieve a Sharepoint principal by Active Directory user or group name
  • Retrieve a document library by name
  • Retrieve a document library template by name
  • Create a document library and set permissions
  • Create a folder in a document library
  • Upload a file to a document library
  • Download a file from a document library
  • List all folders or files in a document library

Setting the stage

It started out making a “Sharepointhelper” class. The basics of this thing is a follows:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Security.Principal;
using System.Text;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Utilities;
using File = Microsoft.SharePoint.Client.File;

namespace TestSharepoint
{
  public class SharepointHelper
  {
    private ClientContext clientContext;
    private Web rootWeb;

    public SharepointHelper(string url, string username, string password)
    {
      clientContext = new ClientContext(url);
      var credentials = new NetworkCredential(username, password, "domain");
      clientContext.Credentials = credentials;
      rootWeb = clientContext.Web;
      clientContext.Load(rootWeb);
    }
  }
}

Creating the object should go like this:

var sh = new SharepointHelper("http://yourserver", "aUser", "hisPassword");

aUser must be a user with enough rights to perform sharepoint administration. I used the domain admin username and password and I assure you – that works ;-)

Create a site

public void CreateSite(string siteDescription, string siteTitle, string siteUrl)
{
  rootWeb = rootWeb.Webs.Add(new WebCreationInformation
    {
      Description = siteDescription,
      Title = siteTitle,
      Url = siteUrl,
      UseSamePermissionsAsParentSite = false
    });
  clientContext.ExecuteQuery();
}
Usage sample: 
sh.Create("My site description", "MySite", "mysiteurl");

Retrieve a site by title

public Web GetWebByTitle(string siteTitle)
{
  var query = clientContext.LoadQuery(
    rootWeb.Webs.Where(p => p.Title == siteTitle));
  clientContext.ExecuteQuery();
  return query.FirstOrDefault();
}
Usage sample: 
var w = sh.GetWebByTitle("MySite");

Retrieve role by Role type

private RoleDefinition GetRole(string siteTitle, RoleType rType)
{
  var web = GetWebByTitle(siteTitle);
  if (web != null)
  {
    var roleDefs = web.RoleDefinitions;
    var query = clientContext.LoadQuery(
        roleDefs.Where(p => p.RoleTypeKind == rType));
    clientContext.ExecuteQuery();
    return query.FirstOrDefault();
  }
  return null;
}
Usage sample: 
var r = sh.GetRole("MySite", RoleType.Contributor);
will get you the contributor role.

Retrieve a Sharepoint principal by Active Directory user or group name

Now this one took me a very long time. For some reason there is a static Utility.SearchPrincipals method that gets you a PrincipalInfo object, but you can never get to get a Principal object that you can use for setting permissions. I spent a long time scratching my head how to get around this before I found there is another way:
public Principal GetPrincipal(string name)
{
  if (web != null)
  {
    try
    {
      var principal = web.EnsureUser(name);
      clientContext.Load(principal);
      clientContext.ExecuteQuery();
      if (principal != null)
      {
        return principal;
      }
    }
    catch (ServerException){}
  }
  return null;
}
Usage sample: 
var g = sh.GetPrincipal("MyUserGroup");
var u = sh.GetPrincipal("MyUser");

This will, as you can see, get you either a user group’s principal or a single user’s principal. Since I was looking for a group’s principal it never occurred to me to try the “EnsureUser” method. If you don’t know what a Principal is – neither do I (at least not exactly) but I of think it as a descriptor of a user’s or group's credentials.

Retrieve a document library by name

public List GetDocumentLibrary(string siteTitle, string libraryName)
{
  var web = GetWebByTitle(siteTitle);
  if (web != null)
  {
    var query = clientContext.LoadQuery(
         web.Lists.Where(p => p.Title == libraryName));
    clientContext.ExecuteQuery();
    return query.FirstOrDefault();
  }
  return null;
}
Usage sample: 
var g = GetDocumentLibrary("MySite", "myDocumentLibrary");

Retrieve a document library template by name

public ListTemplate GetDocumentLibraryTemplate(Web web, string name)
{
  ListTemplateCollection ltc = web.ListTemplates;
  var listTemplates = clientContext.LoadQuery(
    ltc.Where(p => p.InternalName == name));
  clientContext.Load(ltc);
  clientContext.ExecuteQuery();
  return listTemplates.FirstOrDefault();
}
Usage sample: 
var t = sh.GetDocumentLibraryTemplate(web, "doclib");
This will get you the template for the document library type.

Create a document library and set permissions

Now this was what I actually had to prove in the POC, and you can see this as it uses a lot of the previous samples:

public bool CreateDocumentLibrary(string siteTitle, string libraryName, 
                                  string libraryDescription, string userGroup)
{
  var web = GetWebByTitle(siteTitle);
  if (web != null)
  {
    // First load all the list
    var lists = web.Lists;
    clientContext.Load(lists);
    clientContext.ExecuteQuery();

    // Create new lib based upon the doclib template
    var newList = lists.Add(new ListCreationInformation
      {
        Title = libraryName,
        Description = libraryDescription,
        TemplateType = 
          GetDocumentLibraryTemplate(web, "doclib").ListTemplateTypeKind
      });
    clientContext.ExecuteQuery();

    // Override default permission inheritance
    newList.BreakRoleInheritance(true, false);
    // Get principal for usergroup and the contributor role
    var principal = GetPrincipal(userGroup);
    var role = GetRole(siteTitle, RoleType.Contributor);
    
    // Add the role to the collection.
    var collRdb = new RoleDefinitionBindingCollection(clientContext) {role};
    var collRoleAssign = newList.RoleAssignments;
    collRoleAssign.Add(principal, collRdb);

    clientContext.ExecuteQuery();
    
    return true;
  }
  return false;
}
Usage sample: 
var result = sh.CreateDocumentLibrary("MySite", "myDocumentLibrary",
                                      "A very nice library", "MyUserGroup");

Which will create a document library “myDocumentLibrary” in “MySite” with a contributor role for “MyUserGroup”. Like I said, it’s pretty crude still here and there, but you get the idea

Create a folder in a document library

public void CreateFolder( string siteTitle, string libraryName, string folder)
{
  var list = GetDocumentLibrary(siteTitle, libraryName);
  if (list != null)
  {
    var folders = list.RootFolder.Folders;
    clientContext.Load(folders);
    clientContext.ExecuteQuery();
    var newFolder = folders.Add(folder);
    clientContext.ExecuteQuery();
  }
}
I'll skip the usage sample here, as I suppose it's pretty self-explanatory now.

Upload a file to a document library

public void UploadDocument( string siteTitle, string libraryName, string fileName )
{
  var web = GetWebByTitle(siteTitle);
  var fInfo = new FileInfo(fileName);
  var targetLocation = string.Format("{0}/{1}/{2}", web.ServerRelativeUrl, 
     libraryName, fInfo.Name);
  
  using (var fs = new FileStream(fileName, FileMode.Open))
  {
    File.SaveBinaryDirect(clientContext, targetLocation, fs, true);
  }
}
Usage sample: 
var result = sh.UploadDocument("MySite", "myDocumentLibrary",
                              @"c:\temp\sample.png");
This will upload the file c:\temp\sample.png as "sample.png" in the "myDocumentLibrary" library.

Download a file from a document library

What goes up must come down, eh? This one is a bit odd, as it strips the directory name of the target file and tries to find the file in Sharepoint with it, but it works, so what:

public void DownloadDocument(string siteTitle, string libraryName, 
                             string fileName)
{
  var web = GetWebByTitle(siteTitle);
  var fInfo = new FileInfo(fileName);

  var source = string.Format("{0}/{1}/{2}", web.ServerRelativeUrl, 
                                            libraryName, fInfo.Name);
  var spFileInfo = File.OpenBinaryDirect(clientContext, source);
  using (var fs = new FileStream(fileName, FileMode.OpenOrCreate))
  {
    spFileInfo.Stream.CopyTo(fs);
  }
}
Usage sample: 
sh.DownloadDocument("MySite", "myDocumentLibrary",
                     @"c:\temp\sample.png");
will search for the file "sample.png" in "myDocumentLibrary" and try to download that to c:\temp

Listing files or folders in a document library

And finally:

public List<File> ListFiles(string siteTitle, string libraryName)
{
  var list = GetDocumentLibrary(siteTitle, libraryName);
  var files = list.RootFolder.Files;
  clientContext.Load(files);
  clientContext.ExecuteQuery();
  return files.ToList();
}

public List<Folder> ListFolders(string siteTitle, string libraryName)
{
  var list = GetDocumentLibrary(siteTitle, libraryName);
  var folders = list.RootFolder.Folders;
  clientContext.Load(folders);
  clientContext.ExecuteQuery();
  return folders.ToList();
}

and if you don’t mind, I’ll skip the usage samples here as well.

25 February 2011

Using attached dependency properties to toggle an Application Bar Icon from viewmodel

Application Bar Icon buttons are a look-and-feel-wise very consistent and easy to understand way for every Windows Phone 7 application to give it’s users access to the most important functions. The drawback of this thing is that it’s not a real FrameworkElement, thus you cannot bind commands and other stuff to it, but as I described earlier, this has been solved by the BindableApplicationBar.

But even the BindableApplicationBar has its issues. The IconUri attribute of a BindableApplicationBarIconButton cannot be bound to – for it is no Dependecy Property. Now you can fix that, since Nicolas Humann includes the source code of his excellent solution. But I prefer to threat someone else’s code as third party component, and solved the problem using a very powerful way of extending of Silverlight/Windows Phone 7: attached dependency properties.

The problem I wanted to solve is this: I have changed my MapMania App in such a way that it now tracks your location continually if you press the “Satellite” button. But I want the user to be able to stop tracking as well, using the same button. So what used to be a simple activation button, is now a toggle button. When the user is tracking his own phone, I want the button image to change from the image of of a satellite to an image of a satellite with a big cross through it, indicating “if you press me again, I will stop tracking”. And I wanted this, of course, to be steered from the viewmodel.

This is how I solved it, with three attached dependency properties:

using System;
using System.Windows;
using Phone7.Fx.Preview;

namespace LocalJoost.Utilities
{
  /// <summary>
  /// Supports toggle of a BindableApplicationBarIconButton's icon
  /// </summary>
  public static class AppBarIconFlipper
  {
    #region IconUri
    public static readonly DependencyProperty IconUriProperty =
     DependencyProperty.RegisterAttached("IconUri",
     typeof(Uri),
     typeof(AppBarIconFlipper),
     new PropertyMetadata(IconUriPropertyChanged));

    // Called when Property is retrieved
    public static Uri GetIconUri(DependencyObject obj)
    {
      return obj.GetValue(IconUriProperty) as Uri;
    }

    // Called when Property is set
    public static void SetIconUri(
      DependencyObject obj,
      Uri value)
    {
      obj.SetValue(IconUriProperty, value);
    }

    // Called when property is changed
    private static void IconUriPropertyChanged(
     object sender,
     DependencyPropertyChangedEventArgs args)
    {
      var attachedObject = sender as BindableApplicationBarIconButton;
      if (attachedObject == null) return;
      attachedObject.IconUri = (bool)attachedObject.GetValue(ShowAlernateIconUriProperty)
                     ? (Uri)attachedObject.GetValue(AlernateIconUriProperty)
                     : (Uri)args.NewValue;
    }
    #endregion

    #region AlernateIconUri
    public static readonly DependencyProperty AlernateIconUriProperty =
     DependencyProperty.RegisterAttached("AlernateIconUri",
     typeof(Uri),
     typeof(AppBarIconFlipper),
     new PropertyMetadata(AlernateIconUriPropertyChanged));

    // Called when Property is retrieved
    public static Uri GetAlernateIconUri(DependencyObject obj)
    {
      return obj.GetValue(AlernateIconUriProperty) as Uri;
    }

    public static void SetAlernateIconUri(
      DependencyObject obj,
      Uri value)
    {
      obj.SetValue(AlernateIconUriProperty, value);
    }

    private static void AlernateIconUriPropertyChanged(
     object sender,
     DependencyPropertyChangedEventArgs args)
    {
      var attachedObject = sender as BindableApplicationBarIconButton;
      if (attachedObject == null) return;
      attachedObject.IconUri = (bool)attachedObject.GetValue(ShowAlernateIconUriProperty)
                     ? (Uri)args.NewValue
                     : (Uri)attachedObject.GetValue(IconUriProperty);
    }
    #endregion

    #region ShowAlernateIconUri
    public static readonly DependencyProperty ShowAlernateIconUriProperty =
     DependencyProperty.RegisterAttached("ShowAlernateIconUri",
     typeof(bool),
     typeof(AppBarIconFlipper),
     new PropertyMetadata(ShowAlernateIconUriPropertyChanged));

    public static bool GetShowAlernateIconUri(DependencyObject obj)
    {
      return (bool)obj.GetValue(ShowAlernateIconUriProperty);
    }

    public static void SetShowAlernateIconUri(
      DependencyObject obj,
      bool value)
    {
      obj.SetValue(ShowAlernateIconUriProperty, value);
    }

    private static void ShowAlernateIconUriPropertyChanged(
     object sender,
     DependencyPropertyChangedEventArgs args)
    {
      var attachedObject = sender as BindableApplicationBarIconButton;
      if (attachedObject == null) return;
      var value = (bool)args.NewValue;
      attachedObject.IconUri = value
                     ? (Uri)attachedObject.GetValue(AlernateIconUriProperty)
                     : (Uri)attachedObject.GetValue(IconUriProperty);
    }
    #endregion
  }
}
The only interesting code is in the “***Changed” methods, the rest is just the necessary plumbing. Anyway, in stead of setting the IconUri of the BindableApplicationBarIconButton directly, you use the attached dependency properties like this:
<Phone7Fx:BindableApplicationBarIconButton 
 Command="{Binding ShowLocation}" Text="Track" 
 LocalJoostUtils:AppBarIconFlipper.IconUri="/icons/gps.png"
 LocalJoostUtils:AppBarIconFlipper.AlernateIconUri="/icons/gps_stop.png"
 LocalJoostUtils:AppBarIconFlipper.ShowAlernateIconUri="{Binding IsTracking, Mode=TwoWay}"/>

and depending on the value of the Viewmodel property IsTracking the icon will flip from gps.png (false) to gps_stop (true) – or back.

Once again it shows Microsoft’s XAML-based platforms are as flexible as a rubber band, and wherever are holes in binding, you can almost always plug them using attached dependency properties – the super glue of MVVM, IMHO.

20 February 2011

Marketplace monetization idea: gift items

I seem to be going off-topic a lot these days but I hope you will forgive me for that.

My wife has been eying my new HTC 7 Pro quite a lot, especially since I showed her some of her favorite XBox puzzle games on it. I see where this is going to end – sooner or later (and from the looks of it rather sooner than later) her old Nokia phone will be replaced by something that runs Windows Phone 7 as well. If only because I would like to retain control over my own phone, thank you very much ;-)

And then it started to dawn on me: it would be great to buy gifts for someone else in the Marketplace.

Suppose I am browsing the Marketplace and find a game or piece of music that I know my wife (or anyone else for what matters) would like very much. I would like to be able to buy the item as a gift, i.e. I pay with my live id, but instead of installing the item on my own device I would get the option to enter someone else’s live id, and a personal note. My wife for instance would then get an e-mail on her live account (“Hi luv look what I got you”) with a Zune link, she clicks on it, the Marketplace recognizes it’s already paid for, and she gets her beloved game. Or a romantic song, or whatever.

I have no idea if this is a possible or even a viable scenario, but the thought crossed my mind yesterday evening (when my wife was watching me play a puzzle game on my phone and all but ripped it from my hands) and I just wanted to share it.

What do you think? Sensible idea, or simply not viable (too complicated for the expected ROI).?

19 February 2011

Converter to convert a single item to a list to enable Bing Maps binding

Some things are so simple that I wonder if I am missing something. I tried to bind a single GeoPosition to Bing Maps’ MapItemsControl ItemsSource on Windows Phone 7 and it did not work. Apparently Bing Maps want a list. So I wrote the following converter:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows.Data;

namespace LocalJoost.Convertors
{
  public class ToListConverter : IValueConverter
  {
    public object Convert(object value, Type targetType, object parameter, 
                          CultureInfo culture)
    {
      var l = new List<object> ();
      if (value != null) l.Add(value);
      return l;
    }

    public object ConvertBack(object value, Type targetType, object parameter, 
                              CultureInfo culture)
    {
      return null;
    }
  }
}
A masterpiece of complicated coding, right :-/ ? Anyway, in stead of
<Microsoft_Phone_Controls_Maps:MapItemsControl 
  ItemsSource="{Binding GpsLocation}">
I used
<Microsoft_Phone_Controls_Maps:MapItemsControl 
  ItemsSource="{Binding GpsLocation, Converter={StaticResource ToListConverter}}">

and Lo and Behold – now I did get my single icon on the map.

I have no idea if this is a quirk of the Bing Maps control or that ItemsSource attributes in general only accept lists – but either way, this works.

Extended Windows Phone 7 page for handling rotation, focused element updates and back key press

In this article I present ‘my’ base class for Windows Phone 7 Application Pages – essentially nothing more than a collection of utilities to handle common scenarios. Most of the code I did not write myself, but I think it’s a nice aggregation that handles the following three common problems:

  1. When someone is typing in a TextBox and receives a phone call, the model bound to that TextBox does not receive an NotifyPropertyChanged and thus is not updated – and if you tombstone the ViewModel, like I do, the last keystrokes are lost when the application is activated again.
  2. When a page changes from portrait to landscape, you want that transition to be animated
  3. When the users presses the back key, the ViewModel needs to be able to interact with that

I have put this class in “LocalJoost.Controls”. First, class definition and the part that handles rotation:

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Navigation;
using LocalJoost.BaseModels;
using Microsoft.Phone.Controls;

namespace LocalJoost.Controls
{
  public class ExtendedPhonePage : PhoneApplicationPage
  {
    public ExtendedPhonePage()
    {
      Loaded += ExtendedPhonePageLoaded;
    }

    void ExtendedPhonePageLoaded(object sender, RoutedEventArgs e)
    {
      _lastOrientation = Orientation;
    }
    
    PageOrientation _lastOrientation;
    protected override void OnOrientationChanged(OrientationChangedEventArgs e)
    {
      var newOrientation = e.Orientation;
      var transitionElement = new RotateTransition();

      switch (newOrientation)
      {
        case PageOrientation.Landscape:
        case PageOrientation.LandscapeRight:
          // Come here from PortraitUp (i.e. clockwise) or LandscapeLeft?
          if (_lastOrientation == PageOrientation.PortraitUp)
            transitionElement.Mode = RotateTransitionMode.In90Counterclockwise;
          else
            transitionElement.Mode = RotateTransitionMode.In180Clockwise;
          break;
        case PageOrientation.LandscapeLeft:
          // Come here from LandscapeRight or PortraitUp?
          if (_lastOrientation == PageOrientation.LandscapeRight)
            transitionElement.Mode = RotateTransitionMode.In180Counterclockwise;
          else
            transitionElement.Mode = RotateTransitionMode.In90Clockwise;
          break;
        case PageOrientation.Portrait:
        case PageOrientation.PortraitUp:
          // Come here from LandscapeLeft or LandscapeRight?
          if (_lastOrientation == PageOrientation.LandscapeLeft)
            transitionElement.Mode = RotateTransitionMode.In90Counterclockwise;
          else
            transitionElement.Mode = RotateTransitionMode.In90Clockwise;
          break;
        default:
          break;
      }

      // Execute the transition
       var phoneApplicationPage = 
           (((PhoneApplicationFrame)Application.Current.RootVisual)).Content
              as PhoneApplicationPage;
      transition.Completed += (sender, args) => transition.Stop();
      transition.Begin();

      _lastOrientation = newOrientation;
      base.OnOrientationChanged(e);
    }
  }
}
This is basically a slightly (very slightly) modified version of what is presented by Andy Wigley, only stuck in a base class.

The second part, which I nicked from The Code Project simply overrides OnNavigatedFrom – an event that is called when an App tombstones, unlike TextBox.LostFocus – and then forces the bound element to be updated. As a bonus, it tries to reset the focused element as well.

private const string FocusedElement = "FOCUSED_ELEMENT";

protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
  if (State.ContainsKey(FocusedElement))
  {
    State.Remove(FocusedElement);
  }

  var focusedElement = FocusManager.GetFocusedElement() as Control;
  if (focusedElement == null) return;
  if (!String.IsNullOrEmpty(focusedElement.Name))
  {
    State.Add(FocusedElement, focusedElement.Name);
  }

  BindingExpression be = null;

  //TODO - Developers, add additional controls here like a 
  //date picker, combobox, etc.
  if (focusedElement is TextBox)
  {
    be = focusedElement.GetBindingExpression(TextBox.TextProperty);
  }
  if (be != null)
  {
    be.UpdateSource();
  }
  base.OnNavigatingFrom(e);
}

And the third part, which I actually created myself, handles the OnBackKeyPress scenario. Sometimes you want to cancel navigation out of the page, for instance because you have created a popup. If the user then presses the back key you want to close the popup and cancel the navigation (this is actually part of the Certification Requirements), and preferably do so my letting the view model handle that. Unfortunately the only place to intercept the OnBackKeyPress event is by overriding in a method in the Page. So I simply decided to handle this by overriding the OnBackKeyPress like this:

protected override void OnBackKeyPress( CancelEventArgs e)
{
  var dc = DataContext as IBackKeyPressHandler;
  if (dc != null) dc.OnBackKeyPress(e);
}
All ViewModels that should be able to handle dc.OnBackKeyPress should then implement the very complicated interface IBackKeyPressHandler:
using System.ComponentModel;

namespace LocalJoost.BaseModels
{
  public interface IBackKeyPressHandler
  {
    void OnBackKeyPress(CancelEventArgs e);
  }
}
and you are done - the model now gets notified of the OnBackKeyPress and can handle this – or not. Of course you can do this with Messaging and whatnot – this is easy, clean and simple to understand. With on prerequisite of course: the ViewModel should be bound directly to the Page.

In stead of “phone:PhoneApplicationPage” on the top and bottom of my application pages I now simply put “LocalJoost:ExtendedPhonePage” and I am done and get the three functions described above for free. Well, that is, you need of course to define the namespace LocalJoost as something like
“xmlns:LocalJoost="clr-namespace:LocalJoost.Controls;assembly=LocalJoost" – or leave it to ReSharper or some tool like that to do that for you.