Walkthrough: Accessing contact and calendar data for Windows Phone 8

Applies to: Windows Phone 8 and Windows Phone Silverlight 8.1 | Windows Phone OS 7.1

 

In this walkthrough, you build a simple contacts and calendar app. The app that you create in this walkthrough displays contacts, appointments, and the accounts that the data comes from. To download a completed version of this app, see Contacts and Calendar Sample.

This topic discusses read-only access to user’s contact data. For information on creating a custom contact store for your app that provides read and write access, see Custom contact store for Windows Phone 8.

In this walkthrough, you perform the following tasks.

  • Access contact and calendar data.

  • Bind contacts, appointments, and accounts to the user interface.

  • Display details for individual contacts (including photo) and appointments.

  • Data-bind contact photos to the user interface by creating a custom data converter.

The completed app looks like the following.

The main page of the app

This topic contains the following sections.

 

To complete this walkthrough, you must have the Windows Phone SDK installed. For more information, see Windows Phone 8 SDK tools.

First, you create a new Windows Phone app project named ContactsAndCalendarTestApp. In later steps, you will add code to your app that assumes the app name is ContactsAndCalendarTestApp. If you choose a different name for your app, you must change the namespace references in the code.

To create the app project

  1. In Visual Studio, on the File menu, point to New and then click Project.

    The New Project dialog appears.

  2. In the left pane, click Installed Templates, expand Visual C# or Visual Basic, and then click Windows Phone.

  3. In the list of project types, click Windows Phone App .

  4. In the Name box, type ContactsAndCalendarTestApp.

  5. Click OK.

    The Windows Phone platform selection dialog box appears.

  6. In the Target Windows Phone Version drop-down list, select Windows Phone OS 7.1 and then click OK.

    The new app project is created and opens in Visual Studio.

This app contains a main page with three pivot items, one each for contacts, appointments, and accounts. There are also two additional pages for the contact and appointment details.

To set up the app structure

  1. In Solution Explorer, select MainPage.xaml and then press the Delete key to delete it.

  2. In Solution Explorer, right-click the project, point to Add, and then click New Item.

    The Add New Item dialog appears.

  3. Select Windows Phone Pivot Page, enter the name MainPage.xaml, and then click Add.

    The new pivot page opens in the designer.

  4. In the XAML code, locate the GRID element named LayoutRoot. Replace everything from there to the end of the file with the following code. This creates the three pivot items that you will fill in later.

        <!--LayoutRoot is the root grid where all page content is placed-->
        <Grid x:Name="LayoutRoot" Background="Transparent">
    
            <!--Pivot Control-->
            <controls:Pivot Title="Contacts and Calendar Test App" >
    
                <!--Pivot item one-->
                <controls:PivotItem Header="contacts">
                </controls:PivotItem>
    
    
                <!--Pivot item two-->
                <controls:PivotItem Header="accounts">
                </controls:PivotItem>
    
    
                <!--Pivot item three-->
                <controls:PivotItem Header="appointments">
                </controls:PivotItem>
    
            </controls:Pivot>
        </Grid>
    </phone:PhoneApplicationPage>
    
  5. In Solution Explorer, right-click the project, point to Add, and then click New Item.

    The Add New Item dialog appears.

  6. Select Windows Phone Portrait Page, enter the name AppointmentDetails.xaml, and then click Add.

    The new page opens in the designer.

  7. In Solution Explorer, right-click the project, point to Add, and then click New Item.

    The Add New Item dialog appears.

  8. Select Windows Phone Portrait Page, enter the name ContactDetails.xaml, and then click Add.

    The new page opens in the designer.

  9. In Solution Explorer, right-click App.xaml and then click View Code.

    The code-behind file opens in the code editor.

  10. At the top of the class, add the following code. This code creates two global static variables that you use to pass data between the main page and the detail pages.

    public static Microsoft.Phone.UserData.Contact con;
    public static Microsoft.Phone.UserData.Appointment appt;
    
  11. (Optional) Disable the frame rate counters by commenting out the following code.

    Application.Current.Host.Settings.EnableFrameRateCounter = true;
    

In this procedure, you run the app to test your progress.

