Just another side of me

My name is Veri, MSP from ITB. Enjoy my blog...
See also: Other Geeks@INDC
Reactive Extensions (Rx)

Hello readers, we meet again. In this blog post, I will help you in understanding Reactive Extensions (Rx).

Reactive Extensions (Rx)

According to MSDN Library, Reactive Extensions is a library for composing asynchronous and event-based programs using observable sequences and LINQ-style query operators.

Rx represents many data sequences, such as stream of data, web services requests, system notifications, or a series of user input, as observable sequences. If subscribed by an application, this observable sequences can push data to the application asynchronously as new data arrive.

The Rx library is available for desktop application development using .NET, and also available for Silverlight, Windows Phone 7, and JavaScript. The differences between all of them can be read in here.

Interactive V.S Reactive Programming

At this point, maybe you’ll ask me, what is interactive programming? And what is reactive programming? What’re the differences between them and how do they related to Rx?

In interactive programming, the application will try to “pull” the data from the data source to get more information. In code, it is represented by the IEnumerable<T>/IEnumerator<T> interface. The IEnumerable<T> interface have a GetEnumerator() method to iterate through the collection while the IEnumerator<T> interface have the MoveNext method to advances the enumerator to the next element of the collection if there is any.

In reactive programming, the application don’t have to “pull” the data from the data source. Instead, the data source will “push” the data to the application if there are more data to offer. This is what they call with Rx. This action can be done by subscribing to the IObservable<T>/IObserver<T> interface. The IObservable<T> interface is similar to IEnumerable<T> interface. It abstracts a sequence of data, and keeps a list of IObsever<T> implementations that are interested in the data sequence.

For more tutorial about Rx, you can visit this link.

That’s all for this post. See you soon in my next post and ciao…

Share this post: | | | |
BINER (Bakti Informatika untuk Negeri) @ SMPN 22 Bandung

A few weeks ago, I delivered a speech about Rich Internet Application at SMPN 22 Bandung as part of the BINER program hosted by HMIF (Himpunan Mahasiswa Informatika) ITB. There were only 10 students that attended the presentation but they were all really enthusiastic about this topic. I’m really happy to see these middle school students that love to learn something beyond their own school curriculum.

2011-05-23 15.01.492011-05-23 15.02.062011-05-23 15.03.042011-05-23 15.06.00

Share this post: | | | |
Bing Maps Locator Wizard by InKnowledge

Last week, InKnowledge just released the Bing Maps Locator Wizard, a tool that allows corporations and general public to get their location data on a Bing Maps map in minutes. The wizard walks users through the simple steps required to create and customize a locator application which can be downloaded, or even hosted by InKnowledge on the Windows Azure platform, and it’s completely FREE!!

Here is the preview video:

Share this post: | | | |
Bing Maps and OData (part 6)

Dear readers, first of all I wanted to say sorry because my last post about Bing Maps and OData wasn’t really my last post after all because I wanted to try something interesting. I wanted to port my NerdDinner silverlight application to Windows Phone. It’s not that hard actually. All you need to do is just a little bit of tuning because the map control in Windows Phone is a bit different with the Bing Maps Silverlight Control. And don’t forget the most important thing: you can’t add a service reference to OData service like you did in a Silverlight project. So, how can I get the data then? I’ll explain to you how.

Generating WCF Data Services class

Untuk bisa menggunakan OData service dari NerdDinner, kalian harus men-generate sendiri data service class-nya dengan cara menggunakan DataSvcUtil.exe. Untuk contoh penggunaannya bisa dilihat di sini. Jadi, kurang lebih yang akan kalian tuliskan di command prompt adalah seperti ini bila versi .NET Framework kalian adalah versi 4 “%windir%\Microsoft.NET\Framework\v4.0.3\DataSvcUtil.exe” /dataservicecollection /version:2.0 /language:CSharp /out:NerdDinner.cs /uri:http://www.nerddinner.com/Services/OData.svc/

Setelah selesai di generate, include file NerdDinner.cs hasil generate tadi ke dalam project Windows Phone Anda.

Untuk keseluruhan projectnya sendiri, tidak banyak berbeda dengan versi silverlight-nya tapi tentu saja tidak akan ada Child Window-nya. Versi Windows Phone ini hanya untuk melihat lokasi dinnernya saja, tidak seperti versi silverlight. Hasil akhirnya akan tampak seperti pada gambar berikut.

Result

The source code can be downloaded from here. Enjoy…

Share this post: | | | |
Bing Maps and OData (part 5)

