Windows Phone - 深入使用Bing Map - 客製Pushpin

Windows Phone - 深入使用Bing Map - 客製Pushpin

在<Windows Phone 7 - 學習Location Service與Map地圖>介紹過相關使用Bing Map後,我自己遇到在撰寫Bing Map

時還是一些相關的問題,因此,特別將使用過程裡遇到的問題與相關功能做了一個整理。

 

〉. 自訂Pushpin控件

     Pushpin提供開發人員可增加圖標至地圖中,可透過ContentTemplate、Content、Background等項目來調整樣式,並且

配合Tap或DoubleTap事件,補捉到用戶點擊的是那一個Pushpin,並配合自訂的Tip或Content來顯示圖標內容。

 

(A). 重要屬性與事件

‧ 屬性:

名稱 說明
Background 設定/取得背景顏色。
可提供簡易調整Pushpin的色系,來代表不同的圖標。
Content 設定/取得Pushpin繼承ContentControl的屬性值。
可放入多種物件,例如:string、UIElement,甚至DateTime。
Content是ContentPresenter的屬性,也可用於自訂要設定的值如何加以呈現。
設定了ContentPresent後,它會自動與ContentTemplate、Content自動binding。
可詳細可參考<Customizing the Appearance of an Existing Control by Using a ControlTemplate>。
ContentTemplate 設定/取得Data Template用於呈現ContentControl的Content。
每一個UIElement均有預設的ContentTemplate,可透過XAML的方式自行調整,或配合ContentPresenter調整資料Binding對象,產生新的外貌,但是無法改變原始事件功能
Location 設定/取得Pushpin在地圖上的座標。

上述四個屬性裡,個人覺得Content與ContentTemplate是最值得注意的地方,尤其是對開發人員,因為透過XAML

即可以調整這些內容,但有時會後想透過程式來改反而變成更複雜,非常建議先了解Content與ContentTemplate

的原理,可以透過定義與動態引入的方式,讓程式更活用。

 

‧ 事件:

名稱 說明
onTap 觸發控件被輕拍(Tap)的事件。
這個事件與之前看過的<How to: Handle Manipulation Events>有更詳細的說明。
onDoubleTap 觸發控件被連續二次輕拍(Tap)的事件。

以上事件是處理當點擊圖標時,希望出現有Tip或相關應用時可以使用,由於Pushpin本身沒有OnClick的事件,

因此,可以透過上述二個事件來互相搭配完成任務。

 

 

(B). 點擊Pushpin時,出現一個提示框

        在實作前,如果您跟我一樣對ContentTemplate不清楚的話,可以先參考這一篇<Windows Phone 7 - 淺談Custom Control>

我將學習過程對ContentTemplate的暸解配合MSDN上說明加以描述,希望對接下來的範例說明有所幫助。

 

引用<Windows Phone Pushpin Custom Tooltip: Different Techniques>的範例,將它修改成支援簡單動態產生Pushpin時可以使用。

B-1. 擷取範例:將定義好的ContentTemplate擷取出來;

   1: <!-- 直接修改Pushpin的ContentTemplate -->
   2: <my:Pushpin x:Name="pushPin" Tap="pushPin_Tap" >
   3:     <my:Pushpin.Template>
   4:         <ControlTemplate TargetType="my:Pushpin">
   5:             <StackPanel>
   6:                 <ContentPresenter x:Name="content" HorizontalAlignment="Center"
   7:                               Content="{TemplateBinding Content}"
   8:                              />
   9:                 <!-- 定義Path呈現對話框的尾端, 注意Visibility的呈現方式-->
  10:                 <Path 
  11:                     Data="M0,0 L0,1 L1,0"
  12:                     Fill="{TemplateBinding Background}"
  13:                     Stretch="Fill"
  14:                     Margin="32,0"
  15:                     Height="12"
  16:                     Width="18"
  17:                     Visibility="{Binding RelativeSource={RelativeSource TemplatedParent},
  18:                         Path=Content.Visibility, Mode=TwoWay}"
  19:                         HorizontalAlignment="Left" />
  20:                 <Image Source="MapPin.png" Stretch="None" HorizontalAlignment="Left"/>
  21:             </StackPanel>
  22:         </ControlTemplate>
  23:     </my:Pushpin.Template>
  24:     <my:Pushpin.Content>
  25:         <!-- 定義OnTap時要呈現的內容,預設Visibility = Collapsed-->
  26:         <Border Background="Black"  Width="200" Visibility="Collapsed" x:Name="border"  HorizontalAlignment="Center" >
  27:             <StackPanel Orientation="Horizontal">
  28:                 <TextBlock Text="Test" Margin="10"/>
  29:                 <Image Source="Images/appbar.cup.png" Stretch="None" />
  30:                 <Image Source="Images/appbar.gas.png" Stretch="None"/>
  31:                 <Image Source="Images/appbar.home.png" Stretch="None" />
  32:             </StackPanel>
  33:         </Border>
  34:     </my:Pushpin.Content>
  35: </my:Pushpin>