To test the app

  1. On the File menu, click Save All. (Ctrl+Shift+S)

  2. On the Build (or the Debug menu), click Build Solution. (Ctrl+Shift+B)

  3. On the standard toolbar, set the deployment target of the app to Windows Phone Emulator or Windows Phone Device.

    Target on Standard Toolbar selecting emulator Or Target on Standard Toolbar selecting device

  4. On the Debug menu, click Start Debugging. (F5)

    The app starts and the main page appears.

  5. Swipe the pivot items. All three pivot items should appear with the headers contacts, accounts, and appointments.

  6. On the Debug menu, click Stop Debugging. (F5)

The process for accessing contact data is to get a reference to the Contacts object, perform an asynchronous search on it by calling SearchAsync, and then capture the results as a collection of Contact objects in the SearchCompleted event handler.

To create the contact pivot item UI

  1. In Solution Explorer, double-click MainPage.xaml to open it in the designer.

  2. Locate the first pivot item and replace it with the following code. This code creates the text box, radio buttons, and button that are used to search for contacts. It also creates the list box that contains the results of the search.

    <controls:PivotItem Header="contacts">
        <StackPanel Height="Auto" Width="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
    
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
    
                <TextBox Grid.Row="0" Grid.ColumnSpan="2" Name="contactFilterString" />
                <RadioButton Grid.Row="1" Grid.Column="0" Checked="FilterChange" Name="name" Content="name" />
                <RadioButton Grid.Row="1" Grid.Column="1" Checked="FilterChange" Name="phone" Content="phone"/>
                <RadioButton Grid.Row="2" Grid.Column="0" Checked="FilterChange" Name="email" Content="email"/>
                <Button Grid.Row="2" Grid.Column="1" Content="search" Click="SearchContacts_Click" />
            </Grid>
    
            <TextBlock Name="ContactResultsLabel" Text="Search for contacts" TextWrapping="Wrap" Margin="12,0,0,0" />
    
            <ListBox Name="ContactResultsData" ItemsSource="{Binding}" Tap="ContactResultsData_Tap" Height="300" Margin="24,0,0,0" >
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Name="ContactResults" Text="{Binding Path=DisplayName, Mode=OneWay}" FontSize="{StaticResource PhoneFontSizeExtraLarge}" Margin="18,8,0,0" />
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </StackPanel>
    </controls:PivotItem>
    
    

To access contact data

  1. In Solution Explorer, right-click MainPage.xaml and then click View Code.

    The code-behind file opens in the code editor.

  2. Replace the code with the following. This code sets the default contact search filter to none, and sets the default contact search type to name. It also contains the code to change the search filter when you select the radio buttons. For more information, see Contact filtering and matching for Windows Phone 8.

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using Microsoft.Phone.Controls;
    using Microsoft.Phone.UserData;
    
    namespace ContactsAndCalendarTestApp
    {
        public partial class MainPage : PhoneApplicationPage
        {
            FilterKind contactFilterKind = FilterKind.None;
    
            // Constructor
            public MainPage()
            {
                InitializeComponent();
    
                name.IsChecked = true;
            }
    
    
            private void FilterChange(object sender, RoutedEventArgs e)
            {
                String option = ((RadioButton)sender).Name;
    
                InputScope scope = new InputScope();
                InputScopeName scopeName = new InputScopeName();
    
                switch (option)
                {
                    case "name":
                        contactFilterKind = FilterKind.DisplayName;
                        scopeName.NameValue = InputScopeNameValue.Text;
                        break;
    
                    case "phone":
                        contactFilterKind = FilterKind.PhoneNumber;
                        scopeName.NameValue = InputScopeNameValue.TelephoneNumber;
                        break;
    
                    case "email":
                        contactFilterKind = FilterKind.EmailAddress;
                        scopeName.NameValue = InputScopeNameValue.EmailSmtpAddress;
                        break;
    
                    default:
                        contactFilterKind = FilterKind.None;
                        break;
                }
    
                scope.Names.Add(scopeName);
                contactFilterString.InputScope = scope;
                contactFilterString.Focus();
            }
        }//End page class
    }//End namespace
    
  3. After the constructor, add the following code. This code contains the search button click event, and starts the asynchronous contact search.

    private void SearchContacts_Click(object sender, RoutedEventArgs e)
    {
        ContactResultsLabel.Text = "results are loading...";
        ContactResultsData.DataContext = null;
    
        Contacts cons = new Contacts();
    
        cons.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(Contacts_SearchCompleted);
    
        cons.SearchAsync(contactFilterString.Text, contactFilterKind, "Contacts Test #1");
    }
    
  4. After the click event, add the following code. This code contains the method to handle the completed event of the asynchronous search. This code binds the contact data to the user interface by setting the data context of the list box equal to the results of the search. It includes error handling in case there are no results. The code also changes the text of the list box label depending on whether there are results or not.

    void Contacts_SearchCompleted(object sender, ContactsSearchEventArgs e)
    {
        //MessageBox.Show(e.State.ToString());
    
        try
        {
            //Bind the results to the list box that displays them in the UI
            ContactResultsData.DataContext = e.Results;
        }
        catch (System.Exception)
        {
            //That's okay, no results
        }
    
        if (ContactResultsData.Items.Count > 0)
        {
            ContactResultsLabel.Text = "results (tap name for details...)";
        }
        else
        {
            ContactResultsLabel.Text = "no results";
        }
    }
    
  5. After the search completed event, add the following code. When you tap a contact in the results list, this code stores the contact in a global variable, and then navigates to the contact details page.

    private void ContactResultsData_Tap(object sender, GestureEventArgs e)
    {
        App.con = ((sender as ListBox).SelectedValue as Contact);
    
        NavigationService.Navigate(new Uri("/ContactDetails.xaml", UriKind.Relative));
    }
    