This is the last post from a series that talked about Bing Maps and OData. I’ve told you how to retrieve and how to consume the OData in here, how to create the ViewModel that will be used for data binding in here, and how to create the Child Window in here. Finally, in this post I will show you how to make the main UX for the NerdDinner web application. Just copy and paste the code below to your MainPage.xaml.

   1: <UserControl x:Class="BingMapsOData.MainPage"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   5:     xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
   6:     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   7:     xmlns:local="clr-namespace:BingMapsOData"
   8:     xmlns:m="clr-namespace:Microsoft.Maps.MapControl;assembly=Microsoft.Maps.MapControl"
   9:     xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
  10:     mc:Ignorable="d"
  11:     d:DesignHeight="300" d:DesignWidth="400">
  12:     
  13:     <UserControl.Resources>
  14:         <DataTemplate x:Key="DinnerTemplate">
  15:             <m:Pushpin Name="DinnerPushpin" m:MapLayer.Position="{Binding Location}" Content="{Binding Attendees}">
  16:                 <i:Interaction.Triggers>
  17:                     <i:EventTrigger EventName="MouseLeftButtonDown">
  18:                         <local:ShowChildWindowAction ChildWindowType="BingMapsOData.DetailsChildWindow"/>
  19:                     </i:EventTrigger>
  20:                 </i:Interaction.Triggers>
  21:                 <ToolTipService.ToolTip>
  22:                     <StackPanel>
  23:                         <StackPanel Margin="2" Orientation="Horizontal">
  24:                             <Image Source="Images/dinner.png" Width="16" Height="16"/>
  25:                             <TextBlock Text="{Binding Title}" Padding="2" FontWeight="Bold" TextWrapping="Wrap"/>
  26:                         </StackPanel>
  27:                         <TextBlock Text="{Binding Date}" Padding="2" Margin="2" TextWrapping="Wrap"/>
  28:                         <TextBlock Text="{Binding Address}" Padding="2" Margin="2" TextWrapping="Wrap"/>
  29:                         <TextBlock Text="Click Pushpin for details" Foreground="Gray" Padding="2" Margin="2" TextWrapping="Wrap"/>
  30:                     </StackPanel>
  31:                 </ToolTipService.ToolTip>
  32:             </m:Pushpin>
  33:         </DataTemplate>
  34:     </UserControl.Resources>
  35:  
  36:     <Grid x:Name="LayoutRoot" Background="Black">
  37:         <Grid.RowDefinitions>
  38:             <RowDefinition Height="40"/>
  39:             <RowDefinition Height="37"/>
  40:             <RowDefinition Height="*"/>
  41:             <RowDefinition Height="20"/>
  42:         </Grid.RowDefinitions>
  43:         <Grid.ColumnDefinitions>
  44:             <ColumnDefinition />
  45:             <ColumnDefinition Width="Auto" />
  46:         </Grid.ColumnDefinitions>
  47:         
  48:         <m:Map x:Name="dinnerMap"
  49:                Grid.Row="0" Grid.RowSpan="3"
  50:                Grid.Column="0" Grid.ColumnSpan="2"
  51:                CacheMode="BitmapCache"
  52:                CredentialsProvider="{StaticResource MyCredentials}"
  53:                Mode="AerialWithLabels"
  54:                NavigationVisibility="Collapsed">
  55:             <m:MapItemsControl x:Name="dinnerList"
  56:                                ItemTemplate="{StaticResource DinnerTemplate}"
  57:                                ItemsSource="{Binding Dinners}">
  58:             </m:MapItemsControl>
  59:         </m:Map>
  60:  
  61:         <StackPanel Grid.Row="0" Grid.Column="0" Background="Black" Opacity="0.8">
  62:             <StackPanel Orientation="Horizontal">
  63:                 <TextBlock Text="Nerd Dinner Browser" FontSize="20" Padding="6" Foreground="White"/>
  64:                 <TextBlock Text="{Binding Status}" FontSize="14" Padding="12" Foreground="LightGray" Name="txtStatus" >
  65:                     <TextBlock.Triggers>
  66:                     </TextBlock.Triggers>
  67:                 </TextBlock>
  68:             </StackPanel>
  69:         </StackPanel>
  70:  
  71:         <StackPanel Grid.Row="1" Grid.Column="0">
  72:             <Border BorderThickness="1" BorderBrush="LightGray" Background="LightGray" CornerRadius="5" Padding="5" Margin="1">
  73:                 <StackPanel Orientation="Horizontal">
  74:                     <TextBlock Text="Dinners From " Padding="4"/>
  75:                     <controls:DatePicker SelectedDate="{Binding From, Mode=TwoWay}" Name="dtFrom" Width="130"/>
  76:                     <TextBlock Text=" To " Padding="4"/>
  77:                     <controls:DatePicker SelectedDate="{Binding To, Mode=TwoWay}" Name="dtTo" Width="130"/>
  78:                     <TextBlock Text=" Near " Padding="4"/>
  79:                     <TextBox Name="txtPlace" ToolTipService.ToolTip="Optional, Leave blank for a high level view" Width="130"/>
  80:                     <Button Name="SearchDinners" Click="SearchDinners_Click" Margin="1" Padding="3">
  81:                         <StackPanel Orientation="Horizontal" >
  82:                             <Image Source="Images/dinner.png" Width="16" Height="16"/>
  83:                             <TextBlock Text=" Grab The Dinners "/>
  84:                         </StackPanel>
  85:                     </Button>
  86:                     <TextBlock Width="6"/>
  87:                     <StackPanel Background="Gray" Width="2" Margin="2"/>
  88:                 </StackPanel>
  89:             </Border>
  90:         </StackPanel>
  91:  
  92:         <Canvas x:Name="cMiniMap" 
  93:                 Width="150" 
  94:                 Height="150" 
  95:                 HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Grid.Row="2" >
  96:             <m:Map x:Name="MiniMap" 
  97:                    CredentialsProvider="{StaticResource MyCredentials}"
  98:                    CacheMode="BitmapCache"
  99:                    Width="150" 
 100:                    Height="150" 
 101:                    Mode="Road" 
 102:                    NavigationVisibility="Collapsed" 
 103:                    ScaleVisibility="Collapsed" 
 104:                    LogoVisibility="Collapsed"
 105:                    CopyrightVisibility="Collapsed" Foreground="{x:Null}">
 106:                 <m:Map.Clip>
 107:                     <EllipseGeometry RadiusX="69" RadiusY="69" Center="75,75" />
 108:                 </m:Map.Clip>
 109:             </m:Map>
 110:             <Ellipse Width="150" Height="150" Stroke="#CC4C4C4C" StrokeThickness="6" Margin="0,0,0,0" CacheMode="BitmapCache" />
 111:             <Ellipse Height="10" Width="10" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="70,70,0,0" x:Name="ellipse" Fill="#CC205A5B" />
 112:         </Canvas>
 113:  
 114:         <Canvas x:Name="cNavControl" 
 115:                 Width="100" 
 116:                 HorizontalAlignment="Left" 
 117:                 VerticalAlignment="Top" Grid.Row="2" Margin="60,155,0,0" Grid.RowSpan="3" >
 118:             <StackPanel Width="50">
 119:                 <Ellipse x:Name="ePan" Fill="#CC4C4C4C" Height="50" Canvas.ZIndex="1" Width="50"/>
 120:                 <Path x:Name="pathMiniMap" Stretch="Fill" Stroke="#CCFFFFFF" Height="195" Margin="-50,-195,-50,0" UseLayoutRounding="False" Canvas.ZIndex="1" Data="M75,0.5 C116.14521,0.5 149.5,33.854782 149.5,75 C149.5,111.64496 123.04255,142.11044 88.187729,148.3364 L86.852966,148.55754 L87.70414,149.04695 C94.776031,153.34393 99.5,161.1203 99.5,170 C99.5,183.53098 88.530975,194.5 75,194.5 C61.469025,194.5 50.5,183.53098 50.5,170 C50.5,161.1203 55.223965,153.34393 62.29586,149.04695 L63.14703,148.55754 L61.812263,148.3364 C26.957447,142.11044 0.5,111.64496 0.5,75 C0.5,33.854782 33.854786,0.5 75,0.5 z"/>
 121:                 <Grid x:Name="gridPan" Height="50" Margin="0,-50,0,0" Width="50" Canvas.ZIndex="1">
 122:                     <Grid.RowDefinitions>
 123:                         <RowDefinition Height="12"/>
 124:                         <RowDefinition Height="26" />
 125:                         <RowDefinition Height="12"/>
 126:                     </Grid.RowDefinitions>
 127:                     <Grid.ColumnDefinitions>
 128:                         <ColumnDefinition Width="12" />
 129:                         <ColumnDefinition Width="26" />
 130:                         <ColumnDefinition Width="12"/>
 131:                     </Grid.ColumnDefinitions>
 132:  
 133:                     <Image Source="Images/PanUp.png" Stretch="Fill" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Top" Height="20" Margin="0,5,0,0" Width="34" MouseLeftButtonDown="PanMapUp"/>
 134:                     <Image Source="Images/PanLeft.png" Stretch="Fill" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Center" Width="20" Margin="5,0,0,0" Height="34" MouseLeftButtonDown="PanMapLeft"/>
 135:                     <Image Source="Images/PanRight.png" Stretch="Fill" Grid.Row="1" Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Center" Width="20" Margin="0,0,5,0" Height="34" MouseLeftButtonDown="PanMapRight"/>
 136:                     <Image Source="Images/PanDown.png" Stretch="Fill" Height="20" Margin="0,0,0,5" VerticalAlignment="Bottom" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Center" Width="34" MouseLeftButtonDown="PanMapDown"/>
 137:                 </Grid>
 138:                 <Border Margin="0,5,0,0" Width="15" Background="#CC4C4C4C" BorderThickness="1,1,1,0" BorderBrush="#CCFFFFFF" Height="15">
 139:                     <TextBlock Foreground="White" HorizontalAlignment="Center" Text="+" MouseLeftButtonDown="ZoomIn" VerticalAlignment="Center"/>
 140:                 </Border>
 141:                 <Border Height="160" HorizontalAlignment="Center" Margin="0" Width="15" RenderTransformOrigin="0.5,0.5" BorderThickness="1" Background="#CC4C4C4C" BorderBrush="#CCFFFFFF">
 142:                     <Slider x:Name="sldZoom" Orientation="Vertical" Maximum="21" Minimum="1" Height="150" Value="0" HorizontalAlignment="Center" Margin="0" SmallChange="1" BorderBrush="{x:Null}" BorderThickness="1" Width="15" Canvas.ZIndex="1" Foreground="{x:Null}" >
 143:                         <i:Interaction.Behaviors>
 144:                             <local:SnappingSlider/>
 145:                         </i:Interaction.Behaviors>
 146:                     </Slider>
 147:                 </Border>
 148:                 <Border Margin="0,0,0,5" Width="15" Background="#CC4C4C4C" BorderThickness="1,0,1,1" BorderBrush="#CCFFFFFF" Height="15">
 149:                     <TextBlock Foreground="White" HorizontalAlignment="Center" Text="-" MouseLeftButtonDown="ZoomOut" VerticalAlignment="Center"/>
 150:                 </Border>
 151:                 <Border Margin="0" Width="50" Background="#CC4C4C4C" BorderThickness="1" BorderBrush="#CCFFFFFF">
 152:                     <TextBlock Foreground="White" HorizontalAlignment="Center" Text="Road" MouseLeftButtonDown="MapStyleRoad" VerticalAlignment="Center"/>
 153:                 </Border>
 154:                 <Border Height="15" Margin="0" Width="50" Background="#CC4C4C4C" BorderThickness="1,0,1,1" BorderBrush="#CCFFFFFF">
 155:                     <TextBlock Foreground="White" HorizontalAlignment="Center" Text="Aerial" MouseLeftButtonDown="MapStyleAerial" VerticalAlignment="Center"/>
 156:                 </Border>
 157:                 <Border Height="15" Margin="0" Width="50" Background="#CC4C4C4C" BorderThickness="1,0,1,1" BorderBrush="#CCFFFFFF">
 158:                     <TextBlock Foreground="White" HorizontalAlignment="Center" Text="Hybrid" MouseLeftButtonDown="MapStyleHybrid" VerticalAlignment="Center"/>
 159:                 </Border>
 160:             </StackPanel>
 161:         </Canvas>
 162:  
 163:         <StackPanel Orientation="Horizontal" Grid.Row="3" HorizontalAlignment="Center">
 164:             <HyperlinkButton NavigateUri="http://students.netindonesia.net/blogs/veri" Content="My Blog" TargetName="_blank" FontFamily="Verdana" FontSize="12" Foreground="#FFFFFFFF"/>
 165:             <TextBlock Foreground="White" Text="|"></TextBlock>
 166:             <HyperlinkButton NavigateUri="http://twitter.com/vferdiansyah" Content="Twitter" TargetName="_blank" FontFamily="Verdana" FontSize="12" Foreground="#FFFFFFFF"/>
 167:             <TextBlock Foreground="White" Text="|"></TextBlock>
 168:             <HyperlinkButton NavigateUri="http://www.facebook.com/verif" Content="Facebook" TargetName="_blank" FontFamily="Verdana" FontSize="12" Foreground="#FFFFFFFF"/>
 169:             <TextBlock Foreground="White" Text="|"></TextBlock>
 170:             <HyperlinkButton NavigateUri="http://www.linkedin.com/pub/veri-ferdiansyah/21/a14/593" Content="Linked In" TargetName="_blank" FontFamily="Verdana" FontSize="12" Foreground="#FFFFFFFF"/>
 171:         </StackPanel>
 172:     </Grid>
 173: </UserControl>

