Wednesday, December 3, 2014

Office 365 Authentication/Office 365 Integration in Windows store apps

Source code can be found here.
Table of Contents

Overview

The Office 365 Starter Project sample uses the Office 365 API Tools client libraries to illustrate basic operations against the Files, Calendar and Contacts service endpoints in Office 365. The sample also demonstrates how to authenticate against multiple Office 365 services in a single app experience, and retrieve user information from the Users and Groups service. We'll be adding examples of how to use more APIs such as Email when we update this project, so make sure to check back. Below are the operations that you can perform with this sample:
Calendar
  • Get calendar events
  • Create events
  • Update events
  • Delete events
Contacts
  • Get contacts
  • Create contacts
  • Update contacts
  • Delete contacts
  • Change contact photo
My Files
  • Get files and folders
  • Create text files
  • Delete files or folders
  • Read text file contents (OneDrive)
  • Update text file contents
  • Download files
  • Upload files
Users and Groups
  • Get display name
  • Get job title
  • Get profile picture
  • Get user ID
  • Check signed in/out state

Prerequisites and Configuration

This sample requires the following:

Configure the sample

Follow these steps to configure the sample.
  1. Open the O365-APIs-Start-Windows.sln file using Visual Studio 2013.
  2. Register and configure the app to consume Office 365 services (detailed below).

Register app to consume Office 365 APIs

You can do this via the Office 365 API Tools for Visual Studio (which automates the registration process). Be sure to download and install the Office 365 API tools from the Visual Studio Gallery.
  1. In the Solution Explorer window, choose Office365Starter project -> Add -> Connected Service.
  2. A Services Manager dialog box will appear. Choose Office 365 and Register your app.
  3. On the sign-in dialog box, enter the username and password for your Office 365 tenant. We recommend that you use your Office 365 Developer Site. Often, this user name will follow the pattern @.onmicrosoft.com. If you do not have a developer site, you can get a free Developer Site as part of your MSDN Benefits or sign up for a free trial. Be aware that the user must be an Tenant Admin user—but for tenants created as part of an Office 365 Developer Site, this is likely to be the case already. Also developer accounts are usually limited to one sign-in.
  4. After you're signed in, you will see a list of all the services. Initially, no permissions will be selected, as the app is not registered to consume any services yet.
  5. To register for the services used in this sample, choose the following permissions:
    • (Calendar) – Have full access to users’ calendar
    • (Contacts) - Have full access to users' contacts
    • (My Files) – Edit or delete users’ files
    • (Users and Groups) – Enable sign-on and read users' profiles
    • (Users and Groups) – Access your organization's directory
  6. After clicking OK in the Services Manager dialog box, assemblies for connecting to Office 365 REST APIs will be added to your project.
Note: If you see any errors while installing packages during step 6, for example, Unable to find "Microsoft.Azure.ActiveDirectory.GraphClient", make sure the local path where you placed the solution is not too long/deep. Moving the solution closer to the root of your drive resolves this issue. We'll also work on shortening the folder names in a future update.

Build

After you've loaded the solution in Visual Studio, press F5 to build and debug. Run the solution and sign in with your organizational account to Office 365.

Project Files of Interest

Helper Classes
  • CalendarOperations.cs
  • FileOperations.cs
  • UserOperations.cs
  • AuthenticationHelper.cs
  • ContactOperations.cs
View Models
  • CalendarViewModel.cs
  • EventViewModel.cs
  • UserViewModel.cs
  • ContactsViewModel.cs
  • FilesViewModel.cs
  • FileSystemItemViewModel.cs
  • ContactItemViewModel.cs

Known issues

  • None at the moment, but do let us know if you find any. We're listening.

