天天看點

【Silverlight】Bing Maps開發應用與技巧二:自定義圖釘标注控件和動态ToolPanel

  關于圖釘的UI外觀的設計這裡就不詳細介紹了,通過Blend可以快速的建構UI界面。首先介紹下我的實作思想,通過Path建構圖釘标注控件的UI外觀,控件整體布局使用Grid布局,分别在Grid容器裡設計好圖釘UI外觀效果和需要動态提示的ToolPanel(使用Border布局設計),預設将ToolPanel隐藏,在背景代碼中通過滑鼠事件進行控制其是否出現;另外還布局了一個TextBlock控件,用于出現圖釘标注上的内容。下面是定義好的圖釘風格的樣式:

自定義圖釘樣式

<Style x:Name="PushpinStyle" TargetType="Controls:PushPinControl">

    <Setter Property="Template">

        <Setter.Value>

            <ControlTemplate TargetType="Controls:PushPinControl">

                <Grid x:Name="grdRoot" Height="Auto" Width="Auto" HorizontalAlignment="Stretch" RenderTransformOrigin="0,0">

                    <Grid.RenderTransform>

                        <TransformGroup>

                            <ScaleTransform x:Name="_ScaleTransform" ScaleX="1" ScaleY="1"/>

                            <SkewTransform/>

                            <RotateTransform/>

                            <TranslateTransform/>

                        </TransformGroup>

                    </Grid.RenderTransform>

                    <Path Stretch="Fill" Opacity="1" RenderTransformOrigin="0.501,0.281" Data="M0,-250L6.09909264359567,

                          -250C7.86508433137037,-249.883679757668 9.5771753004554,-249.696968148304 11.2361413649071,

                          -249.457603405072 24.5078612249376,-247.542676877067 34.3794798686271,

                          -242.257907887612 41.2465583494687,-237.283319185337 44.6800986937064,

                          -234.796020219885 47.3625022581612,-232.386267374123 49.3432151487858,

                          -230.514059732522 50.3335754087938,-229.577954004373 51.1485091856508,

                          -228.776236246195 51.7942001036199,-228.166407297221 56.0964631917223,

                          -224.103097789728 68.1963801884179,-208.309435634954 69.289336364603,

                          -191.492424677005 70.6231971699074,-170.968460931381 68.290878635012,

                          -158.519576085084 59.6252929380878,-143.46295614065 52.4136905999628,

                          -130.932641056522 38.9633656169578,-121.172558189545 25.9663459471247,

                          -99.9756667119496 22.717070324265,-94.6763733347819 19.5096780307535,

                          -85.8535122559554 16.5262691191198,-75.6002242070549 15.0345529933047,

                          -70.4735161130636 13.5988258504601,-64.9891717094285 12.2418500593682,

                          -59.4087874394669 8.8494006958964,-45.4578438671403 0.658368923825747,

                          -0.264830522697093 0.658368923825747,-0.264830522697093L0.658368923825747,

                          -0.264830522697093C0.658368923825747,-0.264830522697093 -6.20713033738298,

                          -39.8775058725022 -10.9565428086754,-59.4087721806768 -13.6705143479304,

                          -70.5696227914182 -16.6994467050881,-81.3462113972954 -19.8613212892067,

                          -89.645756433626 -21.4422436994774,-93.7955199281247 -23.0564059677924,

                          -97.3260283129902 -24.6810425111283,-99.9756667119496 -37.6780541099905,

                          -121.172569912188 -51.1284623692131,-130.932797619228 -58.3399704286158,

                          -143.462940881861 -67.0055167526496,-158.519492415143 -69.3378901087436,

                          -170.968446571251 -68.0040291139176,-191.492413232913 -66.9110789415046,

                          -208.309331812531 -54.8111481537909,-224.103105568266 -50.508885223533,

                          -228.166399667826 -47.9261288596012,-230.605716191039 -42.6354741589363,

                          -236.115224319832 -34.2414024659624,-241.014917085726 -30.0443655550756,

                          -243.464752007233 -25.0714708225116,-245.762135285075 -19.2732761689687,

                          -247.447058389738 -16.3741806336881,-248.289518545224 -13.2687567063844,

                          -248.978864381863 -9.95082648482475, -249.457595894886 -8.29186423506778,

                          -249.6969603997 -6.57977326598088,-249.883671889854 -4.81378157820587,-250z" 

                          StrokeThickness="2.5" Margin="-28.398,-30.999,0,0" Width="35" Height="30.754" VerticalAlignment="Top" 

                          Fill="#59000000" HorizontalAlignment="Left" d:LayoutOverrides="Width, Height" IsHitTestVisible="False">

                        <Path.RenderTransform>

                            <TransformGroup>

                                <ScaleTransform ScaleX="1" ScaleY="1"/>

                                <SkewTransform AngleX="-57.547" AngleY="0"/>

                                <RotateTransform Angle="0"/>

                                <TranslateTransform X="45.252" Y="0"/>

                            </TransformGroup>

                        </Path.RenderTransform>

                    </Path>

                    <Path Stretch="Fill" Stroke="#FF000000" Opacity="1" RenderTransformOrigin="0.501,0.281" 

                          Data="M0,-250L6.09909264359567,-250C7.86508433137037,-249.883679757668 9.5771753004554,

                          -249.696968148304 11.2361413649071,-249.457603405072 24.5078612249376,

                          -247.542676877067 34.3794798686271,-242.257907887612 41.2465583494687,

                          -237.283319185337 44.6800986937064,-234.796020219885 47.3625022581612,

                          -232.386267374123 49.3432151487858,-230.514059732522 50.3335754087938,

                          -229.577954004373 51.1485091856508,-228.776236246195 51.7942001036199,

                          -228.166407297221 56.0964631917223,-224.103097789728 68.1963801884179,

                          -208.309435634954 69.289336364603,-191.492424677005 70.6231971699074,

                          -170.968460931381 68.290878635012,-158.519576085084 59.6252929380878,

                          -143.46295614065 52.4136905999628,-130.932641056522 38.9633656169578,

                          -121.172558189545 25.9663459471247,-99.9756667119496 22.717070324265,

                          -94.6763733347819 19.5096780307535,-85.8535122559554 16.5262691191198,

                          -75.6002242070549 15.0345529933047,-70.4735161130636 13.5988258504601,

                          -64.9891717094285 12.2418500593682,-59.4087874394669 8.8494006958964,

                          -45.4578438671403 0.658368923825747,-0.264830522697093 0.658368923825747,

                          -0.264830522697093L0.658368923825747,-0.264830522697093C0.658368923825747,

                          -0.264830522697093 -6.20713033738298,-39.8775058725022 -10.9565428086754,

                          -59.4087721806768 -13.6705143479304,-70.5696227914182 -16.6994467050881,

                          -81.3462113972954 -19.8613212892067,-89.645756433626 -21.4422436994774,

                          -93.7955199281247 -23.0564059677924,-97.3260283129902 -24.6810425111283,

                          -99.9756667119496 -37.6780541099905,-121.172569912188 -51.1284623692131,

                          -130.932797619228 -58.3399704286158,-143.462940881861 -67.0055167526496,

                          -158.519492415143 -69.3378901087436,-170.968446571251 -68.0040291139176,

                          -191.492413232913 -66.9110789415046,-208.309331812531 -54.8111481537909,

                          -224.103105568266 -50.508885223533,-228.166399667826 -47.9261288596012,

                          -230.605716191039 -42.6354741589363,-236.115224319832 -34.2414024659624,

                          -241.014917085726 -30.0443655550756,-243.464752007233 -25.0714708225116,

                          -245.762135285075 -19.2732761689687,-247.447058389738 -16.3741806336881,

                          -248.289518545224 -13.2687567063844,-248.978864381863 -9.95082648482475,

                          -249.457595894886 -8.29186423506778,-249.6969603997 -6.57977326598088,

                          -249.883671889854 -4.81378157820587,-250z" 

                          StrokeThickness="2.5" HorizontalAlignment="Left" Margin="-18,-63.25,0,0" x:Name="shpPushpin" 

                          Width="35" d:LayoutOverrides="Width" Height="63" 

                          VerticalAlignment="Top" Cursor="Hand">

                                <SkewTransform AngleX="0" AngleY="0"/>

                                <TranslateTransform X="0" Y="0"/>

                        <Path.Fill>

                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                                <GradientStop Color="#FFFFF77F" Offset="0"/>

                                <GradientStop Color="#FFFCF14E" Offset="1"/>

                            </LinearGradientBrush>

                        </Path.Fill>

                    <TextBlock TextWrapping="Wrap" d:LayoutOverrides="Height, GridBox" RenderTransformOrigin="0.51,0.491" VerticalAlignment="Top" 

                           TextAlignment="Center" Margin="-15.55,-60,0,0" x:Name="txtTitle"

                           Width="30" FontSize="24" Visibility="Visible" FontFamily="Verdana" HorizontalAlignment="Left" IsHitTestVisible="False" >

                            <TextBlock.RenderTransform>

                                <TransformGroup>

                                    <ScaleTransform/>

                                    <SkewTransform AngleX="0" AngleY="0"/>

                                    <RotateTransform Angle="0"/>

                                    <TranslateTransform X="0" Y="0"/>

                                </TransformGroup>

                            </TextBlock.RenderTransform>

                    </TextBlock>

                    <Border x:Name="ToolPanel" VerticalAlignment="Stretch" Background="#A82D2D2D" CornerRadius="8,8,8,8" Visibility="Collapsed" 

                        BorderBrush="#FF626262" BorderThickness="2,2,2,2" ScrollViewer.HorizontalScrollBarVisibility="Visible" 

                        RenderTransformOrigin="0.5,0.5" Grid.Row="0" Width="300" Height="200">

                        <Border.RenderTransform>

                                <ScaleTransform/>

                                <SkewTransform/>

                                <RotateTransform/>

                                <TranslateTransform X="20" Y="-75"/>

                        </Border.RenderTransform>

                        <StackPanel VerticalAlignment="Top" Margin="5,10, 5, 10">

                            <Grid Height="29" VerticalAlignment="Top">

                                <TextBlock Height="25" Width="346" Text="标題内容" TextWrapping="Wrap" Foreground="#FFF0E7E7" FontSize="16" 

                                    HorizontalAlignment="Left" Margin="12,3,0,1"/>

                            </Grid>

                            <StackPanel VerticalAlignment="Top">

                                <Border x:Name="ContentBorder" Background="#FF000000" CornerRadius="8,8,8,8" VerticalAlignment="Top"

                                        Margin="0,3,0,3" Padding="0,8,0,8" Opacity="0.68" MinHeight="200">

                                    <TextBlock Text="顯示内容" Foreground="White" Margin="3" ></TextBlock>

                                </Border>

                            </StackPanel>

                        </StackPanel>

                    </Border>

                </Grid>

            </ControlTemplate>

        </Setter.Value>

    </Setter>

</Style>

  接下來要做的就是實作圖示注控件的定義以及動态控制ToolPanel控件的顯示與否了,主要思路就是通過引用上面定義的樣式,以模闆的方式從樣式裡擷取到相應的控件元素進行動态控制,詳細見如下代碼:

/// <summary>

/// 自定義圖釘控件

/// </summary>

public class PushPinControl : ContentControl

{

    private string Text;

    public PushPinControl(String text)

    {

        //設定圖釘标注控件的标注内容

        this.Text = text == "" ? "M" : text;

        DefaultStyleKey = typeof(PushPinControl);

        //為目前對象引用樣式,從全局資源裡讀取

        this.Style = Application.Current.Resources["PushpinStyle"] as Style;

    }

    public override void OnApplyTemplate()

        base.OnApplyTemplate();

        //從樣式模闆中擷取TextBlock控件

        var textBlock = GetTemplateChild("txtTitle") as TextBlock;

        textBlock.Text = this.Text;

        //從樣式模闆中擷取ToolPanel(既Border布局實作的,詳細見樣式的定義)控件

        var ToolPanelBorder = GetTemplateChild("ToolPanel") as Border;

        //通過事件動态控制ToolPanel的顯示和隐藏

        this.MouseEnter += (mes, meo) => { ToolPanelBorder.Visibility = Visibility.Visible; };

        this.MouseLeave += (mls, mlo) => { ToolPanelBorder.Visibility = Visibility.Collapsed; };

}

        

  到這裡就成功的完成了圖釘标注控件的自定義了,接下來看看如何使用這個自定義的圖釘标注控件,詳見如下代碼塊:

private void AddPushPin()

    //添加Bing Maps Silverlight Control自帶的圖釘

    //var pushpin = new Pushpin();

    //pushpin.Location = new Location(29.5076372217973, 106.489384971208);

    //添加自定義的圖釘

    var pushpin = new PushPinControl("D");

    MapLayer.AddChild(pushpin, new Location(29.5076372217973, 106.489384971208));

       

  或許會有人問道,如何動态的實作ToolPanel裡顯示的内容?要實作這個功能也是非常簡單的,首先我們來分析下上面定義的樣式裡對ToolPanel部分的定義:

<Border x:Name="ToolPanel" VerticalAlignment="Stretch" Background="#A82D2D2D" CornerRadius="8,8,8,8" Visibility="Collapsed" 

    BorderBrush="#FF626262" BorderThickness="2,2,2,2" ScrollViewer.HorizontalScrollBarVisibility="Visible" 

    RenderTransformOrigin="0.5,0.5" Grid.Row="0" Width="300" Height="200">

    <Border.RenderTransform>

        <TransformGroup>

            <ScaleTransform/>

            <SkewTransform/>

            <RotateTransform/>

            <TranslateTransform X="20" Y="-75"/>

        </TransformGroup>

    </Border.RenderTransform>

    <StackPanel VerticalAlignment="Top" Margin="5,10, 5, 10">

        <Grid Height="29" VerticalAlignment="Top">

            <TextBlock Height="25" Width="346" Text="标題内容" TextWrapping="Wrap" Foreground="#FFF0E7E7" FontSize="16" 

                HorizontalAlignment="Left" Margin="12,3,0,1"/>

        </Grid>

        <StackPanel VerticalAlignment="Top">

            <Border x:Name="ContentBorder" Background="#FF000000" CornerRadius="8,8,8,8" VerticalAlignment="Top"

                    Margin="0,3,0,3" Padding="0,8,0,8" Opacity="0.68" MinHeight="200">

                <TextBlock Text="顯示内容" Foreground="White" Margin="3" ></TextBlock>

            </Border>

        </StackPanel>

    </StackPanel>

</Border>

  使用了Border進行圓角布局,在其内部通過StackPanel垂直布局實作了ToolPanel的的标題和内容兩大部分,内容部分并通過Border進行設計,取名為ContentBorder,這是為了實作動态呈現顯示内容而設計,整體Border通過TranslateTransform進行一個偏移的處理,也就是讓ToolPanel始終顯示在圖釘标注的右邊相應的位置,詳細見本文前面提供的截圖。

  從上面的實作知道ToolPanel是在滑鼠的MouseEnter事件執行的時候才會顯示的,當滑鼠離開就會将其可見性設定為隐藏。了解了這個原理後就可以想到,是否可以從MouseEnter事件中通過某種方法去處理?事件是個非常強大的技術點,這裡我們就可以通過事件,将顯示内容的Border容器派發處理,通過事件的監聽來動态更新其顯示内容。首先需要擴充一個事件類:

public delegate void PushpinContentChangedHandler(object sender,PushpinContentChangedEvantAgrs e);

public class PushpinContentChangedEvantAgrs : EventArgs

    public Border ContentBorder { get; set; }

    public PushpinContentChangedEvantAgrs() { }

    public PushpinContentChangedEvantAgrs(Border ContentBorder)

        this.ContentBorder = ContentBorder;

     接下來為自定義的圖釘标注類定義一個事件,事件類型就為上面所定義好的委托類型,傳遞的事件為PushpinContentChangedEventArgs.

    public event PushpinContentChangedHandler ContentChangedEvent;

    現在需要做的就是在目前對象的MouseEnter事件中去觸發這個事件,将樣式裡所定義好的用于顯示内容的Border對象擷取出來,通過事件參數傳遞派發出去,讓事件監聽段可以通過該事件擷取事件參數進行ToolPanel内容的呈現更新。所有我們需要改寫PushPinControl的OnApplyTemplate方法:

public override void OnApplyTemplate()

    base.OnApplyTemplate();

    //從樣式模闆中擷取TextBlock控件

    var textBlock = GetTemplateChild("txtTitle") as TextBlock;

    textBlock.Text = this.Text;

    //從樣式模闆中擷取ToolPanel(既Border布局實作的,詳細見樣式的定義)控件

    var ToolPanelBorder = GetTemplateChild("ToolPanel") as Border;

    //擷取内容Border對象,通過事件将該對象派發出去,在使用段可以通過監聽這個事件而擷取到内容Border

    var ContentBorder = GetTemplateChild("ContentBorder") as Border;

    //通過事件動态控制ToolPanel的顯示和隐藏

    this.MouseEnter += (mes, meo) => 

    { 

        ToolPanelBorder.Visibility = Visibility.Visible;  

        if (ContentChangedEvent != null)

        {

            ContentChangedEvent(this, new PushpinContentChangedEvantAgrs(ContentBorder));

        }

    };

    this.MouseLeave += (mls, mlo) => { ToolPanelBorder.Visibility = Visibility.Collapsed; };

   通過ContentChangedEvent事件的監聽動态的去改變ToolPanel裡的顯示内容就可以達到我們的目的了,比如我們動态的将ToolPanel裡的顯示内容更改為一張圖檔,上面使用自定義圖釘标注的代碼将變成下面這樣的。

    pushpin.ContentChangedEvent += (sender, o) =>

            //構造Image對象 用于顯示在ToolPanel中

            var image = new Image { Width = 100, Height = 100, Margin = new Thickness(8) };

            image.Source = new BitmapImage(new Uri("Resources/Smbecker.png", UriKind.RelativeOrAbsolute));

            Border border = o.ContentBorder;

            border.Child = image;

        };

         

  之前有網友問到如何實作可拖拽的圖釘标注控件,鑒于篇幅的原因這裡就不做介紹,不清楚的朋友可以留言讨論。本篇就介紹到這裡,歡迎大家前來交流、讨論、拍磚。

本文轉自 beniao 51CTO部落格,原文連結:http://blog.51cto.com/beniao/300734,如需轉載請自行聯系原作者

繼續閱讀