上述客製的ContentTemplate定義了Pushpin的呈現方式,它重新定義了Path物件讓它可支援圖標的引入,加上Content是可自行填入的內容。

尤其是:「Path element: Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Visibility, Mode=TwoWay}".」是

產生箭頭的重點。

 

B-2. 修改方式:先將上述的ContentTemplate整理成通用的結構,並在App.xaml中加上Pushpin的ContentTemplate

   1: <!-- //20120715.. ..Pou:增加Pushpin的客製ContentTemplate-->
   2: <!--Application Resources-->
   3: <Application.Resources>
   4:     <ControlTemplate TargetType="my:Pushpin" x:Key="CustomPushPin">
   5:         <StackPanel>
   6:             <ContentPresenter x:Name="content"
   7:                               HorizontalAlignment="Center" 
   8:                               Content="{TemplateBinding Content}" />
   9:             <!-- 保留原有的Path設定內容 -->
  10:             <Path 
  11:                 Data="M0,0 L0,1 L1,0"
  12:                 Fill="{TemplateBinding Background}"
  13:                 Stretch="Fill"
  14:                 Margin="32,0"
  15:                 Height="12"
  16:                 Width="18"
  17:                 Visibility="{Binding RelativeSource={RelativeSource TemplatedParent},
  18:                 Path=Content.Visibility, Mode=TwoWay}"
  19:                 HorizontalAlignment="Left" />
  20:             <Image Source="/AliceDontLeave;component/Images/iconpoint.png" 
  21:                    Stretch="Fill" Width="26" Height="35"
  22:                    HorizontalAlignment="Left"/>
  23:         </StackPanel>
  24:     </ControlTemplate>
  25: </Application.Resources>

修改B-1的內容,去掉定義Pushpin的Content,其原因是內容需要動態產生,在ContentTemplate無法定義,因此移動至B-3的動態程式裡。

 

B-3. 修改方式:建立Pushpin、動態引入ContentTemplate、加上OnTap的事件

   1: /// <summary>
   2: /// 將地轉換成的座標加入Pushpin,並且套用新的ContentTempalte與OnTap事件。
   3: /// </summary>
   4: /// <param name="pGAddressPoint"></param>
   5: private void PinAlicePoint(List<GAddressPoint> pGAddressPoint)
   6: {
   7:     //產生一個MapLayer來加入Pushpin
   8:     MapLayer tMapLayer = new MapLayer();   
   9:     foreach (GAddressPoint tItem in pGAPItem)
  10:     {
  11:         Pushpin tPpItem = new Pushpin();
  12:         //套用定義好的ContentTemplate
  13:         tPpItem.Template = (ControlTemplate)Application.Current.Resources["CustomPushPin"];
  14:         //呼叫建立ToolTip的內容
  15:         tPpItem.Content = BuildPushPinContent(tItem);
  16:         //註冊OnTap的事件
  17:         tPpItem.Tap += new EventHandler<System.Windows.Input.GestureEventArgs>(pushPin_Tap);
  18:         //指定Pushpin的座標
  19:         tPpItem.Location = new GeoCoordinate(double.Parse(tItem.gtag_latitude),
  20:                                              double.Parse(tItem.gtag_longitude));                
  21:         tMapLayer.Children.Add(tPpItem);
  22:     }
  23:     map1.Children.Add(tMapLayer);
  24:     map1.ZoomLevel = 12;
  25: }
  26:  
  27: /// <summary>
  28: /// 將GAdressPoint轉成Pushpin的Content。
  29: /// </summary>
  30: /// <param name="pEntity">GAdressPoint</param>
  31: /// <returns>Border</returns>
  32: private Border BuildPushPinContent(GAdressPoint pEntity)
  33: {
  34:     //將範例中定義的Content透過動態程式加以產生
  35:     Border tBorder = new Border
  36:     {
  37:         //Width = 300,
  38:         Visibility = System.Windows.Visibility.Collapsed,
  39:         Name = "border",
  40:         HorizontalAlignment = System.Windows.HorizontalAlignment.Center
  41:     };
  42:     StackPanel tStakPanel = new StackPanel
  43:     {
  44:         Orientation = System.Windows.Controls.Orientation.Vertical,
  45:         Background = new SolidColorBrush(Colors.Black)          
  46:     };
  47:     TextBlock tAddress = new TextBlock
  48:     {
  49:         Margin = new Thickness(5, 0, 0, 0),
  50:         Text = pEntity.xaddress,
  51:         TextWrapping = TextWrapping.Wrap
  52:     };              
  53:     tStakPanel.Children.Add(tAddress);
  54:     tBorder.Child = tStakPanel;
  55:     return tBorder;
  56: }