Troubleshooting

  • You receive an "insufficient privileges" exception when you connect to Office 365 as a normal user, i.e., someone that does not have elevated privileges and is not a global administrator. Make sure you have set the Access your organization's directory permission when you add the connected services.
  • You receive errors during package installation, for example, Unable to find "Microsoft.Azure.ActiveDirectory.GraphClient". Make sure the local path where you placed the solution is not too long/deep. Moving the solution closer to the root of your drive resolves this issue. We'll also work on shortening the folder names in a future update.
  • You may run into an authentication error after deploying and running if apps do not have the ability to access account information in the Windows Privacy Settings menu. Set Let my apps access my name, picture, and other account info to On. This setting can be reset by a Windows Update.

Tuesday, September 16, 2014

Drag and Drop, Re-Orderting of items in GridView using VariablesizeWrapGrid in Windows store apps

Allowing drag and drop when you use VariableSizeWrapGrid- By default drag and drop and reordering of items are available when you not use variablesizewrapGrid in GridView. If you tend to use variableSizeWrapGrid and still want to use Drag/Drop and Re-Ordering you might use the below extensionClass

    ///



    /// The class implements drag&drop for cases which are not supported by the control:
    /// - for ItemsPanels other than StackPanel, WrapGrid, VirtualizingStackPanel;
    /// - for cases when grouping is set.
    /// It also allows adding new groups to the underlying datasource if end-user drags some item to the left-most or the rigt-most sides of the control.
    ///
    ///
    /// To allow new group creation by the end-user, set property to true.
    /// To add new group, handle event. The
    /// property value defines whether the new group creation has been requested by the end-user actions.
    /// If this property is true, create the new data group and insert it into the groups collection at the positions, specified by the
    /// property value. Then the will insert dragged item
    /// into the newly added group.
    /// Note: you should create new group from your code, as the control knows nothing about your data structure.
    ///
    [TemplatePart(Name = DraggableGridView.NewGroupPlaceHolderFirstName, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = DraggableGridView.NewGroupPlaceHolderLastName, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = DraggableGridView.ScrollViewerName, Type = typeof(ScrollViewer))]
    public partial class DraggableGridView : GridView
    {
        //-------------------------------------------------------------

        #region ** Template Parts

        private const string NewGroupPlaceHolderFirstName = "NewGroupPlaceHolderFirst";
        private FrameworkElement _newGroupPlaceHolderFirst;

        private const string NewGroupPlaceHolderLastName = "NewGroupPlaceHolderLast";
        private FrameworkElement _newGroupPlaceHolderLast;

        private const string ScrollViewerName = "ScrollViewer";
        private ScrollViewer _scrollViewer;

        #endregion ** Template Parts

        //----------------------------------------------------------------------

        #region ** dependency properties

        ///



        /// Gets or sets the value determining whether new group should be created at dragging the item to the empty space.
        /// This is a dependency property. The default value is false.
        ///
        public bool AllowNewGroup
        {
            get { return (bool)GetValue(AllowNewGroupProperty); }
            set { SetValue(AllowNewGroupProperty, value); }
        }

        ///



        /// Identifies the dependency property.
        ///
        public static readonly DependencyProperty AllowNewGroupProperty =
            DependencyProperty.Register("AllowNewGroup", typeof(bool), typeof(GridViewCustomControl), new PropertyMetadata(false));

        #endregion ** dependency properties

        //----------------------------------------------------------------------

        #region ** events

        ///



        /// Occurs before performing drop operation,
        ///
        public event EventHandler BeforeDrop;

        ///



        /// Rizes the event.
        ///
        /// Event data for the event.
        protected virtual void OnBeforeDrop(BeforeDropItemsEventArgs e)
        {
            if (null != BeforeDrop)
            {
                BeforeDrop(this, e);
            }
        }

        #endregion ** events

        //----------------------------------------------------------------------

        #region ** fields

        protected int _lastIndex = 0;  // index of the currently dragged item
        private int _currentOverIndex = -1; // index which should be used if we drop immediately
        private int _topReorderHintIndex = -1; // index of element which has been moved up (need it to restore item visual state later)
        private int _bottomReorderHintIndex = -1; // index of element which has been moved down (need it to restore item visual state later)

        private int _lastGroup = -1;  // index of the currently dragged item group
        private int _currentOverGroup = -1; // index of the group under the pointer

        #endregion ** fields

        //----------------------------------------------------------------------

        #region ** ctor & initialization

        ///



        /// Initializes a new instance of the control.
        ///
        public DraggableGridView()
        {

            CanReorderItems = true;
            AllowDrop = true;
            CanDragItems = true;
            this.DragItemsStarting += GridViewEx_DragItemsStarting;
        }



        protected override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            _newGroupPlaceHolderFirst = GetTemplateChild(NewGroupPlaceHolderFirstName) as FrameworkElement;
            _newGroupPlaceHolderLast = GetTemplateChild(NewGroupPlaceHolderLastName) as FrameworkElement;
            _scrollViewer = GetTemplateChild(ScrollViewerName) as ScrollViewer;
        }

        #endregion ** ctor & initialization

        //----------------------------------------------------------------------

        #region ** protected

        ///



        /// Stores dragged items into DragEventArgs.Data.Properties["Items"] value.
        /// Override this method to set custom drag data if you need to.
        ///
        ///
        protected virtual void OnDragStarting(DragItemsStartingEventArgs e)
        {
            e.Data.RequestedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move;
            e.Data.Properties.Add("Items", e.Items);

            // set some custom drag data as below
            // e.Data.SetText(_lastIndex.ToString());
        }

        ///



        /// Handles drag&drop for cases when it is not supported by the Windows.UI.Xaml.Controls.GridView control (for example, for grouped GridView).
        ///
        ///
        protected override async void OnDrop(DragEventArgs e)
        {
            //IList items = (IList)e.Data.GetView().Properties["Items"];
            //object item = (items != null && items.Count > 0) ? items[0] : Items[_lastIndex];
            //if (items != null)
            //{
            //    // read custom drag data as below if they have been set in OnDragStarting
            //    // string text = await e.Data.GetView().GetTextAsync();

            //    int newIndex = GetDragOverIndex(e);
            //    var oldIndex = this.Items.IndexOf(item);
            //    if (newIndex != oldIndex)
            //    {
            //        //var oldItem = this.Items[newIndex];
            //        //this.Items.RemoveAt(newIndex);
            //        //this.Items.RemoveAt(oldIndex-1);
            //        //this.Items.Insert(newIndex, item);
            //        //this.Items.Insert(oldIndex, oldItem);
            //        this.Items.Clear();
            //        this.Items.Add(item);
            //    }
            //}
            // base.OnDrop(e);
        }

        ///



        /// Shows reoder hints while custom dragging.
        ///
        ///
        protected override void OnDragOver(DragEventArgs e)
        {
            /* set ReorderHintStates for underlying items
                * possible ReorderHintStates:
                    - "NoReorderHint"
                    - "BottomReorderHint"
                    - "TopReorderHint"
                    - "RightReorderHint"
                    - "LeftReorderHint"
                */
            IList items = (IList)e.Data.GetView().Properties["Items"];
            //object item = (items != null && items.Count > 0) ? items[0] : Items[_lastIndex];
            if (items != null)/*This code make sure if items are dragging over in sections while dropping we don't need to show reorder hint here*/
            {
                int newIndex = GetDragOverIndex(e);
                if (newIndex >= 0 && _currentOverIndex != newIndex)
                {
                    _currentOverIndex = newIndex;
                    if (_topReorderHintIndex != -1)
                    {
                        GoItemToState(_topReorderHintIndex, "NoReorderHint", true);
                        _topReorderHintIndex = -1;
                    }
                    if (_bottomReorderHintIndex != -1)
                    {
                        GoItemToState(_bottomReorderHintIndex, "NoReorderHint", true);
                        _bottomReorderHintIndex = -1;
                    }
                    if (newIndex > 0)
                    {
                        _topReorderHintIndex = newIndex - 1;
                    }
                    if (newIndex < Items.Count)
                    {
                        _bottomReorderHintIndex = newIndex;
                    }
                    if (IsGrouping && _currentOverGroup >= 0)
                    {
                        int topHintGroup = GetGroupForIndex(_topReorderHintIndex);
                        if (topHintGroup != _currentOverGroup)
                        {
                            _topReorderHintIndex = -1;
                        }
                        int bottomHintGroup = GetGroupForIndex(_bottomReorderHintIndex);
                        if (bottomHintGroup != _currentOverGroup)
                        {
                            _bottomReorderHintIndex = -1;
                        }
                    }
                    if (_topReorderHintIndex >= 0)
                    {
                        GoItemToState(_topReorderHintIndex, "TopReorderHint", true);
                    }
                    if (_bottomReorderHintIndex >= 0)
                    {
                        GoItemToState(_bottomReorderHintIndex, "BottomReorderHint", true);
                    }
                }
            }
            base.OnDragOver(e);
        }

        #endregion ** protected

        //----------------------------------------------------------------------

        #region ** private

        private void GridViewEx_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
        {
            _currentOverIndex = -1;
            _topReorderHintIndex = -1;
            _bottomReorderHintIndex = -1;
            _lastGroup = -1;
            _currentOverGroup = -1;
            object item = e.Items[0];
            _lastIndex = this.ItemContainerGenerator.IndexFromContainer(this.ItemContainerGenerator.ContainerFromItem(item));
            _lastGroup = this.GetItemGroup(item);
            OnDragStarting(e);
        }

        protected int GetDragOverIndex(DragEventArgs e)
        {
            FrameworkElement root = Window.Current.Content as FrameworkElement;

            Point position = this.TransformToVisual(root).TransformPoint(e.GetPosition(this));

            int newIndex = -1;

            // check items directly under the pointer
            foreach (var element in VisualTreeHelper.FindElementsInHostCoordinates(position, root))
            {
                // assume horizontal orientation
                var container = element as ContentControl;
                if (container == null)
                {
                    continue;
                }

                int tempIndex = this.ItemContainerGenerator.IndexFromContainer(container);
                if (tempIndex >= 0)
                {
                    _currentOverGroup = GetItemGroup(container.Content);
                    // we only need GridViewItems belonging to this GridView control
                    // if we found one - we done
                    newIndex = tempIndex;
                    // adjust index depending on pointer position
                    Point center = container.TransformToVisual(root).TransformPoint(new Point(container.ActualWidth / 2, container.ActualHeight / 2));
                    if (position.Y > center.Y)
                    {
                        newIndex++;
                    }
                    break;
                }
            }
            if (newIndex < 0)
            {
                // if we haven't found item under the pointer, check items in the rectangle to the left from the pointer position
                foreach (var element in GetIntersectingItems(position, root))
                {
                    // assume horizontal orientation
                    var container = element as ContentControl;
                    if (container == null)
                    {
                        continue;
                    }

                    int tempIndex = this.ItemContainerGenerator.IndexFromContainer(container);
                    if (tempIndex < 0)
                    {
                        // we only need GridViewItems belonging to this GridView control
                        // so skip all elements which are not
                        continue;
                    }
                    Rect bounds = container.TransformToVisual(root).TransformBounds(new Rect(0, 0, container.ActualWidth, container.ActualHeight));

                    if (bounds.Left <= position.X && bounds.Top <= position.Y && tempIndex > newIndex)
                    {
                        _currentOverGroup = GetItemGroup(container.Content);
                        newIndex = tempIndex;
                        // adjust index depending on pointer position
                        if (position.Y > bounds.Top + container.ActualHeight / 2)
                        {
                            newIndex++;
                        }
                        if (bounds.Right > position.X && bounds.Bottom > position.Y)
                        {
                            break;
                        }
                    }
                }
            }
            if (newIndex < 0)
            {
                newIndex = 0;
            }
            if (newIndex >= Items.Count)
            {
                newIndex = Items.Count - 1;
            }
            return newIndex;
        }

        ///



        /// returns all items in the rectangle with x=0, y=0, width=intersectingPoint.X, height=root.ActualHeight.
        ///
        ///
        ///
        ///
        private static IEnumerable GetIntersectingItems(Point intersectingPoint, FrameworkElement root)
        {
            Rect rect = new Rect(0, 0, intersectingPoint.X, root.ActualHeight);
            return VisualTreeHelper.FindElementsInHostCoordinates(rect, root);
        }

        private void GoItemToState(int index, string state, bool useTransitions)
        {
            if (index >= 0)
            {
                Control control = this.ItemContainerGenerator.ContainerFromIndex(index) as Control;
                if (control != null)
                {
                    VisualStateManager.GoToState(control, state, useTransitions);
                }
            }
        }

        private int GetGroupForIndex(int index)
        {
            if (index < 0)
            {
                return index;
            }
            return GetItemGroup(Items[index]);
        }

        private int GetItemGroup(object item)
        {
            ICollectionView view = this.ItemsSource as ICollectionView;
            if (view != null && view.CollectionGroups != null)
            {
                foreach (ICollectionViewGroup gr in view.CollectionGroups)
                {
                    if (gr.Group == item || gr.GroupItems.IndexOf(item) >= 0)
                    {
                        return view.CollectionGroups.IndexOf(gr);
                    }
                }
            }
            return -1;
        }

        #endregion ** private
    }

    ///



    /// Provides data for the event.
    ///
    public sealed class BeforeDropItemsEventArgs : System.ComponentModel.CancelEventArgs
    {
        internal BeforeDropItemsEventArgs(object item, int oldIndex, int newIndex, DragEventArgs dragEventArgs)
            : this(item, oldIndex, newIndex, -1, -1, false, dragEventArgs)
        {
        }

        internal BeforeDropItemsEventArgs(object item, int oldIndex, int newIndex,
            int oldGroupIndex, int newGroupIndex, bool requestCreateNewGroup, DragEventArgs dragEventArgs)
            : base()
        {
            RequestCreateNewGroup = requestCreateNewGroup;
            OldGroupIndex = oldGroupIndex;
            NewGroupIndex = newGroupIndex;
            OldIndex = oldIndex;
            NewIndex = newIndex;
            Item = item;
        }

        ///



        /// Gets the item which is beeing dragged.
        ///
        public object Item
        {
            get;
            private set;
        }

        ///



        /// Gets the current item index in the underlying data source.
        ///
        public int OldIndex
        {
            get;
            private set;
        }

        ///



        /// Gets the index in the underlying data source where the item will be insertet by the drop operation.
        ///
        public int NewIndex
        {
            get;
            private set;
        }

        ///



        /// Gets the value determining whether end-user actions requested creation of the new group in the underlying data source.
        /// This property only makes sense if GridViewEx.IsGrouping property is true.
        ///
        ///
        /// If this property is true, create the new data group and insert it into the groups collection at the positions, specified by the
        /// property value. Then the will insert dragged item
        /// into the newly added group.
        ///
        public bool RequestCreateNewGroup
        {
            get;
            internal set;
        }

        ///



        /// Gets the current item data group index in the underlying data source.
        /// This property only makes sense if GridViewEx.IsGrouping property is true.
        ///
        public int OldGroupIndex
        {
            get;
            internal set;
        }

        ///



        /// Gets the data group index in the underlying data source where the item will be insertet by the drop operation.
        /// This property only makes sense if GridViewEx.IsGrouping property is true.
        ///
        public int NewGroupIndex
        {
            get;
            internal set;
        }

        ///



        /// Gets the original data.
        ///
        public DragEventArgs DragEventArgs
        {
            get;
            private set;
        }
    }
}

