Windows Phone7 Live SDK Preview Sample

October 26, 2011 by Injac
Filed under: Windows Phone 7 

Some days ago, I found an interessting sample about how to manage files with the new Live SDK Developer Preview. I have read many postings on MSDN and I found out, that WP7 developers are really keen on a example, on how to upload and download files from SkyDrive, using WP7. I used the SkyPad sample from MSDN and ported parts of it to WP7. 

The main concept and most of the source where taken from the SkyPad sample for Windows Developer Preview and ported tonight to WP7.

Bevore you can use the example, you have to register for an ClientID at the Windows Live Application Management Site. You need this ClientID, to be able to access the Windows Live Services from your applications, not only for mobile devices. 

Please download also the Windows Live SDK Developer Preview from Microsoft Connect

Register For a ClientID 

Visit the Windows Live Application Mangment Site 

Please visit the Windows Live Application Managment Site (be sure to own a Live-Account bevore doing this), and log in: 

Windows Live Application Management Login

Login to get your ClientID

Create An Application 

After successfully logging in – please click on the right side “Create Application”: 

Create a application entry on Windows Live

Create an entry for your app

 Set The Name For Your Application 

Set the name and choose the language for your application: 

Image on how to set the application name in Windows Live

Set the name of your application

Go To The Application Settings Page 

After setting the name, you need to adjust additional API settings for your application. Please click on Application Settings Page. Please copy also the Client ID, you need it later: 

The Application settings to change

Client ID and application settings

Choose The API Settings 

On the current screen, click API Settings on the left: 

Showing the settings screen for the application

Choose the API settings

 Set The Mobile Client App Flag 

To be able to use the WP7 app you need to select yes in the Mobile client app section: 

Select the mobile API settings

Select yes here

After this torture copy your Client ID (if you have not done it before) and open the project in Visual Studio 2010 or Expression Blend. 

Set The Client ID In The Source 

Open the file Main.xaml and insert the Client ID: 

Insert Client ID 

Now compile the source and run the application. 

Here are some screenshots and the main source code snippet: 

The Skypad App for Windows Phone 

 

 

 

 

And here the most important part of the source code, as well as the dowload of the whole project.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Windows.Navigation;
using System.Collections.ObjectModel;
using System.IO;
using System.Text;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
using Microsoft.Live;
using Microsoft.Live.Controls;
using SkyPadWindowsPhone;

namespace SkyPadWindowsPhone
{
    using System.IO.IsolatedStorage;

    public partial class MainPage : PhoneApplicationPage
    {

        /// <summary>
        /// The client to connect to windows live.
        /// </summary>
        private LiveConnectClient client = null;

        /// <summary>
        /// Stack holding the folderIds
        /// </summary>
        private Stack<String> folderIds = new Stack<string>();

        /// <summary>
        /// Appsettings
        /// </summary>
        private static readonly IsolatedStorageSettings appSettings =
                    IsolatedStorageSettings.ApplicationSettings;

        /// <summary>
        /// The folder id, to save the file to.
        /// </summary>
        private DirectoryItem _FolderToSaveTo = null;

        /// <summary>
        /// List of directories avialable.
        /// </summary>
        public ObservableCollection<DirectoryItem> _Directories;

        /// <summary>
        /// The document id of the last saved file.
        /// </summary>
        private string _DocId = string.Empty;

        /// <summary>
        /// Name of the last saved file
        /// </summary>
        private string _LastFileName = string.Empty;

        /// <summary>
        /// Has the file to be saved?
        /// </summary>
        private bool needToSave = false;

        // Constructor
        public MainPage()
        {
            InitializeComponent();
            this.listPicker1.Visibility = Visibility.Collapsed;
            this.txtbFileName.Visibility = Visibility.Collapsed;
            this.btnOpenFile.IsEnabled = false;
            this.btnSaveFile.IsEnabled = false;
            this.txtbFileText.Visibility = Visibility.Collapsed;

        }

        /// <summary>
        /// Handles the Click event of the button1 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            //Save Button
            if (this._FolderToSaveTo != null && this.txtbFileName.Text != string.Empty && this.txtbFileText.Text !=string.Empty)
            {
                this.SaveNote(_FolderToSaveTo.DirectoryId);
            }
            else
            {
                MessageBox.Show("Please check, filename or filext, or folder you want to save to.");
            }
        }

        /// <summary>
        /// Called when [session changed].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="args">The <see cref="Microsoft.Live.Controls.LiveConnectSessionChangedEventArgs"/> instance containing the event data.</param>
        private void OnSessionChanged(Object sender, LiveConnectSessionChangedEventArgs args)
        {

            if (args != null && args.Session != null && args.Session.Status == LiveConnectSessionStatus.Connected)
            {
                this.client = new LiveConnectClient(args.Session);

                    this.SignedInUser();

            }
            else
            {
                this.SignedOutUser();
            }
        }

        /// <summary>
        /// User state is signed in.
        /// </summary>
        private void SignedOutUser()
        {
            // User not login, cleanup user data

            txtbFileText.Text = "";

            txtbFileText.Text = "";
            tblStatus.Text = "";
            imgUserPicture.Source = null;
            tblUserName.Text = "";
            folderIds.Clear();
            needToSave = false;
            txtbFileName.Text = "";
            this.listPicker1.Visibility = Visibility.Collapsed;
            this.txtbFileName.Visibility = Visibility.Collapsed;
            this.btnOpenFile.IsEnabled = false;
            this.btnSaveFile.IsEnabled = false;
            this.txtbFileText.Visibility = Visibility.Collapsed;

        }

        /// <summary>
        /// Called when a page is no longer the active page in a frame.
        /// </summary>
        /// <param name="e">An object that contains the event data.</param>
        protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
        {
            base.OnNavigatedFrom(e);

        }