沿用<Windows Phone 7 - 使用Google Map API將地址轉成座標>撰寫的範例,將地址轉換出來的座標繪制於地圖上。

在動態引入ContentTemplate時,可參考[13行]的程式段,將定義好的ContentTemplate指定給Pushpin.Template屬性,

並且透過ControlTemplate型別加以轉換。

 

B-4. 註冊OnTap事件、Map控件的OnTap事件

   1: private Pushpin gCurrenTipPushpin = null;
   2:  
   3: void pushPin_Tap(object sender, System.Windows.Input.GestureEventArgs e)
   4: {
   5:     //處理在用戶點擊了Pushpin,顯示其Content的內容。
   6:     gCurrenTipPushpin = sender as Pushpin;
   7:     Border tUC = (Border)gCurrenTipPushpin.Content;
   8:     tUC.Visibility = System.Windows.Visibility.Visible;
   9:     e.Handled = true;
  10: }
  11:  
  12: private void map1_Tap(object sender, System.Windows.Input.GestureEventArgs e)
  13: {
  14:     //處理在用戶地圖其他地方,隱藏目前顯示的Content內容。
  15:     if (gCurrenTipPushpin != null)
  16:     {
  17:         Border tUC = (Border)gCurrenTipPushpin.Content;
  18:         tUC.Visibility = System.Windows.Visibility.Collapsed;
  19:         gCurrenTipPushpin = null;
  20:     }
  21: }

上方程式定義了二個事件,一個給Pushpin的onTap事件,讓它被擊點時可以顯示其指定的Content內容;

並且在Map控件觸發OnTap時將被顯示的Content給隱藏起來。

 

B-5. 執行結果

Screen Capture

 

======

以上介紹這些屬性是我在學習使用Pushpin的時候,所遇到的問題,特別把它們記錄下來,希望對大家有所幫助。

老實說XAML這東西真的充滿了驚奇,尤其在FrameworkElement的部分需要再多花時間熟悉與了解其結構才能設計更好的元件。

 

References

Windows Phone Pushpin Custom Tooltip: Different Techniques (重要)

Custom Template in PushPin & Pushpin-Styles in Bing Maps for the Windows Phone (重要)

How to Create a Custom Pushpin Control Template in Expression Blend for Windows Phone 7 Bing Maps - Nick Harris .NET

Windows Phone 7 - the Bing Maps Control & Setting the Map View

Using the Silverlight Map Control on Windows Phone 7

【Silverlight】Bing Maps开发应用与技巧二:自定义图钉标注控件和动态ToolPanel

Show a tooltip for tapped pushpin on Windows Phone

Multiple Pushpins and Infoboxes in Bing Maps V7

[Silverlight] Bing Map 加入標記點(pushpin)

Windows Phone Pushpin Custom Tooltip using Customized ContextMenu (重要,使用contextmenu)

Show a tooltip for tapped pushpin on Windows Phone (自訂contextmenu)

Windows Phone 7 : Adding a Pushpin

Using Listpicker in Windows Phone 7

【Silverlight】Bing Maps开发应用与技巧六:使用样式美化图钉(Pushpin)控件的ToolTip外观

How to add tool tip to Pushpin in Bing Map Silverlight control

 

Dotblogs Tags: