Georg fährt extra nach Berlin um Steve Ballmer zu treffen

31 Tage Mango | Tag #9: Kalender API

Die­ser Arti­kel ist Tag #9 der Serie 31 Tage Man­go von Jeff Blan­ken­burg.

Der Ori­gi­nal­ar­ti­kel befin­det sich hier: Day #9: Calen­dar API.

Heu­te beschäf­ti­gen wir uns noch mal mit dem Microsoft.Phone.UserData Name­space. Im heu­ti­gen Arti­kel schau­en wir uns an, wie wir den Kalen­der des Anwen­ders ver­wen­den kön­nen und wofür.

Wich­tig bei die­sen Daten ist, dass sie, wie die Kon­tak­te, nur les­bar sind. Wir sind nicht in der Lage, neue Ter­mi­ne zum Kalen­der des Anwen­ders hin­zu­zu­fü­gen. Wir kön­nen aber sehen, wann der Anwen­der ver­füg­bar ist.

Den Kalender verwenden

Einer der offen­sicht­li­chen Anwen­dungs­fäl­le für die Kalen­der­da­ten ist in einer Ter­min­pla­nungs­an­wen­dung. Stel­len Sie sich vor, Sie bau­en eine Anwen­dung für eine Arzt­pra­xis und eine der Funk­tio­nen ist: „Ver­ein­ba­re einen Ter­min beim Arzt“. Indem Sie den Kalen­der des Benut­zers mit dem Kalen­der des Arz­tes abglei­chen, soll­ten sie ein­fach in der Lage sein, einen Ter­min vor­zu­schla­gen, der für bei­de passt.

Ein wei­te­res Anwen­dungs­bei­spiel ist Kalen­der­syn­chro­ni­sie­rung. Mei­ne Frau und ich haben zum Bei­spiel bei­de ein Win­dows Pho­ne und wir nut­zen bei­de den Win­dows Live Kalen­der für unse­re Ter­mi­ne. Mit zwei Kin­dern kön­nen Sie sich vor­stel­len, dass wir ziem­lich rum­jon­glie­ren müs­sen, damit jeder zur rech­ten Zeit am rech­ten Fleck ist. Die meis­ten Ter­mi­ne unse­rer Kin­der wer­den von mei­ner Frau orga­ni­siert, also ste­hen die­se in ihrem Kalen­der. Mein Kalen­der dreht sich haupt­säch­lich um mei­ne Arbeit, mei­ne Rei­sen, User Group Mee­tings und mei­ne sport­li­chen Akti­vi­tä­ten. Unse­re Kalen­der sind nicht ver­bun­den. Sie sind nicht syn­chro­ni­siert. Momen­tan haben wir kei­ne ande­re Mög­lich­keit, als bei­de Kalen­der bei bei­den Tele­fo­nen hin­zu­zu­fü­gen. Damit ist es immer­hin mög­lich, dass ich kei­ne Rei­se wäh­rend eines wich­ti­gen Fami­li­en­er­eig­nis­ses pla­ne und sie kei­ne Ter­mi­ne plant, wenn ich nicht da bin. Eine Anwen­dung die bei­de Kalen­der ver­eint, wäre für mich eine sehr will­kom­me­ne Erwei­te­rung mei­nes Win­dows Pho­nes.

Die Benutzeroberfläche

Jetzt, wo wir eini­ge mög­li­che Anwen­dungs­fäl­le dis­ku­tiert haben, wol­len wir uns anse­hen wie man das eigent­lich macht. Ich fan­ge ger­ne mit der Benut­zer­ober­flä­che an, da ich dadurch bes­ser ver­ste­he, wel­che Daten ich eigent­lich auf dem Bild­schirm brau­che oder möch­te. Für die heu­ti­ge Anwen­dung ver­wen­den wir das DatePi­cker Con­trol aus dem Sil­ver­light Tool­kit for Win­dows Pho­ne. Wir ver­wen­den es, um eine Lis­te von Ter­mi­nen für einen bestimm­ten Tag anzu­zei­gen.

Falls Sie das Sil­ver­light Tool­kit for Win­dows Pho­ne noch nicht ken­nen, soll­ten Sie sich die­ses unbe­dingt anschau­en. Es han­delt sich um eine kos­ten­lo­se Samm­lung von Con­trols für Win­dows Pho­ne Anwen­dun­gen auf Code­plex. Ich habe das Sil­ver­light Tool­kit in Day #21 der 31 Days of Win­dows Pho­ne näher behan­delt. Sie soll­ten mit die­sen Inhal­ten ver­traut sein, bevor wir wei­ter­ma­chen. Es gibt eini­ge Fein­hei­ten zum DatePi­cker in die­sem Arti­kel, die Sie wis­sen soll­ten.