After that, you also need to copy and paste the code below to your MainPage.xaml.cs.

   1: using System;
   2: using System.Windows;
   3: using System.Windows.Browser;
   4: using System.Windows.Controls;
   5: using System.Windows.Input;
   6: using BingMapsOData.Helpers;
   7: using BingMapsOData.ViewModels;
   8: using Microsoft.Maps.MapControl;
   9:  
  10: namespace BingMapsOData
  11: {
  12:     public partial class MainPage : UserControl
  13:     {
  14:         NerdDinnerViewModel vm;
  15:         MapSearchHelper searchHelper = new MapSearchHelper();
  16:         
  17:         public MainPage()
  18:         {
  19:             InitializeComponent();
  20:             InitializeViewModel();
  21:  
  22:             dinnerMap.TargetViewChanged += new EventHandler<MapEventArgs>(dinnerMap_TargetViewChanged);
  23:  
  24:             sldZoom.Value = dinnerMap.ZoomLevel;
  25:             sldZoom.ValueChanged += new RoutedPropertyChangedEventHandler<double>(ZoomChange);
  26:  
  27:             MiniMap.MouseClick += new EventHandler<MapMouseEventArgs>(MiniMap_MouseClick);
  28:             MiniMap.MouseDoubleClick += new EventHandler<MapMouseEventArgs>(MiniMap_MouseDoubleClick);
  29:             MiniMap.MouseDragBox += new EventHandler<MapMouseDragEventArgs>(MiniMap_MouseDragBox);
  30:             MiniMap.MousePan += new EventHandler<MapMouseDragEventArgs>(MiniMap_MousePan);
  31:             MiniMap.MouseWheel += new System.Windows.Input.MouseWheelEventHandler(MiniMap_MouseWheel);
  32:             MiniMap.KeyUp += new System.Windows.Input.KeyEventHandler(MiniMap_KeyUp);
  33:             MiniMap.KeyDown += new System.Windows.Input.KeyEventHandler(MiniMap_KeyDown);
  34:             MiniMap.KeyPress += new EventHandler<MapKeyPressEventArgs>(MiniMap_KeyPress);
  35:             MiniMap.KeyHeld += new EventHandler<MapKeyHeldEventArgs>(MiniMap_KeyHeld);
  36:             MiniMap.SetView(dinnerMap.TargetCenter, Math.Max(1.0, dinnerMap.TargetZoomLevel - 5));
  37:         }
  38:  
  39:         #region MainPage Events
  40:  
  41:         private void dinnerMap_TargetViewChanged(object sender, MapEventArgs e)
  42:         {
  43:             MiniMap.SetView(dinnerMap.TargetCenter, Math.Max(1.0, dinnerMap.TargetZoomLevel - 5));
  44:             sldZoom.Value = dinnerMap.TargetZoomLevel;
  45:         }
  46:  
  47:         #endregion
  48:  
  49:         #region MiniMap Events
  50:  
  51:         private void MiniMap_KeyHeld(object sender, MapKeyHeldEventArgs e)
  52:         {
  53:             e.Handled = true;
  54:         }
  55:  
  56:         private void MiniMap_KeyPress(object sender, MapKeyPressEventArgs e)
  57:         {
  58:             e.Handled = true;
  59:         }
  60:  
  61:         private void MiniMap_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
  62:         {
  63:             e.Handled = true;
  64:         }
  65:  
  66:         private void MiniMap_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
  67:         {
  68:             e.Handled = true;
  69:         }
  70:  
  71:         private void MiniMap_MouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
  72:         {
  73:             e.Handled = true;
  74:         }
  75:  
  76:         private void MiniMap_MousePan(object sender, MapMouseDragEventArgs e)
  77:         {
  78:             e.Handled = true;
  79:         }
  80:  
  81:         private void MiniMap_MouseDragBox(object sender, MapMouseDragEventArgs e)
  82:         {
  83:             e.Handled = true;
  84:         }
  85:  
  86:         private void MiniMap_MouseDoubleClick(object sender, MapMouseEventArgs e)
  87:         {
  88:             e.Handled = true;
  89:         }
  90:  
  91:         private void MiniMap_MouseClick(object sender, MapMouseEventArgs e)
  92:         {
  93:             e.Handled = true;
  94:         }
  95:  
  96:         #endregion
  97:  
  98:         #region Map Navigation
  99:  
 100:         private void ZoomChange(object sender, RoutedPropertyChangedEventArgs<double> e)
 101:         {
 102:             dinnerMap.ZoomLevel = sldZoom.Value;
 103:         }
 104:  
 105:         private void ZoomIn(object sender, MouseButtonEventArgs e)
 106:         {
 107:             dinnerMap.ZoomLevel = dinnerMap.TargetZoomLevel + 1;
 108:         }
 109:  
 110:         private void ZoomOut(object sender, MouseButtonEventArgs e)
 111:         {
 112:             dinnerMap.ZoomLevel = dinnerMap.TargetZoomLevel - 1;
 113:         }
 114:  
 115:         private void PanMapLeft(object sender, MouseButtonEventArgs e)
 116:         {
 117:             dinnerMap.Center = dinnerMap.ViewportPointToLocation(new Point(dinnerMap.ViewportSize.Width / 2 - 50, dinnerMap.ViewportSize.Height / 2));
 118:         }
 119:  
 120:         private void PanMapRight(object sender, MouseButtonEventArgs e)
 121:         {
 122:             dinnerMap.Center = dinnerMap.ViewportPointToLocation(new Point(dinnerMap.ViewportSize.Width / 2 + 50, dinnerMap.ViewportSize.Height / 2));
 123:         }
 124:  
 125:         private void PanMapUp(object sender, MouseButtonEventArgs e)
 126:         {
 127:             dinnerMap.Center = dinnerMap.ViewportPointToLocation(new Point(dinnerMap.ViewportSize.Width / 2, dinnerMap.ViewportSize.Height / 2 - 50));
 128:         }
 129:  
 130:         private void PanMapDown(object sender, MouseButtonEventArgs e)
 131:         {
 132:             dinnerMap.Center = dinnerMap.ViewportPointToLocation(new Point(dinnerMap.ViewportSize.Width / 2, dinnerMap.ViewportSize.Height / 2 + 50));
 133:         }
 134:  
 135:         private void MapStyleRoad(object sender, MouseButtonEventArgs e)
 136:         {
 137:             dinnerMap.Mode = new RoadMode();
 138:         }
 139:  
 140:         private void MapStyleAerial(object sender, MouseButtonEventArgs e)
 141:         {
 142:             dinnerMap.Mode = new AerialMode(false);
 143:         }
 144:  
 145:         private void MapStyleHybrid(object sender, MouseButtonEventArgs e)
 146:         {
 147:             dinnerMap.Mode = new AerialMode(true);
 148:         }
 149:  
 150:         #endregion
 151:  
 152:         /// <summary>
 153:         /// Initialize our view model, and assign it to the view
 154:         /// </summary>
 155:         private void InitializeViewModel()
 156:         {
 157:             vm = new NerdDinnerViewModel();
 158:             this.DataContext = vm;
 159:             try
 160:             {
 161:                 vm.QueryDinners();
 162:             }
 163:             catch (Exception ex)
 164:             {
 165:                 MessageBox.Show("Error loading the dinners. Make sure you are online. " + ex.Message);
 166:             }
 167:         }
 168:  
 169:         private void SearchDinners_Click(object sender, RoutedEventArgs e)
 170:         {
 171:             try
 172:             {
 173:                 if (!string.IsNullOrEmpty(txtPlace.Text))
 174:                     searchHelper.ExecuteSearch(txtPlace.Text, this.dinnerMap);
 175:             }
 176:             catch (Exception ex)
 177:             {
 178:                 MessageBox.Show("Error zooming in to " + txtPlace.Text + ex.Message);
 179:             }
 180:  
 181:             try
 182:             {
 183:                 vm.QueryDinners();
 184:             }
 185:             catch (Exception ex)
 186:             {
 187:                 MessageBox.Show("Error loading the dinners. Make sure you are online. " + ex.Message);
 188:             }
 189:         }
 190:     }
 191: }

Don’t forget to change the Bing Maps credentials in App.xaml with your own key. Hit F5 and your NerdDinner web application is ready to go!

Result

You can download the sample code in here. Enjoy…

Share this post: | | | |
Bing Maps and OData (part 4)

We meet again fellas. Postingan kali ini merupakan bagian keempat dari postingan saya tentang Bing Maps dan OData. Sebelumnya saya sudah menjelaskan tentang apa itu OData pada postingan pertama, lalu saya menjelaskan tentang pengambilan data dari OData pada postingan yang kedua, dan yang terakhir saya telah menjelaskan tentang MVVM dan MEF yang saya gunakan dalam aplikasi ini pada postingan yang ketiga. Nah, pada postingan yang keempat ini, kita akan mulai membuat behavior dan UI dari aplikasi. Ok, let’s get started…

1. Creating ChildWindow Behavior

Apa itu ChildWindow? ChildWindow merupakan sejenis pop-up window yang dapat kita munculkan untuk memberikan notifikasi kepada pengguna tentang sesuatu. Nah, ChildWindow ini akan saya gunakan untuk menampilkan detail dari Dinner yang kita pilih. Tambahkanlah sebuah class ke dalam project Anda dan beri nama sesuka Anda (dalam kasus saya, class ini saya beri nama ShowChildWindowAction.cs). Lalu, copy paste kode berikut ini ke dalam class tersebut.

   1: using System;
   2: using System.Windows;
   3: using System.Windows.Controls;
   4: using System.Windows.Interactivity;
   5:  
   6: namespace BingMapsOData
   7: {
   8:     [DefaultTrigger(typeof(UIElement), typeof(System.Windows.Interactivity.EventTrigger), new object[] { "MouseLeftButtonDown" })]
   9:     public class ShowChildWindowAction : TriggerAction<FrameworkElement>
  10:     {
  11:         public string ChildWindowType { get; set; }
  12:  
  13:         protected override void Invoke(object parameter)
  14:         {
  15:             ChildWindow window = Activator.CreateInstance(Type.GetType(ChildWindowType, false, true)) as ChildWindow;
  16:             if (window == null)
  17:             {
  18:                 return;
  19:             }
  20:             if (AssociatedObject != null)
  21:             {
  22:                 window.DataContext = AssociatedObject.DataContext;
  23:             }
  24:             window.Show();
  25:         }
  26:     }
  27: }

Kode tersebut digunakan untuk memunculkan Child Window apabila terjadi sebuah event yang men-trigger-nya yang dalam hal ini adalah event MouseLeftButtonDown yang nantinya behavior tersebut akan kita taruh didalam pushpin.

2. Creating Child Window

Selanjutnya, kita akan membuat Child Window. Child Window ini akan muncul apabila pengguna mengklik salah satu pushpin yang ada pada Bing Map. Child Window ini berisi detail dari Dinner pada sebuah lokasi tertentu, sesuai dengan lokasi pushpin yang diklik oleh pengguna. Tambahkan Child Window pada project Anda dengan cara mengklik kanan pada project dan pilih Add > New Item.. atau tekan Ctrl+Shift+A lalu pilih Silverlight Child Window. Pada kasus saya, Child Window ini saya beri nama DetailsChildWindow.xaml.

ChildWindow

Kemudian, copy paste kode berikut..