After that you can handle the DropMethod in your any of derived calsses like below

   public class DraggableSectionGridView : DraggableGridView
    {
        public DraggableSectionGridView()
        {
            this.Drop += DraggableSectionGridView_Drop;
        }


        private ObservableCollection ItemsSourceValue
        {
            get { return this.ItemsSource as ObservableCollection; }
        }

        void DraggableSectionGridView_Drop(object sender, Windows.UI.Xaml.DragEventArgs e)
        {
            //throw new NotImplementedException();
            IList items = (IList)e.Data.GetView().Properties["Items"];
            object draggedItem = (items != null && items.Count > 0) ? items[0] : Items[_lastIndex];
            if (items != null)
            {
                // read custom drag data as below if they have been set in OnDragStarting
                // string text = await e.Data.GetView().GetTextAsync();

                int droppedIndex = GetDragOverIndex(e);
                var draggedIndex = this.ItemsSourceValue.IndexOf(draggedItem as GridViewCustomControl);
                if (droppedIndex >= 0 && draggedIndex >= 0)
                {
                    if (droppedIndex != draggedIndex)
                    {
                        var droppedItem = this.ItemsSourceValue[droppedIndex];

                        this.ItemsSourceValue.RemoveAt(draggedIndex);
                        if (droppedIndex > draggedIndex)
                        {
                            //this.Items.RemoveAt(oldIndex);
                            droppedIndex -= 1;
                            //oldIndex += 1;
                        }
                        //var freshDraggedControl = Activator.CreateInstance(draggedItem.GetType()) as GridViewCustomControl;


                        this.ItemsSourceValue.Insert(droppedIndex, draggedItem as GridViewCustomControl);
                        //freshDraggedControl.DataContext = (draggedItem as Control).DataContext;
                    }
                }
            }
        }
    }