When you tap a contact in the results list on the main page, the app navigates to the contact details page.

To display the contact details

  1. In Solution Explorer, double-click ContactDetails.xaml to open it in the designer.

  2. Locate the GRID element named LayoutRoot. Replace everything from there to the end of the file with the following code. This creates a text block for the contact’s name, an image for the contact’s photo, and list boxes to hold other contact data.

        <!--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,0,0">
                <TextBlock x:Name="ApplicationTitle" Text="Contacts and Calendar Test App" Style="{StaticResource PhoneTextNormalStyle}"/>
                <TextBlock x:Name="PageTitle" Text="contact details" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
            </StackPanel>
    
            <!--ContentPanel - place additional content here-->
            <StackPanel x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    
                <TextBlock Text="{Binding Path=DisplayName, Mode=OneWay}" Foreground="{StaticResource PhoneAccentBrush}" FontSize="{StaticResource PhoneFontSizeExtraLarge}" />
    
                <Border BorderThickness="2" HorizontalAlignment="Left" BorderBrush="{StaticResource PhoneAccentBrush}" >
                    <Image Name="Picture" Height="85" Width="85" HorizontalAlignment="Left" />
                </Border>
    
                <TextBlock Text="phone numbers" Margin="12,12,0,0"/>
                <ListBox ItemsSource="{Binding Path=PhoneNumbers}" Height="60"  Margin="36,0,0,0">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
                                <TextBlock Grid.Column="0" Text="{Binding Path=Kind, Mode=OneWay}" />
                                <TextBlock Grid.Column="1" Text=":  " />
                                <TextBlock Grid.Column="2" Text="{Binding Path=PhoneNumber, Mode=OneWay}" />
                            </Grid>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
    
                <TextBlock Text="email addresses" Margin="12,12,0,0" />
                <ListBox ItemsSource="{Binding Path=EmailAddresses}" Height="60"  Margin="36,0,0,0">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
                                <TextBlock Grid.Column="0" Text="{Binding Path=Kind, Mode=OneWay}" />
                                <TextBlock Grid.Column="1" Text=":  " />
                                <TextBlock Grid.Column="2" Text="{Binding Path=EmailAddress, Mode=OneWay}" />
                            </Grid>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
    
                <TextBlock Text="web sites" Margin="12,12,0,0" />
                <ListBox ItemsSource="{Binding Path=Websites}" Height="60"  Margin="36,0,0,0" />
    
                <TextBlock Text="company information" Margin="12,12,0,0" />
                <ListBox ItemsSource="{Binding Path=Companies}" Height="60"  Margin="36,0,0,0">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
                                <TextBlock Grid.Column="0" Text="{Binding Path=CompanyName, Mode=OneWay}" />
                                <TextBlock Grid.Column="1" Text=":  " />
                                <TextBlock Grid.Column="2" Text="{Binding Path=JobTitle, Mode=OneWay}" />
                            </Grid>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
    
                <TextBlock Text="accounts" Margin="12,12,0,0" />
                <ListBox ItemsSource="{Binding Path=Accounts}" Height="60" Margin="36,0,0,0">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
                                <TextBlock Grid.Column="0" Text="{Binding Path=Kind, Mode=OneWay}" />
                                <TextBlock Grid.Column="1" Text=":  " />
                                <TextBlock Grid.Column="2" Text="{Binding Path=Name, Mode=OneWay}" />
                            </Grid>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
            </StackPanel>
        </Grid>
    </phone:PhoneApplicationPage>
    
    
  3. In Solution Explorer, right-click ContactDetails.xaml and then click View Code.

    The code-behind file opens in the code editor.

  4. Replace the code with the following. This code sets the data context of the page to the contact that was selected on the main page. It also calls the GetPicture method and displays the result in the image control.

    using System;
    using Microsoft.Phone.Controls;
    using System.Windows.Media.Imaging;
    
    namespace ContactsAndCalendarTestApp
    {
        public partial class ContactDetails : PhoneApplicationPage
        {
            public ContactDetails()
            {
                InitializeComponent();
            }
    
            protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
            {
                base.OnNavigatedTo(e);
    
                //Set the data context for this page to the selected contact
                this.DataContext = App.con;
    
                try
                {
                    //Try to get a picture of the contact
                    BitmapImage img = new BitmapImage();
                    img.SetSource(App.con.GetPicture());
                    Picture.Source = img;
                }
                catch (Exception)
                {
                    //can't get a picture of the contact
                }
            }
        }
    }
    

In this procedure, you run the app to test your progress.

NoteNote:

Windows Phone Emulator contains sample contacts. You can test this procedure using Windows Phone Emulator or a physical device. However, the sample contacts do not have photos.

To test the app

  1. Start your app in the emulator or on a device. If necessary, use the instructions from the first checkpoint.

    The app starts and the main page appears.

  2. In the text box, enter the letter A, and then click search.

    The results populate the list. If you test the app on Windows Phone Emulator, you see the following.

    Andrew Hill

    Arturo Lopez

  3. Tap a name in the result list.

    The contact details page opens with the contact details displayed. Not all data is available for all contacts.

  4. On the Debug menu, click Stop Debugging. (F5)

The process for accessing calendar data is to get a reference to the Appointments object, perform an asynchronous search on it by calling SearchAsync, and then capture the results as a collection of Appointment objects in the SearchCompleted event handler.

To create the appointment pivot item UI

  1. In Solution Explorer, double-click MainPage.xaml to open it in the designer.

  2. Locate the third pivot item and replace it with the following code. This code creates labels for the start and end dates, the search button, and the list box that contains the results of the search.

    <controls:PivotItem Header="appointments">
        <StackPanel Height="Auto" Width="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
    
            <TextBlock Text="appointments between" Foreground="{StaticResource PhoneAccentBrush}" />
    
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
    
                <TextBlock Grid.Row="0" Grid.Column="0" Text="start date" />
                <TextBlock Grid.Row="0" Grid.Column="1" Text="end date" />
                <TextBlock Grid.Row="1" Grid.Column="0" Text="placeholder" Name="StartDate" />
                <TextBlock Grid.Row="1" Grid.Column="1" Text="placeholder" Name="EndDate" />
                <Button Grid.Row="2" Grid.ColumnSpan="2" Content="search" Click="SearchAppointments_Click" HorizontalAlignment="Center" />
            </Grid>
    
            <TextBlock Name="AppointmentResultsLabel" Text="search for appointments" TextWrapping="Wrap" />
    
            <ListBox Name="AppointmentResultsData" ItemsSource="{Binding}" Tap="AppointmentResultsData_Tap" Height="400"  ScrollViewer.ManipulationMode="Control" Margin="24,0,0,0" >
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Path=Subject, Mode=OneWay}"  FontSize="{StaticResource PhoneFontSizeExtraLarge}" />
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </StackPanel>
    </controls:PivotItem>
    

To access appointment data

  1. In Solution Explorer, right-click MainPage.xaml and then click View Code.

    The code-behind file opens in the code editor.

  2. In the MainPage class, after the constructor, add the following code. This code contains the search button click event, and starts the asynchronous appointment search. This code searches for appointments during the upcoming week.

    private void SearchAppointments_Click(object sender, RoutedEventArgs e)
    {
        AppointmentResultsLabel.Text = "results are loading...";
        AppointmentResultsData.DataContext = null;
        Appointments appts = new Appointments();
    
        appts.SearchCompleted += new EventHandler<AppointmentsSearchEventArgs>(Appointments_SearchCompleted);
    
        DateTime start = DateTime.Now;
        DateTime end = start.AddDays(7);
    
        appts.SearchAsync(start, end, 20, "Appointments Test #1");
    }
    
  3. After the click event, add the following code. This code contains the method to handle the completed event of the asynchronous search. This code binds the appointment data to the user interface by setting the data context of the list box equal to the results of the search. It includes error handling in case there are no results. The code also changes the text of the list box label depending on whether there are results or not.

    void Appointments_SearchCompleted(object sender, AppointmentsSearchEventArgs e)
    {
        StartDate.Text = e.StartTimeInclusive.ToShortDateString();
        EndDate.Text = e.EndTimeInclusive.ToShortDateString();
    
        try
        {
            //Bind the results to the list box that displays them in the UI
            AppointmentResultsData.DataContext = e.Results;
        }
        catch (System.Exception)
        {
            //That's okay, no results
        }
    
        if (AppointmentResultsData.Items.Count > 0)
        {
            AppointmentResultsLabel.Text = "results (tap for details...)";
        }
        else
        {
            AppointmentResultsLabel.Text = "no results";
        }
    }
    
    
  4. After the search completed event, add the following code. When you tap an appointment in the results list, this code stores the appointment in a global variable, and then navigates to the appointment details page.

    private void AppointmentResultsData_Tap(object sender, GestureEventArgs e)
    {
        App.appt = ((sender as ListBox).SelectedValue as Appointment);
    
        NavigationService.Navigate(new Uri("/AppointmentDetails.xaml", UriKind.Relative));
    }
    

When you tap an appointment in the results list on the main page, the app navigates to the appointment details page.

To display the appointment details

  1. In Solution Explorer, double-click AppointmentDetails.xaml to open it in the designer.

  2. Locate the GRID element named LayoutRoot. Replace everything from there to the end of the file with the following code. This creates a text block for the appointment subject, and a scroll viewer to hold the other appointment data.

        <phone:PhoneApplicationPage.Resources>
    
            <DataTemplate x:Key="AttendeeTemplate">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Column="0" Text="{Binding Path=DisplayName, Mode=OneWay}" TextWrapping="Wrap" />
                    <TextBlock Grid.Column="1" Text=":  " />
                    <TextBlock Grid.Column="2" Text="{Binding Path=EmailAddress, Mode=OneWay}" TextWrapping="Wrap" />
                </Grid>
            </DataTemplate>
        </phone:PhoneApplicationPage.Resources>
    
    
        <!--LayoutRoot is the root grid where all page content is placed-->
        <Grid x:Name="LayoutRoot" Background="Transparent">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <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,0,6">
                <TextBlock x:Name="ApplicationTitle" Text="Contacts and Calendar Test App" Style="{StaticResource PhoneTextNormalStyle}"/>
                <TextBlock x:Name="PageTitle" Text="appt details" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
            </StackPanel>
    
            <TextBlock Grid.Row="1" Text="{Binding Path=Subject, Mode=OneWay}" Foreground="{StaticResource PhoneAccentBrush}" FontSize="{StaticResource PhoneFontSizeExtraLarge}" TextWrapping="Wrap" />
    
            <!--ContentPanel - place additional content here-->
            <ScrollViewer x:Name="ContentPanel" Grid.Row="2" Margin="12,0,12,0">
                <StackPanel>
    
                    <TextBlock Text="{Binding Path=Details, Mode=OneWay}"  Margin="12,0,0,0" TextWrapping="Wrap" />
                    
                    <TextBlock Text="{Binding Path=StartTime, Mode=OneWay}"  Margin="12,12,0,0"/>
                    <TextBlock Text="{Binding Path=EndTime, Mode=OneWay}"  Margin="12,0,0,0"/>
    
                    <TextBlock Text="{Binding Path=Location, Mode=OneWay}"  Margin="12,12,0,0"/>
    
                    <TextBlock Text="{Binding Path=Status, Mode=OneWay}"  Margin="12,12,0,0"/>
    
                    <TextBlock Text="organizer" Margin="12,12,0,0" />
                    <ListBox ItemsSource="{Binding Path=Organizer}" ItemTemplate="{StaticResource AttendeeTemplate}" Margin="24,0,0,0" />
    
                    <TextBlock Text="attendees" Margin="12,12,0,0" />
                    <ListBox ItemsSource="{Binding Path=Attendees}" ItemTemplate="{StaticResource AttendeeTemplate}" Margin="24,0,0,0" />
    
                    <TextBlock Text="accounts" Margin="12,12,0,0" />
                    <ListBox ItemsSource="{Binding Path=Accounts}" Margin="24,0,0,0">
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="Auto"/>
                                        <ColumnDefinition Width="Auto"/>
                                        <ColumnDefinition Width="*"/>
                                    </Grid.ColumnDefinitions>
                                    <TextBlock Grid.Column="0" Text="{Binding Path=Kind, Mode=OneWay}" />
                                    <TextBlock Grid.Column="1" Text=":  " />
                                    <TextBlock Grid.Column="2" Text="{Binding Path=Name, Mode=OneWay}" />
                                </Grid>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                </StackPanel>
            </ScrollViewer>
        </Grid>
    </phone:PhoneApplicationPage>
    
  3. In Solution Explorer, right-click AppointmentDetails.xaml and then click View Code.

    The code-behind file opens in the code editor.

  4. Replace the code with the following. This code set the data context of the page to the appointment that was selected on the main page.

    using Microsoft.Phone.Controls;
    
    namespace ContactsAndCalendarTestApp
    {
        public partial class AppointmentDetails : PhoneApplicationPage
        {
            public AppointmentDetails()
            {
                InitializeComponent();
            }
    
            protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
            {
                base.OnNavigatedTo(e);
    
                //Set the data context for this page to the selected appointment
                this.DataContext = App.appt;
            }
        }
    }
    
    