DetailsChildWindow.xaml

   1: <controls:ChildWindow x:Class="BingMapsOData.DetailsChildWindow"
   2:            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   3:            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
   4:            xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
   5:            Title="{Binding Title, Mode=OneWay}">
   6:     
   7:     <controls:ChildWindow.Resources>
   8:         <Style x:Key="ChildWindowStyle" TargetType="controls:ChildWindow">
   9:             <Setter Property="IsTabStop" Value="false"/>
  10:             <Setter Property="TabNavigation" Value="Cycle"/>
  11:             <Setter Property="HorizontalAlignment" Value="Center"/>
  12:             <Setter Property="VerticalAlignment" Value="Center"/>
  13:             <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
  14:             <Setter Property="VerticalContentAlignment" Value="Stretch"/>
  15:             <Setter Property="BorderThickness" Value="1"/>
  16:             <Setter Property="BorderBrush">
  17:                 <Setter.Value>
  18:                     <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
  19:                         <GradientStop Color="#FFA3AEB9" Offset="0"/>
  20:                         <GradientStop Color="#FF8399A9" Offset="0.375"/>
  21:                         <GradientStop Color="#FF718597" Offset="0.375"/>
  22:                         <GradientStop Color="#FF617584" Offset="1"/>
  23:                     </LinearGradientBrush>
  24:                 </Setter.Value>
  25:             </Setter>
  26:             <Setter Property="OverlayBrush" Value="#7F000000"/>
  27:             <Setter Property="OverlayOpacity" Value="1"/>
  28:             <Setter Property="Template">
  29:                 <Setter.Value>
  30:                     <ControlTemplate TargetType="controls:ChildWindow">
  31:                         <Grid x:Name="Root">
  32:                             <VisualStateManager.VisualStateGroups>
  33:                                 <VisualStateGroup x:Name="WindowStates">
  34:                                     <VisualState x:Name="Open">
  35:                                         <Storyboard>
  36:                                             <DoubleAnimationUsingKeyFrames BeginTime="0" Storyboard.TargetName="Overlay" Storyboard.TargetProperty="Opacity">
  37:                                                 <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
  38:                                                 <EasingDoubleKeyFrame KeyTime="00:00:00.3" Value="1"/>
  39:                                             </DoubleAnimationUsingKeyFrames>
  40:                                             <DoubleAnimationUsingKeyFrames BeginTime="0" Storyboard.TargetName="ContentRoot" Storyboard.TargetProperty="(RenderTransform).(Children)[0].ScaleX">
  41:                                                 <SplineDoubleKeyFrame KeyTime="0" Value="0"/>
  42:                                                 <SplineDoubleKeyFrame KeyTime="00:00:00.25" Value="0"/>
  43:                                                 <SplineDoubleKeyFrame KeyTime="00:00:00.4" Value="1"/>
  44:                                                 <SplineDoubleKeyFrame KeyTime="00:00:00.45" Value="1.05" KeySpline="0,0,0.5,1"/>
  45:                                                 <SplineDoubleKeyFrame KeyTime="00:00:00.55" Value="1"/>
  46:                                             </DoubleAnimationUsingKeyFrames>
  47:                                             <DoubleAnimationUsingKeyFrames BeginTime="0" Storyboard.TargetName="ContentRoot" Storyboard.TargetProperty="(RenderTransform).(Children)[0].ScaleY">
  48:                                                 <SplineDoubleKeyFrame KeyTime="0" Value="0"/>
  49:                                                 <SplineDoubleKeyFrame KeyTime="00:00:00.25" Value="0"/>
  50:                                                 <SplineDoubleKeyFrame KeyTime="00:00:00.4" Value="1"/>
  51:                                                 <SplineDoubleKeyFrame KeyTime="00:00:00.45" Value="1.05" KeySpline="0,0,0.5,1"/>
  52:                                                 <SplineDoubleKeyFrame KeyTime="00:00:00.55" Value="1"/>
  53:                                             </DoubleAnimationUsingKeyFrames>
  54:                                         </Storyboard>
  55:                                     </VisualState>
  56:                                     <VisualState x:Name="Closed">
  57:                                         <Storyboard>
  58:                                             <DoubleAnimationUsingKeyFrames BeginTime="0" Storyboard.TargetName="Overlay" Storyboard.TargetProperty="Opacity">
  59:                                                 <EasingDoubleKeyFrame KeyTime="0" Value="1"/>
  60:                                                 <EasingDoubleKeyFrame KeyTime="00:00:00.3" Value="0"/>
  61:                                             </DoubleAnimationUsingKeyFrames>
  62:                                             <DoubleAnimationUsingKeyFrames BeginTime="0" Storyboard.TargetName="ContentRoot" Storyboard.TargetProperty="(RenderTransform).(Children)[0].ScaleX">
  63:                                                 <SplineDoubleKeyFrame KeyTime="00:00:00.2" Value="1"/>
  64:                                                 <SplineDoubleKeyFrame KeyTime="00:00:00.25" Value="1.05"/>
  65:                                                 <SplineDoubleKeyFrame KeyTime="00:00:00.45" Value="0"/>
  66:                                             </DoubleAnimationUsingKeyFrames>
  67:                                             <DoubleAnimationUsingKeyFrames BeginTime="0" Storyboard.TargetName="ContentRoot" Storyboard.TargetProperty="(RenderTransform).(Children)[0].ScaleY">
  68:                                                 <SplineDoubleKeyFrame KeyTime="00:00:00.2" Value="1"/>
  69:                                                 <SplineDoubleKeyFrame KeyTime="00:00:00.25" Value="1.05"/>
  70:                                                 <SplineDoubleKeyFrame KeyTime="00:00:00.45" Value="0"/>
  71:                                             </DoubleAnimationUsingKeyFrames>
  72:                                         </Storyboard>
  73:                                     </VisualState>
  74:                                 </VisualStateGroup>
  75:                             </VisualStateManager.VisualStateGroups>
  76:                             <Grid x:Name="Overlay" HorizontalAlignment="Stretch" Margin="0" VerticalAlignment="Top" Opacity="{TemplateBinding OverlayOpacity}" Background="{TemplateBinding OverlayBrush}"/>
  77:                             <Grid x:Name="ContentRoot" Height="{TemplateBinding Height}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}" Width="{TemplateBinding Width}" RenderTransformOrigin="0.5,0.5">
  78:                                 <Grid.RenderTransform>
  79:                                     <TransformGroup>
  80:                                         <ScaleTransform/>
  81:                                         <SkewTransform/>
  82:                                         <RotateTransform/>
  83:                                         <TranslateTransform/>
  84:                                     </TransformGroup>
  85:                                 </Grid.RenderTransform>
  86:                                 <Border HorizontalAlignment="Stretch" Margin="-1" VerticalAlignment="Stretch" Background="#14000000" BorderBrush="#14000000" BorderThickness="1" CornerRadius="2"/>
  87:                                 <Border HorizontalAlignment="Stretch" Margin="-2" VerticalAlignment="Stretch" Background="#0F000000" BorderBrush="#0F000000" BorderThickness="1" CornerRadius="2.25"/>
  88:                                 <Border HorizontalAlignment="Stretch" Margin="-3" VerticalAlignment="Stretch" Background="#0C000000" BorderBrush="#0C000000" BorderThickness="1" CornerRadius="2.5"/>
  89:                                 <Border HorizontalAlignment="Stretch" Margin="-4" VerticalAlignment="Stretch" Background="#0A000000" BorderBrush="#0A000000" BorderThickness="1" CornerRadius="2.75"/>
  90:                                 <Border Background="#FFFFFFFF" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="2">
  91:                                     <Border Margin="1" CornerRadius="1.5">
  92:                                         <Border.Background>
  93:                                             <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
  94:                                                 <GradientStop Color="#FFE5E8EB" Offset="1"/>
  95:                                                 <GradientStop Color="#FFF6F8F9" Offset="0"/>
  96:                                             </LinearGradientBrush>
  97:                                         </Border.Background>
  98:                                         <Grid>
  99:                                             <Grid.RowDefinitions>
 100:                                                 <RowDefinition Height="Auto"/>
 101:                                                 <RowDefinition/>
 102:                                                 <RowDefinition Height="Auto"/>
 103:                                             </Grid.RowDefinitions>
 104:                                             <Border x:Name="Chrome" Width="Auto" BorderBrush="#FFFFFFFF" BorderThickness="0,0,0,1">
 105:                                                 <Border.Background>
 106:                                                     <LinearGradientBrush EndPoint="0.5,0.528" StartPoint="0.5,0">
 107:                                                         <GradientStop Color="#FFE5E8EB" Offset="1"/>
 108:                                                         <GradientStop Color="#FFFEFEFE" Offset="0"/>
 109:                                                     </LinearGradientBrush>
 110:                                                 </Border.Background>
 111:                                                 <Grid Height="Auto" Width="Auto">
 112:                                                     <Grid.ColumnDefinitions>
 113:                                                         <ColumnDefinition/>
 114:                                                         <ColumnDefinition Width="30"/>
 115:                                                     </Grid.ColumnDefinitions>
 116:                                                     <ContentControl HorizontalAlignment="Stretch" Margin="6" VerticalAlignment="Center" FontWeight="Bold" IsTabStop="False" Content="{TemplateBinding Title}"/>
 117:                                                 </Grid>
 118:                                             </Border>
 119:                                             <Border Margin="7" Grid.Row="1" Background="{TemplateBinding Background}">
 120:                                                 <ContentPresenter x:Name="ContentPresenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"/>
 121:                                             </Border>
 122:                                             <Button x:Name="CloseButton" HorizontalAlignment="Right" VerticalAlignment="Center" IsTabStop="False" Grid.Column="1" Grid.Row="2" Content="Close" Padding="8,2" Margin="8"/>
 123:                                         </Grid>
 124:                                     </Border>
 125:                                 </Border>
 126:                             </Grid>
 127:                         </Grid>
 128:                     </ControlTemplate>
 129:                 </Setter.Value>
 130:             </Setter>
 131:         </Style>
 132:     </controls:ChildWindow.Resources>
 133:  
 134:     <controls:ChildWindow.Style>
 135:         <StaticResource ResourceKey="ChildWindowStyle"/>
 136:     </controls:ChildWindow.Style>
 137:     
 138:     <StackPanel x:Name="LayoutRoot" Background="WhiteSmoke" Width="210">
 139:         <TextBlock Text="RSVP " FontWeight="Bold"  Foreground="Gray" Padding="2" Margin="2" TextWrapping="Wrap"/>
 140:         <StackPanel Orientation="Horizontal">
 141:             <Button Margin="2" Padding="4" Name="btnTwitter" Click="btnTwitter_Click">
 142:                 <Image Source="Images/twitter.png" Width="16" Height="16"/>
 143:             </Button >
 144:             <Button Margin="2" Padding="4" Name="btnGoogle" Click="btnGoogle_Click">
 145:                 <Image Source="Images/google.png" Width="16" Height="16"/>
 146:             </Button>
 147:             <Button Margin="2" Padding="4" Name="btnYahoo" Click="btnYahoo_Click">
 148:                 <Image Source="Images/yahoo.png" Width="16" Height="16"/>
 149:             </Button>
 150:         </StackPanel>
 151:         <TextBlock Text="When? " FontWeight="Bold"  Foreground="Gray" Padding="2" Margin="2" TextWrapping="Wrap"/>
 152:         <TextBlock Text="{Binding Date}" Padding="2" Margin="2" TextWrapping="Wrap"/>
 153:         <TextBlock Text="Where? " FontWeight="Bold"  Foreground="Gray" Padding="2" Margin="2" TextWrapping="Wrap"/>
 154:         <TextBlock Text="{Binding Address}" Padding="2" Margin="2" TextWrapping="Wrap"/>
 155:         <TextBlock Text="Description " FontWeight="Bold"  Foreground="Gray" Padding="2" Margin="2" TextWrapping="Wrap"/>
 156:         <TextBlock Text="{Binding Description}" Padding="2" Margin="2" TextWrapping="Wrap"/>
 157:         <TextBlock Text="Hosted By: " FontWeight="Bold" Foreground="Gray" Padding="2" Margin="2" TextWrapping="Wrap"/>
 158:         <TextBlock Text="{Binding HostedBy}" Padding="2" Margin="2" TextWrapping="Wrap"/>
 159:         <TextBlock Text="Phone: " FontWeight="Bold"  Foreground="Gray" Padding="2" Margin="2" TextWrapping="Wrap"/>
 160:         <TextBlock Text="{Binding Phone}" Padding="2" Margin="2" TextWrapping="Wrap"/>
 161:         <TextBlock Text="Attendees: " FontWeight="Bold"  Foreground="Gray" Padding="2" Margin="2" TextWrapping="Wrap"/>
 162:         <TextBlock Text="{Binding Attendees}" Padding="2" Margin="2" TextWrapping="Wrap"/>
 163:     </StackPanel>
 164: </controls:ChildWindow>

DetailsChildWindow.xaml.cs

   1: using System;
   2: using System.Windows;
   3: using System.Windows.Browser;
   4: using System.Windows.Controls;
   5: using BingMapsOData.ViewModels;
   6:  
   7: namespace BingMapsOData
   8: {
   9:     public partial class DetailsChildWindow : ChildWindow
  10:     {
  11:         public DetailsChildWindow()
  12:         {
  13:             InitializeComponent();
  14:         }
  15:  
  16:         private void btnTwitter_Click(object sender, RoutedEventArgs e)
  17:         {
  18:             var d = this.DataContext as DinnerViewModel;
  19:             HtmlPage.Window.Navigate(new Uri("http://nerddinner.com/RSVP/RsvpTwitterBegin/" + d.DinnerId), "_blank");
  20:         }
  21:  
  22:         private void btnGoogle_Click(object sender, RoutedEventArgs e)
  23:         {
  24:             var d = this.DataContext as DinnerViewModel;
  25:             HtmlPage.Window.Navigate(new Uri("http://nerddinner.com/RSVP/RsvpBegin/" + d.DinnerId + "?identifier=https%3A%2F%2Fwww.google.com%2Faccounts%2Fo8%2Fid"), "_blank");
  26:         }
  27:  
  28:         private void btnYahoo_Click(object sender, RoutedEventArgs e)
  29:         {
  30:             var d = this.DataContext as DinnerViewModel;
  31:             HtmlPage.Window.Navigate(new Uri("http://nerddinner.com/RSVP/RsvpBegin/" + d.DinnerId + "?identifier=https%3A%2F%2Fme.yahoo.com%2F"), "_blank");
  32:         }
  33:     }
  34: }
  35:  

Oke, cukup sekian dulu nih. Masih ada pembahasan selanjutnya loh. Jadi, stay tuned ya..

Share this post: | | | |
Bing Maps and OData (part 3)

Pada postingan pertama saya tentang Bing Maps dan OData, saya sudah menjelaskan secara garis besar tentang apa itu OData. Pada postingan yang kedua, saya sudah menjelaskan bagaimana membuat sebuah service untuk mengkonsumsi data dari OData. Nah, pada postingan saya yang ketiga ini, saya akan menjelaskan tentang pembuatan ViewModel dan MEF (Managed Extensibility Framework) yang saya gunakan dalam aplikasi ini.

Model-View-ViewModel Design Pattern

Model-View-ViewModel merupakan sebuah pola arsitektur yang digunakan dalam software engineering yang dibuat oleh Microsoft. Model MVVM ini sebenarnya berasal dari model MVC (Model-View-Controller), dimana MVVM lebih ditujukan untuk UI development platform yang modern seperti WPF (Windows Presentation Foundation) dan Silverlight.

MVVM_Relation

Bahasa gampangnya, MVVM ini digunakan untuk memfasilitasi para programmer dalam membangun logic dari sebuah aplikasi dan para designer dalam membuat UX agar mereka dapat bebas berkreasi tanpa harus saling bergantung antar satu sama lainnya.

WLW-TheRevolutionHasBegun_10247-image_2

Pada aplikasi ini, saya memiliki sebuah Model yaitu DinnerViewModel.cs dan sebuah ViewModel yaitu NerdDinnerViewModel.cs. Dalam DinnerViewModel.cs, terdapat objek-objek dari elemen Dinner seperti Title, Location, Address, dll. Sedangkan di dalam NerdDinnerViewModel.cs terdapat fungsi LINQ untuk mengquery Dinner yang didapatkan dengan memanfaatkan service yang telah kita buat pada postingan saya sebelumnya.

Secara keseluruhan, DinnerViewModel.cs akan berisi kode-kode seperti berikut.

   1: using System;
   2: using BingMapsOData.NerdDinnerClient;
   3: using Microsoft.Maps.MapControl;
   4:  
   5: namespace BingMapsOData.ViewModels
   6: {
   7:     public class DinnerViewModel
   8:     {
   9:         public Location Location { get; set; }
  10:         public string Title { get; set; }
  11:         public string Description { get; set; }
  12:         public DateTime Date { get; set; }
  13:         public string Address { get; set; }
  14:         public string HostedBy { get; set; }
  15:         public int Attendees { get; set; }
  16:         public string Phone { get; set; }
  17:         public int DinnerId { get; set; }
  18:  
  19:         public DinnerViewModel(Dinner d)
  20:         {
  21:             Title = d.Title;
  22:             Location = new Location() { Latitude = d.Latitude, Longitude = d.Longitude };
  23:             Address = d.Address;
  24:             HostedBy = d.HostedBy;
  25:             Attendees = d.RSVPs.Count;
  26:             Description = d.Description;
  27:             Date = d.EventDate;
  28:             Phone = d.ContactPhone;
  29:             DinnerId = d.DinnerID;
  30:         }
  31:     }
  32: }

Sedangkan dalam NerdDinnerViewModel.cs akan berisi kode-kode berikut.

   1: using System;
   2: using System.Collections.Generic;
   3: using System.ComponentModel.Composition;
   4: using System.Linq;
   5: using BingMapsOData.NerdDinnerClient;
   6: using BingMapsOData.Services.Data;
   7:  
   8: namespace BingMapsOData.ViewModels
   9: {
  10:     /// <summary>
  11:     /// View model for the nerd dinner
  12:     /// </summary>
  13:     public class NerdDinnerViewModel : ViewModelBase
  14:     {
  15:         #region Methods
  16:  
  17:         /// <summary>
  18:         /// Set the default values
  19:         /// </summary>
  20:         private void InitializeDefaults()
  21:         {
  22:             From = DateTime.Now.Subtract(new TimeSpan(12, 0, 0));
  23:             To = DateTime.Now.AddMonths(1);
  24:             OnPropertyChanged("From");
  25:             OnPropertyChanged("To");
  26:         }
  27:  
  28:         /// <summary>
  29:         /// Ctor
  30:         /// </summary>
  31:         public NerdDinnerViewModel()
  32:         {
  33:             CompositionInitializer.SatisfyImports(this);
  34:             InitializeDefaults();
  35:  
  36:             Service.DinnersChanged += (dinners) =>
  37:             {
  38:                 _dinners = dinners;
  39:                 Status = " | " + dinners.Count() + " Dinners from " + From.ToLongDateString() + " To " + To.ToLongDateString();
  40:                 OnPropertyChanged("Dinners");
  41:             };
  42:         }
  43:  
  44:         /// <summary>
  45:         /// Execute the service query to return the dinners
  46:         /// </summary>
  47:         public void QueryDinners()
  48:         {
  49:             Service.QueryDinners(From, To);
  50:             Status = " | Loading Dinners, Have a cup of tea..";
  51:         }
  52:  
  53:         #endregion
  54:  
  55:         #region Bindable Properties
  56:  
  57:         private IEnumerable<Dinner> _dinners = new List<Dinner>();
  58:  
  59:         private string _status = string.Empty;
  60:         public string Status
  61:         {
  62:             get
  63:             {
  64:                 return _status;
  65:             }
  66:             set
  67:             {
  68:                 _status = value;
  69:                 OnPropertyChanged("Status");
  70:             }
  71:         }
  72:  
  73:         public IEnumerable<DinnerViewModel> Dinners
  74:         {
  75:             get
  76:             {
  77:                 var items = from d in _dinners
  78:                             select new DinnerViewModel(d);
  79:                 return items;
  80:             }
  81:         }
  82:  
  83:         public DateTime From { get; set; }
  84:         public DateTime To { get; set; }
  85:  
  86:         #endregion
  87:  
  88:         #region Imported Services
  89:  
  90:         [Import(typeof(INerdDinnerService))]
  91:         public INerdDinnerService Service { get; set; }
  92:  
  93:         #endregion
  94:     }
  95: }

Mungkin sekarang timbul pertanyaan. Pada part 2, terdapat [Export(typeof(INerdDinnerService))] lalu pada postingan kali ini terdapat [Import(typeof(INerdDinnerService))]. Sebenarnya itu buat apaan sih? Oke, sekarang juga akan saya jelaskan.

Managed Extensibility Framework

Managed Extensibility Framework atau MEF merupakan sebuah library untuk membuat sebuah aplikasi yang ringan dan extensible. MEF memungkinkan para developer untuk membuat extension-extension dari aplikasi tanpa konfigurasi apapun. Selain itu, dengan menggunakan MEF, extension-extension tersebut tidak hanya bisa di re-use dalam sebuah aplikasi tetapi juga dapat digunakan dalam aplikasi lain. MEF ini sudah include di dalam .NET Framework 4 dan Silverlight 4.

MEF_Diagram

Untuk lebih jelasnya tentang pemrograman menggunakan MEF, bisa dilihat disini.

Oke, kayaknya cukup sampai sini dulu deh. Silakan di pelajari sedikit demi sedikit. Tunggu pembahasan selanjutnya ya…

Share this post: | | | |
Bing Maps and OData (Part 2)

Pada postingan saya sebelumnya, saya sudah sedikit menjelaskan tentang apa itu OData. Nah, pada postingan ini dan seterusnya, saya akan menjelaskan tentang cara membuat sebuah aplikasi Bing Maps sederhana yang memanfaatkan OData. Sebelum melanjutkan, kalian harus memiliki beberapa tools berikut:

Setelah kalian sudah menginstal semua tools tersebut, sekarang saatnya kita mulai membuat aplikasinya.

1. Buat sebuah aplikasi Silverlight baru.

Buat sebuah aplikasi Silverlight baru pada Visual Studio dan tambahkan reference-reference seperti pada gambar berikut.

References

2. Mengkonsumsi OData di Silverlight

Untuk mengkonsumsi OData di Silverlight, kalian cukup menambahkan service reference ke service OData. Caranya, klik kanan pada Silverlight project kalian dan pilih Add Service Reference. Tambahkan service reference ke endpoint OData Nerd Dinner.

OData Service

3. Mengambil Data

Langkah selanjutnya adalah mengambil data dari OData endpoint. Buatlah sebuah interface bernama INerdDinnerService.cs dan sebuah kelas NerdDinnerService.cs yang mengimplementasi interface tersebut. Di dalam kelas NerdDinnerService.cs, kita akan membuat sebuah menambahkan filter untuk mengquery data diantara dua buah tanggal.

Apakah hal tersebut bisa dilakukan? Bisa, karena OData mendukung berbagai URI convention dan bentuk-bentuk query. Sebagai contoh, misalnya kita ingin mengambil 5 dinner teratas, kita bisa menambahkan $top=5 pada URI sehingga bentuk URI-nya akan menjadi seperti ini http://nerddinner.com/Services/OData.svc/Dinners?$top=5.

Pada kasus kali ini, saya akan meminta data dinner yang berada pada range tanggal tertentu. Berdasarkan URI convention dari OData, maka bentuk query yang akan kita buat kurang lebih berbentuk seperti ini http://nerddinner.com/Services/OData.svc/Dinners?$filter=EventDate%20le%20datetime'2011-04-01T09:00:00'%20and%20EventDate%20gt%20datetime'2011-03-01T09:00:00'

Interface INerdDinnerService.cs akan berisi kode berikut:

   1: using System;
   2: using System.Collections.Generic;
   3: using BingMapsOData.NerdDinnerClient;
   4:  
   5: namespace BingMapsOData.Services.Data
   6: {
   7:     /// <summary>
   8:     /// INerdDinnerService interface
   9:     /// </summary>
  10:     public interface INerdDinnerService
  11:     {
  12:         void QueryDinners(DateTime from, DateTime to);
  13:         event Action<IEnumerable<Dinner>> DinnersChanged;
  14:     }
  15: }

Sedangkan untuk kelas NerdDinnerService.cs-nya akan berbentuk seperti ini:

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Collections.ObjectModel;
   4: using System.ComponentModel.Composition;
   5: using System.Data.Services.Client;
   6: using System.Windows;
   7: using BingMapsOData.NerdDinnerClient;
   8:  
   9: namespace BingMapsOData.Services.Data
  10: {
  11:     [Export(typeof(INerdDinnerService))]
  12:     public class NerdDinnerService : INerdDinnerService
  13:     {
  14:         ObservableCollection<Dinner> _dinners;
  15:  
  16:         /// <summary>
  17:         /// Query the dinners in nerd dinner database
  18:         /// </summary>
  19:         public void QueryDinners(DateTime from, DateTime to)
  20:         {
  21:             // Create a new data service context.
  22:             var context = new NerdDinnerEntities
  23:               (new Uri("http://nerddinner.com/Services/OData.svc/", UriKind.Absolute));
  24:  
  25:             // Creates the query. Dirty strings for now
  26:             string exp = "EventDate le " + GetODataFormat(to) + " and EventDate gt " + GetODataFormat(from);
  27:  
  28:             //Add a filtering option
  29:             DataServiceQuery<Dinner> query = context.Dinners.AddQueryOption("$filter", exp).Expand("RSVPs");
  30:  
  31:             try
  32:             {
  33:                 // Begin the query execution.
  34:                 query.BeginExecute(OnDinnerQueryComplete, query);
  35:             }
  36:             catch (Exception ex)
  37:             {
  38:                 MessageBox.Show(ex.Message);
  39:             }
  40:         }
  41:  
  42:         /// <summary>
  43:         /// Gets the oDataFormat
  44:         /// </summary>
  45:         public string GetODataFormat(DateTime dt)
  46:         {
  47:             return "datetime'" + dt.ToString("yyyy-MM-ddThh:mm:ss") + "'";
  48:         }
  49:  
  50:         /// <summary>
  51:         /// Will be invoked upon completion of the query
  52:         /// </summary>
  53:         /// <param name="result"></param>
  54:         private void OnDinnerQueryComplete(IAsyncResult result)
  55:         {
  56:             // Get the original query back from the result.
  57:             DataServiceQuery<Dinner> query = result.AsyncState as DataServiceQuery<Dinner>;
  58:  
  59:             try
  60:             {
  61:                 _dinners = new DataServiceCollection<Dinner>(query.EndExecute(result));
  62:                 if (DinnersChanged != null)
  63:                     DinnersChanged(_dinners);
  64:             }
  65:             catch (DataServiceQueryException ex)
  66:             {
  67:                 MessageBox.Show(ex.Message);
  68:             }
  69:         }
  70:  
  71:         /// <summary>
  72:         /// Event to raise when dinners changed
  73:         /// </summary>
  74:         public event Action<IEnumerable<Dinner>> DinnersChanged;
  75:     }
  76: }

Fungsi dari QueryDinners adalah untuk memfilter dinner yang berada dalam selang waktu tertentu. Saat kita melakukan BeginExecute, kita melempar callback OnDinnerQueryComplete agar nantinya callback ini dipanggil setelah eksekusi query selesai. Di dalam OnDinnerQueryComplete ini kita memanggil EndExecute untuk menampilkan hasil dari query. Selain itu, kita juga memanggil event DinnersChanged untuk memberikan notifikasi pada ViewModel kita.

Mudah bukan?

Untuk postingan kali ini mungkin cukup sampai disini dulu. Sampai jumpa di postingan saya selanjutnya…

Share this post: | | | |
Bing Maps and OData (Part 1)

Setelah lama gak eksplorasi teknologi karena berbagai kesibukan seperti mengurus acara Arkavidia 2.0 dan terutama adalah Tugas Akhir atau yang biasa disebut sebagai skripsi, akhirnya ada sedikit waktu untuk eksplorasi juga. Pada postingan yang akan terdiri dari beberapa bagian kali ini, saya akan menjelaskan tentang OData dan integrasi OData pada Bing Maps.

Open Data Protocol

Open Data Protocol, atau yang biasa disebut dengan OData, merupakan sebuah web protocol untuk melakukan query dan update data yang menyajikan sebuah cara baru untuk meng-unlock data dan membersihkannya dari “silo” yang biasa terdapat dalam aplikasi-aplikasi saat ini. OData dibuat berdasarkan teknologi web seperti HTTP, Atom Publishing Protocol (AtomPub), dan JSON untuk menyediakan akses terhadap informasi dari berbagai sumber seperti basis data relasional, file system, content management system, dan website-website tradisional.

WCF Data Services

WCF Data Services (sebelumnya bernama ADO.NET Data Services atau Astoria), merupakan teknologi Microsoft pertama yang mendukung OData di Visual Studio 2008 SP1. Saat ini, Microsoft juga mendukung OData di SQL Server 2008 R2, Windows Azure Storage, Excel 2010 (melalui PowerPivot), dan SharePoint 2010.

aa937697_DS_AtAGlance_2a(en-us,MSDN_10)

Oke, sekarang kita sudah mengetahui sekilas tentang apa itu OData dan WCF Data Services. Pada postingan selanjutnya, saya akan menjelaskan tentang membuat aplikasi Bing Maps yang mengkonsumsi data dari OData. Ciao for now…

Share this post: | | | |
Arkavidia 2.0

Arkavidia 2.0 merupakan sebuah acara besar di bidang IT hasil karya Himpunan Mahasiswa Informatika ITB. Acara tersebut akan berlangsung pada tanggal 19-20 Februari 2011 dan bertempat di dalam kampus ITB. Acara Arkavidia 2.0 ini terdiri dari beberapa acara kecil antara lain:

  • Lomba
  • Seminar
  • Expo
  • Career Day
  • Gerakan Seribu Jari

Di lomba, kita bisa belajar berkompetisi. Di seminar, kita bisa dapet ilmu mengenai IT untuk masa sekarang dan yang akan datang. Di expo, kita bisa liat karya-karya mahasiswa terutama mahasiswa IF ITB. Di career day, kita bisa mencari info tentang pekerjaan di perusahaan-perusahaan bonafit. Di gerakan seribu jari, kita bisa beramal untuk sesama.

Selain itu, bakal ada juga performance dari band-band terkenal loh! Salah satunya adalah Mocca. So, buat kalian para penggemar Mocca, pasti rugi banget deh klo gak dateng…

So, jangan lupa dateng ya ke acara Arkavidia 2.0 ini kawan-kawan.

171532_1826644794182_1482175738_1996880_7661617_o

Share this post: | | | |
News Reader for Windows Phone

Dear all, recently I have made a news reader application for Windows Phone. With this application, you can read news from Detik, Kompas Cybermedia, Okezone, and Metrotv News. You also can list some news as your favorite and if you don’t want to waste your time searching a whole list for news that you want to read, just type some word in the search box and the application will do the rest. Below is the screencast for this application. Enjoy…

News Reader for Windows Phone
Share this post: | | | |
Windows Phone 7 Map and Pivot Control

Pada 2 postingan sebelumnya, yang dapat dilihat disini dan disini, saya telah menjelaskan tentang Map control pada Windows Phone 7. Nah, pada postingan kali ini, saya masih akan membahas tentang Map control pada Windows Phone 7 namun dalam aplikasi yang menggunakan Pivot control.

Pivot Control

Pivot Control merupakan sebuah control pada Windows Phone yang mempercepat pengaturan view atau halaman. Control ini bisa digunakan untuk memfilter dataset yang besar, menampilkan banyak dataset, atau berpindah-pindah antar view dalam satu aplikasi.

Dasar dari sebuah aplikasi berbasis Pivot adalah sebuah Pivot control yang merupakan container untuk secondary control yang disebut PivotItem. PivotItem ini mengandung konten-konten seperti grid, link, atau dalam kasus ini sebuah map dalam tiap halamannya.