Feel free to reach me by posting comment or emailing me vinod8812@gmail.com

Tuesday, July 15, 2014

Live SDK for Windows store app

First of all, you need to download the live sdk from here.

Once SDK is downloaded, you need to add refrence to the project where you want to use. It will appear as Extension under Windows component.




Not to login using Live below method can be used. Note this method can be called once and the LiveConnectSession will used later on for further operations like Upload file/Download files etc.

public static async Task GetToken()
        {
            try
            {
                //if (authClient == null)
                //{
                    authClient = new LiveAuthClient();
                //}
                //authClient.i)
                LiveLoginResult loginResult = await authClient.LoginAsync(scopes);
                await Task.Delay(1000); //TODO
                if (loginResult.Status == LiveConnectSessionStatus.Connected)
                {
                    return loginResult.Session;
                }
            }
            catch (LiveAuthException authExp)
            {
            }
            return null;
        }

Creating a Directory using LiveConnect you can use the below method. This method creates the directory in case Directory name is not available otherwise return the Id of directory.

  private async static Task CreateDirectoryAsync(this LiveConnectClient client, string folderName, string parentFolder)
        {
            string folderId = null;

            // Retrieves all the directories.
            var queryFolder = parentFolder + "/files?filter=folders,albums";
            var opResult = await client.GetAsync(queryFolder);
            dynamic result = opResult.Result;

            foreach (dynamic folder in result.data)
            {
                // Checks if current folder has the passed name.
                if (folder.name.ToLowerInvariant() == folderName.ToLowerInvariant())
                {
                    folderId = folder.id;
                    break;
                }
            }

            if (folderId == null)
            {
                // Directory hasn't been found, so creates it using the PostAsync method.
                var folderData = new Dictionary();
                folderData.Add("name", folderName);
                opResult = await client.PostAsync(parentFolder, folderData);
                result = opResult.Result;

                // Retrieves the id of the created folder.
                folderId = result.id;
            }

            return folderId;
        }

Download the file using LiveSDK

 public static async Task GetFileAsync(string key, string fileId, LiveConnectSession session)
        {
            try
            {
                var liveConnectClient = new LiveConnectClient(session);
                var folder = await Windows.Storage.ApplicationData.Current.TemporaryFolder.CreateFolderAsync("TempFolder", Windows.Storage.CreationCollisionOption.OpenIfExists);
                var file = await folder.CreateFileAsync("TempFile", CreationCollisionOption.ReplaceExisting);
                LiveDownloadOperation operation = await liveConnectClient.CreateBackgroundDownloadAsync(fileId + "/content", file);
                var result = await operation.StartAsync();
                var json = await Windows.Storage.FileIO.ReadTextAsync(result.File);
                return json;
            }
            catch (Exception)
            {
                return null;
            }

        }