Unse­re Ober­flä­che wird die­ses Mal ziem­lich ein­fach sein. Wir wer­den einen DatePi­cker haben, mit dem der Anwen­der ein Datum aus­wäh­len kann und eine List­Box, wel­che die Kalen­der­ein­trä­ge für die­ses Datum anzeigt. Wie schon erwähnt, kön­nen wir mit die­ser API kei­ne Ter­mi­ne hin­zu­fü­gen oder ver­än­dern, wir wer­den die Ter­mi­ne dem Benut­zer also nur anzei­gen.

Im unten ste­hen­den XAML habe ich wie­der die Stan­dard­vor­la­ge für Win­dows Pho­ne Anwen­dun­gen ver­wen­det. Die ein­zi­gen Ände­run­gen gegen­über der Vor­la­ge sind der DatePi­cker, die List­Box und eini­ge Text­Blocks, wel­che ich nach dem Code­bei­spiel beschrei­ben wer­de. Bit­te beach­ten Sie auch die Zei­le xmlns:toolkit für den Sil­ver­light Tool­kit for Win­dows Pho­ne Name­space oben in der Sei­te. Wir brau­chen die­sen Name­space um den DatePi­cker ver­wen­den zu kön­nen.

<phone:PhoneApplicationPage 
   x:Class="Day9_CalendarAPI.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" 
    xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit" 
   mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768" 
   FontFamily="{StaticResource PhoneFontFamilyNormal}" 
   FontSize="{StaticResource PhoneFontSizeNormal}" 
   Foreground="{StaticResource PhoneForegroundBrush}" 
   SupportedOrientations="Portrait" Orientation="Portrait" 
   shell:SystemTray.IsVisible="True"> 

    <Grid x:Name="LayoutRoot" Background="Transparent"> 
        <Grid.RowDefinitions> 
            <RowDefinition Height="Auto"/> 
            <RowDefinition Height="*"/> 
        </Grid.RowDefinitions> 

        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> 
            <TextBlock x:Name="ApplicationTitle" Text="31 DAYS OF MANGO - DAY #9" Style="{StaticResource PhoneTextNormalStyle}"/> 
            <TextBlock x:Name="PageTitle" Text="calendar api" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> 
        </StackPanel> 

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> 
            <toolkit:DatePicker x:Name="DateBox" Height="100" Margin="0,37,0,470" ValueChanged="DateBox_ValueChanged" /> 
            <TextBlock Height="30" HorizontalAlignment="Left" Margin="12,6,0,0" Name="textBlock1" Text="select a date" VerticalAlignment="Top" Width="126" /> 
            <ListBox x:Name="DateList" Margin="0,143,0,0"> 
                <ListBox.ItemTemplate> 
                    <DataTemplate> 
                        <StackPanel> 
                            <TextBlock Text="{Binding StartTime}" FontSize="16" /> 
                            <TextBlock Text="{Binding Subject}" TextWrapping="NoWrap" FontWeight="Bold" FontSize="24" /> 
                            <TextBlock Text="{Binding Location}" TextWrapping="NoWrap" Margin="0,0,0,15" FontSize="20" Foreground="Gray"/> 
                        </StackPanel> 
                    </DataTemplate> 
                </ListBox.ItemTemplate> 
            </ListBox> 
            <TextBlock Height="30" HorizontalAlignment="Left" Margin="70,107,0,0" Name="MessageText" VerticalAlignment="Top" Width="380" TextAlignment="Right" /> 
        </Grid> 
    </Grid> 
</phone:PhoneApplicationPage>

Der DatePi­cker ist ein ziem­lich ein­fach zu benut­zen. Er ver­wen­det auto­ma­tisch das heu­ti­ge Datum wenn Sie keins ange­ben (was für unse­re Zwe­cke völ­lig aureicht). Wei­ter­hin hat er einen Event Value­Ch­an­ged, den wir nut­zen um bei Ände­rung des gewähl­ten Datums eine neue Kalen­der­su­che anzu­sto­ßen.

Die bei­den Text­Blocks sind eigent­lich nur Ver­zie­rung. Im zwei­ten Text­Block zei­gen wir an, wie­vie­le Ein­trä­ge wir gefun­den haben. Wir wer­den dazu kom­men, wenn wir in die code-behind Datei schau­en.

Schließ­lich haben wir noch die List­Box. Das heu­ti­ge Bei­spiel ist etwas aus­führ­li­cher als das gest­ri­ge, da wir einen etwas auf­wän­di­ge­rern DataTem­pla­te in der Lis­te ver­wen­den. Wir bin­den die­sen wie­der an Eigen­schaf­ten unse­rer Appoint­ment Objek­te, wel­che wir in unse­rem Code bekom­men. Hier ist eine klei­ne Vor­schau auf die Benut­zer­ober­flä­che.