In this procedure, you run the app to test your progress.

Important noteImportant Note:

Windows Phone Emulator does not contain sample appointments. You can test this procedure using Windows Phone Emulator, but you will see appointments only on a physical device.

To test the app

  1. Start your app in the emulator or on a device. If necessary, use the instructions from the first checkpoint.

    The app starts and the main page appears.

  2. Swipe to the appointments pivot item, and then click the search button.

    The results populate the list.

  3. Tap an appointment in the list.

    The appointment details page opens with the appointment details displayed. If the details are long, scroll the page to see all the details.

  4. On the Debug menu, click Stop Debugging. (F5)

Windows Phone provides an aggregated view of the user’s contact data across the user's different accounts. Information can come from sources such as data entered in the phone itself, social networking sites, and other data service providers. In this procedure, you display the accounts that the contacts and calendar data comes from.

To access account data

  1. In Solution Explorer, double-click MainPage.xaml to open it in the designer.

  2. Locate the second pivot item and replace it with the following code. This code creates two list boxes, one for the contact accounts and one for the appointment accounts. This code also uses an item template which you will add in the next step.

    <controls:PivotItem Header="accounts">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
    
            <StackPanel Grid.Row="0" >
    
                <TextBlock Text="contact accounts" Foreground="{StaticResource PhoneAccentBrush}" Style="{StaticResource PhoneTextLargeStyle}" />
                <ListBox Name="ContactAccounts" ItemsSource="{Binding}" ItemTemplate="{StaticResource AccountTemplate}" Height="200" Margin="24,0,0,0" />
            </StackPanel>
    
            <StackPanel Grid.Row="1" >
    
                <TextBlock Text="appointment accounts" Foreground="{StaticResource PhoneAccentBrush}" Style="{StaticResource PhoneTextLargeStyle}" />
                <ListBox Name="CalendarAccounts" ItemsSource="{Binding}" ItemTemplate="{StaticResource AccountTemplate}" Height="200" Margin="24,0,0,0" />
            </StackPanel>
        </Grid>
    </controls:PivotItem>
    
  3. After the PHONE:PHONEAPPLICATIONPAGE element and before the GRID element, add the following code. This template displays the name and kind of account on a single line for each entry in the list.

    <phone:PhoneApplicationPage.Resources>
    
        <DataTemplate x:Key="AccountTemplate">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <TextBlock Grid.Column="0" Text="{Binding Path=Name, Mode=OneWay}" />
                <TextBlock Grid.Column="1" Text=" account: " />
                <TextBlock Grid.Column="2" Text="{Binding Path=Kind, Mode=OneWay}" />
            </Grid>
        </DataTemplate>
    
    </phone:PhoneApplicationPage.Resources>
    
  4. In Solution Explorer, right-click MainPage.xaml and then click View Code.

    The code-behind file opens in the code editor.

  5. In the constructor, after any existing code, add the following. This code binds the account data to the user interface by setting the data context of the contacts list box to the Accounts property and the appointments list box to the Accounts property.

    ContactAccounts.DataContext = (new Contacts()).Accounts;
    CalendarAccounts.DataContext = (new Appointments()).Accounts;
    

