Create calendar mark-up for Windows Phone

For didactic purpose I have started to create a calendar mark-up for Windows Phone using Silverlight technology. Silverlight is native for Windows Phone and this is one of the reasons I choose it. The final scope is to have something like this.

CalendarWindowsPhone

First step you need to do is to add a user control in your project. In my case I have created a folder called Controls and inside it I have added a user control called Calendar. After this step is done, is time to move to the calendar logic itself. First of all, you need a grid with 7 columns and 8 rows. 7 columns because I we have only seven days is an week and 8 rows you need for the following distribution:
– 1st row is containing buttons for navigation to previous or next month and to display selected month and year.
– 2nd row is containing days of the week.
– Rows 3,4,5,6,7 are containing dates for selected month
– Last row is for displaying additional data based on selected date. It’s all about developers imagination what data wants to display and how and I won’t talk about this.

The CAML code is simple. You can note the grid, days of the week displayed in blocks of text wrapped in borders controls and a long list selector which can be used to display additional date.

<UserControl xmlns:Controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"  x:Class="PhoneCorporateApplication.Controls.Calendar"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    xmlns:sharecontrols="clr-namespace:PhoneCorporateApplication.Controls"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    d:DesignHeight="480" d:DesignWidth="480">
    
    <Grid x:Name="LayoutRoot"  Background="#000" Loaded="LayoutRoot_Loaded">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*"></ColumnDefinition>
            <ColumnDefinition Width="1*"></ColumnDefinition>
            <ColumnDefinition Width="1*"></ColumnDefinition>
            <ColumnDefinition Width="1*"></ColumnDefinition>
            <ColumnDefinition Width="1*"></ColumnDefinition>
            <ColumnDefinition Width="1*"></ColumnDefinition>
            <ColumnDefinition Width="1*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"  />
            <RowDefinition Height="Auto"  />
            <RowDefinition Height="Auto" x:Name="FirstWeek"  />
            <RowDefinition Height="Auto" x:Name="SecondWeek"  />
            <RowDefinition Height="Auto" x:Name="ThirdWeek"  />
            <RowDefinition Height="Auto" x:Name="FourthWeek"  />
            <RowDefinition Height="Auto" x:Name="FifthWeek"  />
            <RowDefinition Height="Auto" x:Name="SixthWeek"  />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>


        <Button Grid.Row="0" Grid.Column="0" Name="btnPrevMonth"  Content="&lt;" BorderThickness="0" Click="btnPrevMonth_Click" />
        <TextBlock Name="txtMonthAndYear" Text="" VerticalAlignment="Center" HorizontalAlignment="Stretch" Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="5" TextAlignment="Center"  />
        <Button Grid.Row="0" Grid.Column="6" Name="btnNextMonth"  Content="&gt;" BorderThickness="0" Click="btnNextMonth_Click" />


        <!-- Calendar days-->
        <Border Grid.Column="0" Grid.Row="1" Background="BlueViolet" CornerRadius="4" Margin="2">
            <TextBlock Text="Su" Style="{StaticResource CalendarDays}" />
        </Border>
        <Border Grid.Column="1" Grid.Row="1" Background="BlueViolet" CornerRadius="4" Margin="2">
            <TextBlock  Text="Mo" Style="{StaticResource CalendarDays}" />
        </Border>
        <Border Grid.Column="2" Grid.Row="1" Background="BlueViolet" CornerRadius="4" Margin="2">
            <TextBlock Text="Tu" Style="{StaticResource CalendarDays}" />
        </Border>
        <Border Grid.Column="3" Grid.Row="1" Background="BlueViolet" CornerRadius="4" Margin="2">
            <TextBlock Text="We" Style="{StaticResource CalendarDays}"  />
        </Border>
        <Border Grid.Column="4" Grid.Row="1" Background="BlueViolet" CornerRadius="4" Margin="2">
            <TextBlock Grid.Column="4" Grid.Row="0" Text="Th" Style="{StaticResource CalendarDays}"  />
        </Border>
        <Border Grid.Column="5" Grid.Row="1" Background="BlueViolet" CornerRadius="4" Margin="2">
            <TextBlock Grid.Column="5" Grid.Row="0" Text="Fr" Style="{StaticResource CalendarDays}" />
        </Border>
        <Border Grid.Column="6" Grid.Row="1" Background="BlueViolet" CornerRadius="4" Margin="2">
            <TextBlock Grid.Column="6" Grid.Row="0" Text="Sa" Style="{StaticResource CalendarDays}" />
        </Border>
         <StackPanel Orientation="Horizontal" Grid.Row="8" Grid.Column="0" Grid.ColumnSpan="7">

            <Controls:LongListSelector Name="ViewEvents">
              
            </Controls:LongListSelector>
         
         </StackPanel>


    </Grid>