Wie­der ein­mal habe ich auch ein klei­nes Video der lau­fen­den Anwen­dung auf mei­nem Gerät vor­be­rei­tet. Schau­en Sie sich das Video an, wenn Sie das End­ergeb­nis des heu­ti­gen Arti­kels sehen möch­ten!

Die Calendar API verwenden

Auch wenn unser Bei­spiel ziem­lich ein­fach ist, wer­den wir am Ende eine ziem­lich robus­te Anwen­dung für unse­ren Anwen­der erstellt haben. Als ers­tes machen wir den Name­space Microsoft.Phone.UserData per using State­ment bekannt. Wenn wir das haben, erstel­len wir ein neu­es Appoint­ment Objekt zum Zugriff auf die Kalen­der­da­ten unse­res Anwen­ders.

Hier ist unser ers­tes Code­bei­spiel:

using System; 
using System.Linq; 
using Microsoft.Phone.Controls; 
using Microsoft.Phone.UserData; 

namespace Day9_CalendarAPI 
{ 
   public partial class MainPage : PhoneApplicationPage 
   { 
      Appointments appointments = new Appointments(); 

      public MainPage() 
      { 
         InitializeComponent(); 
         appointments.SearchCompleted += new EventHandler<AppointmentsSearchEventArgs>(appointments_SearchCompleted); 
         appointments.SearchAsync(DateBox.Value.Value, DateBox.Value.Value.AddDays(1), null); 
      } 

      void appointments_SearchCompleted(object sender, AppointmentsSearchEventArgs e) 
      { 
         //SEARCH THE CALENDAR! 
      } 
   } 
} 

Wie Sie im obi­gen Bei­spiel sehen, erstel­len wir einen Search­Com­ple­ted Event Hand­ler und rufen dann Sear­chA­sync() auf, um unse­re Suche durch­zu­füh­ren. Die Metho­de Sear­chA­sync() erwar­tet drei Para­me­ter:

  • Start­Da­te — Ein DateTime Wert, wel­cher den Anfang unse­rer Suche reprä­sen­tiert. Die­ser Wert ist ein­schließ­lich, d.h. wenn Sie hier DateTime.Now ange­ben, wer­den Sie alle Ter­mi­ne ab inklu­si­ve heu­te bekom­men.
  • End­Da­te — Wie­der ein ein­schließ­li­cher Wert mit dem wir das Ende­da­tum der Suche ange­ben.
  • Sta­te — Ein benut­zer­de­fi­nier­tes Objekt, wel­ches wir der Suche über­ge­ben kön­nen. Es wird nach Abschluss der Suche dem Event Hand­ler mit­ge­ge­ben. Sie kön­nen die­ses Objekt nut­zen um eine ein­zel­ne Such­an­fra­ge spä­ter zu iden­ti­fi­zie­ren. Ein­fa­che Anwen­dun­gen wie unse­re heu­ti­ge über­ge­ben hier ein­fach null als Wert.

In unse­rem XAML oben haben wir einen DatePi­cker der Ober­flä­che hin­zu­ge­fügt. Sie wer­den im obi­gen Code­bei­spiel wahr­schein­lich den Code ver­misst haben, der die Aus­wahl des Anwen­ders berück­sich­tigt und die Such­ergeb­nis­se an die List­Box bin­det. Die­se zwei Schrit­te müs­sen wir noch erle­di­gen, damit die Anwen­dung so funk­tio­niert wie in dem Video oben.

Für den DatePi­cker estel­len wir eine Event Hand­ler Metho­de für den Value­Ch­an­ged Event, den wir im XAML schon regis­triert haben. Da wir die Metho­de Sear­chA­sync() mög­li­cher­wei­se von meh­re­ren Stel­len in unse­rem Code auf­ru­fen wer­den, las­sen wir unse­re Value­Ch­an­ged Event Hand­ler Metho­de eine neue Metho­de Search­Ca­len­dar() auf­ru­fen, in wel­cher wir den tat­säch­li­chen Auf­ruf Sear­chA­sync() durch­füh­ren (ich habe des­halb den Auf­ruf von Sear­chA­sync() aus dem Main­Page Kon­struk­tur ent­fernt).

using System; 
using System.Linq; 
using Microsoft.Phone.Controls; 
using Microsoft.Phone.UserData; 

namespace Day9_CalendarAPI 
{ 
   public partial class MainPage : PhoneApplicationPage 
   { 
      Appointments appointments = new Appointments(); 

      public MainPage() 
      { 
         InitializeComponent(); 
         appointments.SearchCompleted += new EventHandler<AppointmentsSearchEventArgs>(appointments_SearchCompleted); 
         SearchCalendar(); 
      } 

      private void SearchCalendar() 
      { 
         appointments.SearchAsync(DateBox.Value.Value, DateBox.Value.Value.AddDays(1), null); 
      } 