In this procedure, you run the app to test your progress.

To test the app

  1. Start your app in the emulator or on a device. If necessary, use the instructions from the first checkpoint.

    The app starts and the main page appears.

  2. Swipe to the accounts pivot item.

    The results populate the lists. If you test the app on Windows Phone Emulator, you see the following in both lists.

    Phone account: Phone

  3. On the Debug menu, click Stop Debugging. (F5)

In a previous procedure, you displayed the photo for a single contact on the contact details page. In this procedure, you data-bind multiple contact photos directly to the results list on the main page. Because contact photos are not a property (they are returned by calling the GetPicture method), you must create a custom data converter before you can data-bind them.

To data-bind contact photos to the UI

  1. In Solution Explorer, right-click MainPage.xaml and then click View Code.

    The code-behind file opens in the code editor.

  2. Locate the following code. In the next step, you add new code after this line.

    }//End page class
    
  3. After the MainPage class code, add the following new class. This is the custom data converter.

    public class ContactPictureConverter : System.Windows.Data.IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            Contact c = value as Contact;
            if (c == null) return null;
    
            System.IO.Stream imageStream = c.GetPicture();
            if (null != imageStream)
            {
                return Microsoft.Phone.PictureDecoder.DecodeJpeg(imageStream);
            }
            return null;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }//End converter class
    
  4. In Solution Explorer, double-click MainPage.xaml to open it in the designer.

  5. In the <phone:PhoneApplicationPage> tag, with the other namespace declarations, add the following code. This allows you to access the custom data converter.

    xmlns:MyApp="clr-namespace:ContactsAndCalendarTestApp"
    
  6. Locate the PHONE:PHONEAPPLICATION.RESOURCES element that you added in a previous procedure. After the data template, before the end </phone:PhoneApplicationPage.Resources> tag, add the following.

    <MyApp:ContactPictureConverter x:Key="ContactPictureConverter" />
    
  7. In the first pivot item, in the contact results, locate the following data template.

    <DataTemplate>
        <TextBlock Name="ContactResults" Text="{Binding Path=DisplayName, Mode=OneWay}" FontSize="{StaticResource PhoneFontSizeExtraLarge}" Margin="18,8,0,0" />
    </DataTemplate>
    
  8. Replace the existing data template with the following. This adds the photo of the contact, and data-binds it using the custom data converter.

    <DataTemplate>
        <StackPanel Orientation="Horizontal" >
            <Border BorderThickness="2" HorizontalAlignment="Left" VerticalAlignment="Center" BorderBrush="{StaticResource PhoneAccentBrush}" >
                <Image Source="{Binding Converter={StaticResource ContactPictureConverter}}" Width="48" Height="48" Stretch="Fill"  />
            </Border>
            <TextBlock Name="ContactResults" Text="{Binding Path=DisplayName, Mode=OneWay}" FontSize="{StaticResource PhoneFontSizeExtraLarge}" Margin="18,8,0,0" />
        </StackPanel>
    </DataTemplate>
    

In this procedure, you run the app to test your progress.

NoteNote:

Windows Phone Emulator contains sample contacts. You can test this procedure using Windows Phone Emulator or a physical device. However, the sample contacts do not have photos.

To test the app

  1. Start your app in the emulator or on a device. If necessary, use the instructions from the first checkpoint.

    The app starts and the main page appears.

  2. In the text box, enter the letter A, and then click search.

    The results populate the list. If you test the app on a physical device, some contacts may have photos. Scroll the list until you see contacts that have photos.

  3. On the Debug menu, click Stop Debugging. (F5)

You can expand the functionality of the app in the following ways.

  • Change the appointment search to get the start and end dates from the user.

  • Change the contact details page to use a scroll viewer, similar to the appointment details page.

  • Change the contact search results to display the contact’s name, email, or phone number depending on the type of search the user performs.

  • Add the ability to search for all contacts pinned to the Start screen. For more information, see Contact filtering and matching for Windows Phone 8.

Show:
© 2014 Microsoft