</UserControl>

From this code we missed dates for selected months, but this will be added dynamically from the code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;

namespace PhoneCorporateApplication.Controls
{
    public partial class Calendar : UserControl
    {
        /// <summary>
        /// Months names
        /// </summary>
        string[] months = new string[12] { "January","February","March","April","May","June","July","August","September","October","November","December" };
        
        /// <summary>
        /// Selected month
        /// </summary>
        int selectedMonth;
        /// <summary>
        /// Selected year
        /// </summary>
        int selectedYear;


        /// <summary>
        /// Draw calendar mark-up
        /// </summary>
        /// 
        /// 
        public void DrawCalendar(int year, int month)
        {
            
            CleanCalendar();
       

            this.selectedMonth = month;
            this.selectedYear = year;

            DateTime firstDay = new DateTime(year, month, 1);
            DateTime lastDay = new DateTime(year, month, DateTime.DaysInMonth(year, month));

            int week = 2;
            while (firstDay &lt;= lastDay)
            {
                var txtCalendarDate = new TextBlock();
                txtCalendarDate.Style = Application.Current.Resources[&quot;CalendarDates&quot;] as Style;
                txtCalendarDate.Text = Convert.ToString(firstDay.Day);
               
                txtCalendarDate.Loaded += txtCalendarDate_Loaded;
                txtCalendarDate.Tap += txtCalendarDate_Tap;
               

                // Create border arround date
                Border calendarDateBorder = new Border();
                calendarDateBorder.Style = Application.Current.Resources[&quot;CalendarDateBackground&quot;] as Style;
                calendarDateBorder.Child = txtCalendarDate;

                Grid.SetRow(calendarDateBorder, week);
                Grid.SetColumn(calendarDateBorder, Convert.ToInt16(firstDay.DayOfWeek));
                this.LayoutRoot.Children.Add(calendarDateBorder);
       
              
                if (firstDay.DayOfWeek == DayOfWeek.Saturday)
                {
                    week++;
                }
                firstDay = firstDay.AddDays(1);
            }


            this.txtMonthAndYear.Text = this.months.ElementAt(month - 1) + &quot; - &quot; + year;  
        }

        void txtCalendarDate_Loaded(object sender, RoutedEventArgs e)
        {
           
        }

        void txtCalendarDate_Tap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            TextBlock txtCalendarDate = (TextBlock)sender;
            
        }


        public Calendar()
        {
            InitializeComponent();
        }

        private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
        {
            DrawCalendar(System.DateTime.Today.Year, System.DateTime.Today.Month);
        }


        /// <summary>
        /// Go to next month
        /// </summary>
        /// 
        /// 
        private void btnNextMonth_Click(object sender, RoutedEventArgs e)
        {
            CleanCalendar();
 
            if(this.selectedMonth == 12) {
                this.DrawCalendar(this.selectedYear + 1, 1);
            }
            else {
                this.DrawCalendar(this.selectedYear, this.selectedMonth + 1);
            }
        
        
        }

        /// <summary>
        /// Go to previous month
        /// </summary>
        /// 
        /// 
        private void btnPrevMonth_Click(object sender, RoutedEventArgs e)
        {
            CleanCalendar();
            if(this.selectedMonth == 1)
            {
                this.DrawCalendar(this.selectedYear - 1, 12);
            }
            else
            {
                this.DrawCalendar(this.selectedYear, this.selectedMonth - 1);
            }
        }


        /// <summary>
        /// Clean existing calendar data before render new mark-up
        /// </summary>
        private void CleanCalendar()
        {
            int[] rows = new int[6] { 2, 3, 4, 5, 6, 7 };
            for(int i = 0; i  0)
            {
                LayoutRoot.Children.Remove(eList.First());
            }
        }

    }
} 

The main method is DrawCalendar which accepts two integer parameters: year and month. When the user control is loaded it is called with year and month for current date. Previous and next month buttons are calling it with different parameters by adding or decreasing month and year properties with 1 month. There is method bind to tap even for each block of text representing dates of month. Depending of requirements, implementation should be done here.

Advertisements

Getting list items from SharePoint Online to Windows phone

Getting data from SharePoint Online to Windows phone is not too complicated. But I am referencing here only projects targeting Windows 8.0, as Microsoft supply a SharePoint SDK only for this platform and I am not aware yet of a SDK targeting Windows 8.1.

As a concrete example, I have created an announcement list called “Company News” in a SharePoint Online environmental and I trying to display it in a client mobile application. The structure of announcement list is simple, being only interested in getting only 3 columns: Title (single line of text), Body (plain text), and Category (choice field).

I will start presenting structure of my project, which is a Silverlight blank application for Windows phone, and explain it step by step.

Sprint Structure

CompanyUpdate.cs is a simple class representing data structure of my SharePoint list. A list of CompanyUpdate objects will be used as source for a longlistselector control.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace SPRInt
{
    class CompanyUpdate
    {
        public string Title { get; set; }
        public string Category { get; set; }
        public string Body { get; set; }

    }
}

ExtensionMethods.cs contains a single static class with a single extension method, designed to replace br tags with /n and strip all other HTML tags. That’s because content of Body column contains HTML tags but my application is not HTML based.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace SPRInt
{
     public static class ExtendedMethods
    {
         public static string StripTags (this string input)
         {
             string _input = Regex.Replace(input, @&amp;amp;amp;amp;amp;quot;(&amp;amp;amp;amp;amp;lt;br */&amp;amp;amp;amp;amp;gt;)|(\[br */\])&amp;amp;amp;amp;amp;quot;, &amp;amp;amp;amp;amp;quot;\n&amp;amp;amp;amp;amp;quot;);
             _input = Regex.Replace(_input, @&amp;amp;amp;amp;amp;quot;(&amp;amp;amp;amp;amp;lt;.*?&amp;amp;amp;amp;amp;gt;)&amp;amp;amp;amp;amp;quot;, String.Empty;
             return _input;
         }

    }
}

We are moving now to ListOperations.cs , which is actually the core of the application.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Phone;

namespace SPRInt
{
    class ListOperations
    {
        string url;

        /// &amp;amp;amp;amp;amp;lt;summary&amp;amp;amp;amp;amp;gt;
        /// List operations constructor
        /// &amp;amp;amp;amp;amp;lt;/summary&amp;amp;amp;amp;amp;gt;
        /// &amp;amp;amp;amp;amp;lt;param name=&amp;amp;amp;amp;amp;quot;url&amp;amp;amp;amp;amp;quot;&amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;lt;/param&amp;amp;amp;amp;amp;gt;
        public ListOperations(string url)
        {
            this.url = url;
        }

        /// &amp;amp;amp;amp;amp;lt;summary&amp;amp;amp;amp;amp;gt;
        /// Get list items
        /// &amp;amp;amp;amp;amp;lt;/summary&amp;amp;amp;amp;amp;gt;
        /// &amp;amp;amp;amp;amp;lt;param name=&amp;amp;amp;amp;amp;quot;listName&amp;amp;amp;amp;amp;quot;&amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;lt;/param&amp;amp;amp;amp;amp;gt;
        public void GetItems(string listName, Action&amp;amp;amp;amp;amp;lt;List&amp;amp;amp;amp;amp;lt;CompanyUpdate&amp;amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;gt; callback)
        {
            Authenticator sprintAuthenticator = new Authenticator();
            sprintAuthenticator.AuthenticationMode = ClientAuthenticationMode.MicrosoftOnline;
            sprintAuthenticator.CookieCachingEnabled = true;

            ClientContext ctx = new ClientContext(this.url);
            ctx.Credentials = sprintAuthenticator;

                List spList = ctx.Web.Lists.GetByTitle(listName);
                CamlQuery query = CamlQuery.CreateAllItemsQuery();
                ListItemCollection items = spList.GetItems(query);
                ctx.Load(items);

                ctx.ExecuteQueryAsync(
                    (Object sender, ClientRequestSucceededEventArgs args) =&amp;amp;amp;amp;amp;gt; {
                        List&amp;amp;amp;amp;amp;lt;CompanyUpdate&amp;amp;amp;amp;amp;gt; companyUpdates = new List&amp;amp;amp;amp;amp;lt;CompanyUpdate&amp;amp;amp;amp;amp;gt;();
                        foreach (ListItem item in items)
                        {
                            CompanyUpdate cUpdate = new CompanyUpdate();
                            cUpdate.Title = Convert.ToString(item[&amp;amp;amp;amp;amp;quot;Title&amp;amp;amp;amp;amp;quot;]);
                            cUpdate.Category = Convert.ToString(item[&amp;amp;amp;amp;amp;quot;Category&amp;amp;amp;amp;amp;quot;]);
                            cUpdate.Body = Convert.ToString(item[&amp;amp;amp;amp;amp;quot;Body&amp;amp;amp;amp;amp;quot;]).StripTags();
                            companyUpdates.Add(cUpdate);
                        }
                        callback(companyUpdates);
                    },
                    (Object sender, ClientRequestFailedEventArgs args) =&amp;amp;amp;amp;amp;gt; {

                    }
                );

        }

    }
}

You can note I am using Microsoft.SharePoint.Client and Microsoft.SharePoint.Client.Phone namespaces in the file, these being available because I have SharePoint SDK for Windows phone libraries to my project. Being now able to use classes coming from these namespace, I can make use of Authenticator class (responsible to authenticate me with SharePoint Online) and other client object model classes. Class is instantiated with url of our SharePoint and has a method called GetItems which accepts two parameters: the name of the list and an action which serves as callback method.

It remains MainPage.xaml and associated cs file. There is nothing complicated with this file. It is a simple Silverlight page containing a LongListSelector. When page is loaded, data is getting from the SharePoint list and displayed into the LongListSelector.

<phone:PhoneApplicationPage
 x:Class="SPRInt.MainPage"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
 xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 mc:Ignorable="d"
 FontFamily="{StaticResource PhoneFontFamilyNormal}"
 FontSize="{StaticResource PhoneFontSizeNormal}"
 Foreground="{StaticResource PhoneForegroundBrush}"
 SupportedOrientations="Portrait" Orientation="Portrait"
 shell:SystemTray.IsVisible="True" Loaded="PhoneApplicationPage_Loaded">

 <!--LayoutRoot is the root grid where all page content is placed-->
 <Grid x:Name="LayoutRoot" Background="Transparent">
 <Grid.RowDefinitions>
 <RowDefinition Height="Auto"/>
 <RowDefinition Height="*" />
 </Grid.RowDefinitions>



 <!--TitlePanel contains the name of the application and page title-->
 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,12,28">
 <TextBlock Text="SPRInt for mobile" Style="{StaticResource PhoneTextNormalStyle}" />
 <TextBlock Text="News" Style="{StaticResource PhoneTextTitle1Style}"/>
 
 </StackPanel>

 <!-- Data displayed here -->
 <phone:LongListSelector Grid.Row="1" Name="lstCompanyNews" Margin="12,0,12,0">
 <phone:LongListSelector.ItemTemplate>
 <DataTemplate>
 <StackPanel Orientation="Vertical">
 <TextBlock Text="{Binding Title}" Style="{StaticResource companyupdatetitle}" />
 <TextBlock Text="{Binding Category}" Foreground="AliceBlue" />
 <TextBlock Text="{Binding Body}" Foreground="AliceBlue" />
 </StackPanel> 
 </DataTemplate>
 </phone:LongListSelector.ItemTemplate>

 </phone:LongListSelector>


 </Grid>

</phone:PhoneApplicationPage>
       
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.SharePoint.Client;
using Microsoft.SharePoint.Client.Phone;
using Microsoft.Phone.Shell;

using SPRInt.Resources;

namespace SPRInt
{
 public partial class MainPage : PhoneApplicationPage
 {
 // Constructor
 public MainPage()
 {
 InitializeComponent();
 }

 private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
 {
 ListOperations ops = new ListOperations("https://sprint");
 Action<List<CompanyUpdate>> callback = (List<CompanyUpdate> items) =>
 {
 this.Dispatcher.BeginInvoke(() =>
 {

 this.lstCompanyNews.ItemsSource = items;
 });
 };
 ops.GetItems("Company News", callback);

 }

 }
}