        /// <summary>
        /// Called when a page becomes the active page in a frame.
        /// </summary>
        /// <param name="e">An object that contains the event data.</param>
        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

        }

        /// <summary>
        /// User state is signed out.
        /// </summary>
        private void SignedInUser()
        {

            this.GetUserPicture();
        }

        /// <summary>
        /// Gets the user picture.
        /// </summary>
        private void GetUserPicture()
        {
            var memoryStream = new MemoryStream();
            client.DownloadCompleted += new EventHandler<LiveOperationCompletedEventArgs>(this.GetUserPictureCallback);
            client.DownloadAsync("/me/picture?return_ssl_resources=true", memoryStream, memoryStream);
        }

        /// <summary>
        /// Gets the user picture callback.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="Microsoft.Live.LiveOperationCompletedEventArgs"/> instance containing the event data.</param>
        private void GetUserPictureCallback(object sender, LiveOperationCompletedEventArgs e)
        {
            client.DownloadCompleted -= this.GetUserPictureCallback;

            if (e.Error == null)
            {

                MemoryStream imageStream = e.UserState as MemoryStream;
                BitmapImage b = new BitmapImage();
                b.SetSource(imageStream);

                if (imageStream != null)
                {
                    this.imgUserPicture.Source = b;
                    this.imgUserPicture.Visibility = Visibility.Visible;
                    this.tblUserName.Visibility = Visibility.Visible;

                }
                else
                {
                    MessageBox.Show("Unable to find your picture.", "Windows Live Message", MessageBoxButton.OK);
                }
            }
            else
            {
                MessageBox.Show(e.Error.Message, "Windows Live Error", MessageBoxButton.OK);
            } 

            this.GetUserName();
        }

        /// <summary>
        /// Gets the name of the user.
        /// </summary>
        private void GetUserName()
        {
            client.GetCompleted += new EventHandler<LiveOperationCompletedEventArgs>(this.GetUserNameCallback);
            client.GetAsync("/me");
        }

        /// <summary>
        /// Gets the user name callback.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="Microsoft.Live.LiveOperationCompletedEventArgs"/> instance containing the event data.</param>
        private void GetUserNameCallback(object sender, LiveOperationCompletedEventArgs e)
        {
            client.GetCompleted -= this.GetUserNameCallback;

            if (e.Error == null)
            {
                var user = e.Result;
                tblUserName.Text = user["name"].ToString();
            }
            else
            {
                tblStatus.Text = e.Error.Message;
            }

            GetFiles("/me/skydrive");

        }

        /// <summary>
        /// Saves the note.
        /// </summary>
        /// <param name="path">The path.</param>
        private void SaveNote(string path)
        {
            if (client.Session == null || client.Session.Status != LiveConnectSessionStatus.Connected)
            {
                tblStatus.Text = "You need to Sign In";
            }
            else
            {
                if (txtbFileName.Text.Length == 0)
                {
                    tblStatus.Text = "Please provide a Filename";
                }
                else
                {

                    tblStatus.Text = "Saving " + txtbFileName.Text;

                    System.Text.UTF8Encoding enc = new UTF8Encoding();
                    var stream = new MemoryStream(enc.GetBytes(txtbFileText.Text));

                    String filename = txtbFileName.Text + ".txt";

                    //Disable the textbox
                    this.txtbFileText.Visibility = Visibility.Collapsed;
                    this.txtbFileName.Visibility = Visibility.Collapsed;
                    this.listPicker1.Visibility = Visibility.Collapsed;

                    client.UploadCompleted += new EventHandler<LiveOperationCompletedEventArgs>(this.SaveNoteCallback);
                    client.UploadAsync(path, filename, true, stream, stream);
                }
            }
        }

        /// <summary>
        /// Saves the note callback.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="Microsoft.Live.LiveOperationCompletedEventArgs"/> instance containing the event data.</param>
        void SaveNoteCallback(object sender, LiveOperationCompletedEventArgs e)
        {
            client.UploadCompleted -= this.SaveNoteCallback;

            if (e.Error == null)
            {
                //Get the file-id of the file, theres only one
                KeyValuePair<string,object> data =  e.Result.FirstOrDefault();
                this._DocId = data.Value.ToString();
                Dispatcher.BeginInvoke(() => { this._LastFileName = txtbFileName.Text + ".txt"; });

                //Don't F** with tha WP7 Dispatcha!
                if (tblStatus.CheckAccess())
                {
                    tblStatus.Text = "File saved";

                    btnSaveFile.IsEnabled = false;
                    btnOpenFile.IsEnabled = true;
                    txtbFileName.Visibility = Visibility.Collapsed;
                    txtbFileText.Visibility = Visibility.Collapsed;
                    ;

                    needToSave = false;

                }
                else
                {

                    Dispatcher.BeginInvoke(() => { tblStatus.Text = "File Saved"; });
                    Dispatcher.BeginInvoke(() => { btnSaveFile.IsEnabled = false; });
                    Dispatcher.BeginInvoke(() => { btnOpenFile.IsEnabled = true; });
                    Dispatcher.BeginInvoke(() => { this.txtbFileText.Visibility = Visibility.Collapsed; });
                    Dispatcher.BeginInvoke(() => { this.listPicker1.Visibility = Visibility.Collapsed;});
                    Dispatcher.BeginInvoke(() => { this.txtbFileText.Text = ""; });
                    Dispatcher.BeginInvoke(() => { this.txtbFileName.Visibility = Visibility.Collapsed;});
                    needToSave = false;
                }

            }
            else
            {
                tblStatus.Text = e.Error.Message;
            }
        }

        /// <summary>
        /// Saves the BTN click.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void SaveBtnClick(object sender, RoutedEventArgs e)
        {
            if(this._FolderToSaveTo !=null)
            this.SaveNote(_FolderToSaveTo.Directory);
        }

        /// <summary>
        /// Gets the complete sky drive directory root.
        /// </summary>
        private void GetCompleteSkyDriveDirectoryRoot()
        {
            this.GetFiles("/me/skydrive");
        }

        /// <summary>
        /// Gets the files. Here Directories only.
        /// </summary>
        /// <param name="folder">The folder.</param>
        private void GetFiles(string folder)
        {
            // check if we are moving to a child folder or just re-enumerating the current folder
            if (folderIds.Count == 0 || folderIds.Peek() != folder)
            {
                folderIds.Push(folder);
            }

            client.GetCompleted += new EventHandler<LiveOperationCompletedEventArgs>(this.GetDirectoriesCallBack);
            client.GetAsync(folder + "/files");
        }

        /// <summary>
        /// Gets the directories call back.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="Microsoft.Live.LiveOperationCompletedEventArgs"/> instance containing the event data.</param>
        private void GetDirectoriesCallBack(object sender, LiveOperationCompletedEventArgs e)
        {
            client.GetCompleted -= this.GetDirectoriesCallBack;

            if (e.Error == null)
            {
                _Directories = new ObservableCollection<DirectoryItem>();

                List<object> data = (List<object>)e.Result["data"];

                // Generate parent folder list entry
                if (folderIds.Peek() != "/me/skydrive")
                {

                    _Directories.Add( new DirectoryItem("..",null));

                }

                foreach (IDictionary<string, object> datum in data)
                {
                    String name = datum["name"].ToString();
                    String type = datum["type"].ToString();

                    if (type == "folder")
                    {
                        _Directories.Add(new DirectoryItem(name,datum["id"].ToString()));

                    }
                    else if (name.EndsWith(".txt"))
                    {
                        //name = name.Replace(".txt", null);
                        //createNoteListEntry(name, datum["id"].ToString(), "note");
                    }
                }
                tblStatus.Text = "Found " + _Directories.Count() + " folders";
            }
            else
            {
                tblStatus.Text = e.Error.Message;
            }

            this.txtbFileName.Visibility = Visibility.Visible;
            this.txtbFileName.IsEnabled = true;
            this.txtbFileText.Visibility = Visibility.Visible;
            this.txtbFileText.IsEnabled = true;
            this.btnSaveFile.IsEnabled = true;
            this.listPicker1.Visibility = Visibility.Visible;
            this.listPicker1.IsEnabled = true;

            this.listPicker1.DataContext = _Directories;
        }

        /// <summary>
        /// Directories the list selection changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Controls.SelectionChangedEventArgs"/> instance containing the event data.</param>
        private void DirectoryListSelectionChanged(object sender, SelectionChangedEventArgs e)
        {

            this._FolderToSaveTo = (DirectoryItem)(((ListBox)sender).SelectedItem);

        }

        /// <summary>
        /// Downloads the note.
        /// </summary>
        /// <param name="noteId">The note id.</param>
        private void DownloadNote(String noteId)
        {

            if (client == null || client.Session == null || client.Session.Status != LiveConnectSessionStatus.Connected)
            {
                tblStatus.Text = "You need to Sign In";
            }
            else
            {

                var stream = new MemoryStream();

                client.DownloadCompleted += new EventHandler<LiveOperationCompletedEventArgs>(this.DownloadNoteCallback);
                client.DownloadAsync(noteId + "/content?return_ssl_resources=true", stream, stream);
            }
        }

        /// <summary>
        /// Downloads the note callback.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="Microsoft.Live.LiveOperationCompletedEventArgs"/> instance containing the event data.</param>
        private void DownloadNoteCallback(object sender, LiveOperationCompletedEventArgs e)
        {
            client.DownloadCompleted -= this.DownloadNoteCallback;

            if (e.Error == null)
            {
                // Get the stream with the downloaded file
                var memoryStream = e.UserState as MemoryStream;

                // Cursor is at the end of the stream so we need to rewind
                memoryStream.Seek(0, SeekOrigin.Begin);

                // Read stream into a byte array
                byte[] bytes = new byte[1000];
                int numbytes = memoryStream.Read(bytes, 0, (int)memoryStream.Length);

                // Prevent loading textbox from firing a text change event
                txtbFileText.TextChanged -= this.NotesEditorTextChanged;

                // Load text into the TextBox decoding it as UTF8
                System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding();
                txtbFileText.Text = enc.GetString(bytes, 0, numbytes);

                // Enable editing note content
                txtbFileText.IsReadOnly = false;

                // Set Save status to false
                needToSave = false;

                btnSaveFile.IsEnabled = false;

                // Enable detecting changes
                txtbFileText.TextChanged += this.NotesEditorTextChanged;

                tblStatus.Text = "Downloaded note (" + numbytes + " bytes)";
            }
            else
            {

                    tblStatus.Text = e.Error.Message;

            }

            this.txtbFileName.Visibility = Visibility.Visible;
            this.txtbFileText.Visibility = Visibility.Visible;
            this.listPicker1.Visibility = Visibility.Visible;
            this.btnSaveFile.IsEnabled = true;
            this.btnOpenFile.IsEnabled = false;
        }

        /// <summary>
        /// Noteses the editor text changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Controls.TextChangedEventArgs"/> instance containing the event data.</param>
        private void NotesEditorTextChanged(object sender, TextChangedEventArgs e)
        {
            needToSave = true;

        }

        /// <summary>
        /// Datasave for each directory entry.
        /// </summary>
        public class DirectoryItem
        {
            private string _directory;

            private string _directoryId;

            public DirectoryItem(string path,string id)
            {
                this._directory = path;
                this._directoryId = id;
            }

            public string Directory
            {
                get
                {
                    return _directory;
                }
                set
                {
                    _directory = value;
                }
            }

            public string DirectoryId
            {
                get
                {
                    return _directoryId;
                }
                set
                {
                    _directoryId = value;
                }
            }
        }

        /// <summary>
        /// BTNs the open file click.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void BtnOpenFileClick(object sender, RoutedEventArgs e)
        {
            if(this._DocId != null)
            {
                this.txtbFileName.Text = this._LastFileName;
                this.DownloadNote(this._DocId);
            }

        }

    }
}

Here the download:

Comments

Tell me what you're thinking...
and oh, if you want a pic to show with your comment, go get a gravatar!