IC425811

Pivot Control Navigation

Untuk menavigasikan Pivot control ini, kalian tidak perlu mengimplementasikan special gesture apapun pada aplikasi kalian karena Pivot control ini, by default, sudah dibekali dengan built-in touch interaction. Touch interaction yang didukung oleh control ini antara lain:

  • Horizontal pan
  • Horizontal flick
  • Navigating hosted controls

Problem

Permasalahan utama dalam menempatkan sebuah control yang mensupport flick interaction seperti Map pada Pivot adalah bila Anda melakukan flick pada Map searah dengan Pivot, maka tampilan pada layar akan berpindah ke halaman sebelum/setelahnya tergantung dari arah flick Anda.

Cobalah buat sebuah aplikasi Pivot pada Visual Studio 2010, dan masukkan Map control ke dalam halaman pertama. Jalankan aplikasi Anda dan cobalah untuk menavigasikan Map-nya. Anda akan menemukan dua buah bug yaitu:

  • Saat menavigasikan Map, aplikasi Anda akan crash
  • Saat Anda melakukan fast flick pada Map, maka halaman pada layar akan berpindah

Solution

Solusi untuk menyelesaikan permasalahan tersebut adalah dengan menggunakan fungsi IsHitTestVisible yang merupakan sebuah fungsi boolean dari WPF yang dapat meng-enable atau men-disable nilai true yang muncul bila touch event terjadi pada sebuah komponen. Jadi, bila Anda menset properti IsHitTestVisible pada sebuah Pivot menjadi false saat terdapat event MouseLeftButtonDown pada Map, maka Anda dapat menavigasikan Map dengan bebas tanpa perlu khawatir akan berpindah halaman.

Aplikasi ini bisa Anda download disini. Enjoy…

Share this post: | | | |
Bing Maps and Facebook API

Kalian semua pasti tau apa itu Facebook kan? Kayaknya gak mungkin deh anak muda Indonesia zaman sekarang gak punya account Facebook atau malah gak tau apa itu Facebook. Buat yang belum tau, Facebook itu adalah sebuah situs social networking seperti Friendster yang dibuat oleh Mark Zuckerberg, seorang mahasiswa yang di DO dari Harvard. Hebat ya mahasiswa DO Harvard bisa bikin Facebook dan sekarang jadi salah satu multi-millionaire termuda di dunia dan baru-baru ini, dia terpilih sebagai “People of the Year” versi majalah Times.

Nah, kalian yang sering buka Facebook pasti pernah menggunakan salah satu aplikasi yang menanyakan kepada kalian apakah kalian setuju untuk memberikan izin kepada aplikasi tersebut untuk mengakses data-data pribadi kalian seperti yang terlihat pada gambar berikut.

api_facebook14

Atau seperti pada gambar berikut.

n20531316728_1757356_1276

Sebenarnya itu apa sih? Bagi kalian yang belum tau, kedua gambar diatas merupakan contoh-contoh aplikasi yang menggunakan Facebook Connect, sebuah metode autentikasi untuk mengakses data-data user yang ada pada Facebook. Jadi, dengan memberikan izin kepada sebuah aplikasi untuk mengakses profil Anda, berarti Anda telah memberikan izin kepada aplikasi tersebut untuk melihat data-data pribadi Anda. Oleh karena itu, berhati-hatilah terhadap aplikasi-aplikasi “nakal” yang bisa menyalahgunakan informasi yang Anda berikan.

Karena sedang liburan, saya membuat sebuah aplikasi map sederhana yang memanfaatkan Facebook API untuk mengakses data pribadi Anda seperti nama lengkap, about me dan current location yang Anda tulis pada profil Facebook Anda. Setelah Anda melakukan login dan menyetujui bahwa aplikasi ini akan mengakses data pribadi Anda, maka pada map akan muncul sebuah pushpin yang terletak di kota tempat ada berada sekarang (menurut profil Facebook) yang memiliki tooltip berupa nama lengkap dan about me pada profil Facebook Anda yang akan muncul apabila Anda melakukan aksi Mouse Over pada pushpin tersebut.

Untitled

Aplikasi ini bisa Anda coba sendiri dengan mengunduhnya disini. Sebelumnya saya ingin memberitahukan bahwa aplikasi ini hanya mengakses nama lengkap, lokasi, dan about me pada profil Facebook Anda. Selain itu, saya juga tidak akan menyalahgunakan data-data tersebut karena aplikasi ini hanya saya buat untuk sekedar mengisi waktu luang dan berbagi ilmu saja.

Bagi yang penasaran, Anda cukup membuka solutionnya di Visual Studio 2010 dan menekan F5 untuk menjalankan aplikasinya. Lalu login, dan berikan izin kepada aplikasi untuk mengakses data pribadi Anda. Enjoy…

Share this post: | | | |
Road to Imagine Cup 2011: Proposal Making Sharing Session

Pada hari Jum’at tanggal 17 Desember 2010, MSP ITB bekerja sama dengan Puja Pramudya selaku perwakilan dari tim Ganesh, melakukan sharing kepada para peserta Imagine Cup 2011 dari ITB tentang cara pembuatan proposal. Puja memberikan penjelasan kepada para peserta yang hadir tentang bagaimana cara membuat proposal yang baik, content-content yang perlu ada pada proposal dan berbagai tips menarik lainnya.

Selain itu, para peserta juga diberikan untuk bertanya seputar kompetisi Imagine Cup, tidak terbatas untuk kategori Software Design saja. Saya dan Puja juga memberikan sedikit tips and trick agar mereka bisa sukses di kompetisi Imagine Cup pertama mereka. Berikut adalah dokumentasi dari acara ini.

1712201002117122010022171220100231712201002417122010025

Share this post: | | | |
Windows Phone 7 Custom Map Control

Pada postingan saya yang ini, saya sudah menjelaskan bagaimana cara menggunakan map control untuk Windows Phone 7. Pada postingan tersebut saya juga menyebutkan bahwa untuk menavigasikan map pada emulator Windows Phone 7, diperlukan control-control yang harus kita buat sendiri. Nah, pada postingan kali ini, saya akan menjelaskan tentang cara membuat custom control tersebut.

Caranya sebagai berikut:

1. Buat sebuah project Windows Phone baru.

2. Tambahkan reference ke Microsoft.Phone.Controls.Maps pada project (bagi yang lupa caranya bisa melihatnya disini).

3. Tambahkan reference map control tersebut ke dalam file MainPage.xaml.

   1: xmlns:m="clr-namespace:Microsoft.Phone.Controls.Maps;assembly=Microsoft.Phone.Controls.Maps"

4. Selanjutnya, tambahkan kode berikut ke dalam grid yang bernama ContentPanel.

   1: <m:Map x:Name="MyMap" CredentialsProvider="YOUR BING MAPS KEY" Height="462" Width="444" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="6,6,0,0"/>
   2: <Button x:Name="btnRoad" Content="Road Mode" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="6,474,0,0" Width="207" Click="btnRoad_Click"/>
   3: <Button x:Name="btnAerial" Content="Aerial Mode" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="243,474,0,0" Width="207" Click="btnAerial_Click"/>
   4: <Button x:Name="btnZoomIn" Content="Zoom In" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="6,535,0,0" Width="207" Click="btnZoomIn_Click"/>
   5: <Button x:Name="btnZoomOut" Content="Zoom Out" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="243,535,0,0" Width="207" Click="btnZoomOut_Click"/>

Ganti “YOUR BING MAPS KEY” dengan Bing Maps key yang kalian miliki.

5. Terakhir, tambahkan kode berikut ke dalam file MainPage.xaml.cs.

   1: private void btnRoad_Click(object sender, RoutedEventArgs e)
   2: {
   3:     MyMap.Mode = new RoadMode();
   4: }
   5:  
   6: private void btnAerial_Click(object sender, RoutedEventArgs e)
   7: {
   8:     MyMap.Mode = new AerialMode();
   9: }
  10:  
  11: private void btnZoomIn_Click(object sender, RoutedEventArgs e)
  12: {
  13:     double zoom;
  14:     zoom = MyMap.ZoomLevel;
  15:     MyMap.ZoomLevel = ++zoom;
  16: }
  17:  
  18: private void btnZoomOut_Click(object sender, RoutedEventArgs e)
  19: {
  20:     double zoom;
  21:     zoom = MyMap.ZoomLevel;
  22:     MyMap.ZoomLevel = --zoom;
  23: }

6. Tekan F5 dan navigasikan map dengan tombol-tombol yang ada.

Untitled

Sekarang kalian bisa melakukan zoom in dan zoom out pada map dan mengganti-ganti map mode dari road mode menjadi aerial mode dan sebaliknya.

Source code program bisa di download disini. Ciao…

Share this post: | | | |
More Posts Next page »