      private void DateBox_ValueChanged(object sender, DateTimeValueChangedEventArgs e) 
      { 
         SearchCalendar(); 
      } 

      void appointments_SearchCompleted(object sender, AppointmentsSearchEventArgs e) 
      { 
         if (e.Results.Count() == 0) 
         { 
            MessageText.Text = "no events for the selected day"; 
         } 
         else 
         { 
            MessageText.Text = e.Results.Count() + " events found"; 
            DateList.ItemsSource = e.Results; 
         } 
      } 
   } 
} 

Zum Schluss soll­ten Sie sich die Metho­de appointments_SearchCompleted() anse­hen. Die­se wird auf­ge­ru­fen, wenn die Ergeb­nis­se unse­res Sear­chA­sync() Auf­rufs vor­lie­gen. Die Ergeb­nis­se bekom­men wir als Para­me­ter mit­ge­lie­fert. In der Bei­spiel­an­wen­dung schaue ich nach, wie­vie­le Ein­trä­ge gefun­den wur­den und gebe das Ergeb­nis im Mess­a­ge­Text Text­Block aus. Zuletzt bin­de ich die Ergeb­nis­se der Suche an unse­re Date­List List­Box — vor­aus­ge­setzt, es wur­den Ein­trä­ge gefun­den.

Die Geheimnisse des Databindings

Für die­je­ni­gen unter Ihnen, die gera­de erst mit der XAML Ent­wick­lung begin­nen, mag die fol­gen­de Zei­le etwas geheim­nis­voll wir­ken:

DateList.ItemsSource = e.Results;

Es mag so wir­ken, als ob hier Zau­be­rei geschieht und in gewis­ser Wei­se stimmt das sogar. Wenn Sie sich noch an unser XAML erin­nern, sehen Sie ein rela­tiv aus­führ­li­ches List­Box Con­trol:

<ListBox x:Name="DateList" Margin="0,143,0,0"> 
    <ListBox.ItemTemplate> 
        <DataTemplate> 
            <StackPanel> 
                <TextBlock Text="{Binding StartTime}" FontSize="16" /> 
                <TextBlock Text="{Binding Subject}" TextWrapping="NoWrap" FontWeight="Bold" FontSize="24" /> 
                <TextBlock Text="{Binding Location}" TextWrapping="NoWrap" Margin="0,0,0,15" FontSize="20" Foreground="Gray"/> 
            </StackPanel> 
        </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

Im DataTem­pla­te für die List­Box habe ich drei Text­Block Con­trols defi­niert. Jeder die­ser Text­Blocks hat ein {Bin­ding} für den Wert sei­ner Text Eigen­schaft. Für uns als Ent­wick­ler bedeu­tet das, dass wir ein­zel­ne Eigen­schaf­ten unse­rer Daten­ob­jek­te neh­men und deren Wer­te an unse­re XAML Objek­te bin­den kön­nen.

Die­se Fähig­keit ist natür­lich nicht auf Text Wer­te beschränkt. Sie kön­nen bei­na­he jede Eigen­schaft eines XAML Ele­ments an Ihre Daten­ob­jek­te bin­den. Zah­len­wer­te kön­nen für die Opa­ci­ty Eigen­schaft, Far­ben für Fore­ground und Fill usw. ver­wen­det wer­den. Der ein­zi­ge ech­te Nach­teil des Data­bin­dings in XAML ist, dass Ihre Sei­te kaputt gehen wird, wenn Sie die Struk­tur Ihrer Daten­ob­jek­te ändern (stel­len Sie sich vor, sie ent­fer­nen Sub­ject aus der Appoint­ment Klas­se). Ins­ge­samt ist dies aber eine her­vor­ra­gen­de Mög­lich­keit, mit wenig Code eine Collec­tion von Objek­ten an eine List­Box zu bin­den.

Zusammenfassung

In die­sem Arti­kel haben wir Schritt für Schritt eine Anwen­dung ent­wi­ckelt, wel­che Daten aus dem Kalen­der des Anwen­ders aus­liest. Wie ein­gangs erwähnt, gibt es eine Viel­zahl von Anwen­dungs­fäl­len für die­se API — von der Arzt­pra­xis bis hin zu Syn­chro­ni­sie­rungs­werk­zeu­gen.

Um ein kom­plett lauf­fä­hi­ges Win­dows Pho­ne Pro­jekt mit dem gan­zen Bei­spiel­code her­un­ter­zu­la­den, kli­cken Sie auf den Down­load Code But­ton:

Mor­gen wer­den wir in den Name­space Net­work­In­for­ma­ti­on ein­tau­chen und ein Bei­spiel ent­wi­ckeln, wie und war­um man die­se Daten benutzt.

Bis dahin!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert