Widgets翻譯過來是小玩具。如果使用過Dojo或者ExtJS等js架構肯定會瞭解到這個“小玩具”也有大用處,能夠在很大程度上減少我們的工作量,快速完成功能需求。能減少多大工作量呢?讓我們先來,點擊這裡,看一個例子。
下載 (339.67 KB)2009-4-15 23:09
前兩節的地圖中,總感覺少點什麼……對,就是一個sliderbar,有了它感覺就像汽車有了方向盤一樣,能夠控制方向了。那麼來看看實現上面這個例子中的滑塊條需要做什麼工作吧。
在silverlight中建立一個UserControl,把上面sliderbar的外觀和功能都封裝在裡面。
來看具體工作。vs中,在silverlight工程上按右鍵,add,new item,選擇silverlight user control,起名叫mapslider,在mapslider.xaml中填如下代碼:
- <Grid x:Name="slidergrid" HorizontalAlignment="Left" VerticalAlignment="Center" Background="Azure" Margin="20">
- <StackPanel Orientation="Vertical">
- <Button x:Name="btnzoomin" Content="+" Click="btnzoomin_Click" />
- <Slider x:Name="sliderLOD" Orientation="Vertical" Height="200" SmallChange="1" LargeChange="1" Minimum="0" Cursor="Hand" ValueChanged="slider1_ValueChanged" />
- <Button x:Name="btnzoomout" Content="-" Click="btnzoomout_Click" />
- </StackPanel>
- </Grid>
複製代碼
上面這些就是滑塊條的外觀,接下來看功能部分。大致思路是在mapslider類中設定一個公用屬性Map,就是需要操作的地圖了,但這個屬性不是ESRI.ArcGIS.Map,而是另一個自訂類。為什麼要這麼做?因為這個自訂類需要實現INotifyPropertyChanged介面,當我們把自己的Map控制項作為mapslider的屬性賦值的時候,這個Map需要做另外一些工作。看代碼吧,不太明白的話就要加強對silverlight中data binding的學習。在mapslider.xaml.cs頁面中填入一下代碼:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Net;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Documents;
- using System.Windows.Input;
- using System.Windows.Media;
- using System.Windows.Media.Animation;
- using System.Windows.Shapes;
- using System.ComponentModel;
- namespace customcontrol
- {
- public partial class mapslider : UserControl
- {
- private mymap map = new mymap();
- public ESRI.ArcGIS.Map Map
- {
- get
- {
- return map.Map;
- }
- set
- {
- map.Map=value;
- if (map.Map != null)
- {
- Map.ExtentChanged += new EventHandler<ESRI.ArcGIS.ExtentEventArgs>(map_ExtentChanged);
- Map.SnapToLevels = true;
- ((ESRI.ArcGIS.ArcGISTiledMapServiceLayer)Map.Layers[0]).Initialized += new EventHandler<EventArgs>(layer0_initialized);
- }
- }
- }
- private void layer0_initialized(object o,EventArgs e)
- {
- sliderLOD.Maximum = ((ESRI.ArcGIS.ArcGISTiledMapServiceLayer)Map.Layers[0]).TileInfo.Lods.Length - 1;
- }
- public mapslider()
- {
- InitializeComponent();
- }
- private void slider1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
- {
- if (map.Map!=null)
- {
- Map.ZoomToResolution(((ESRI.ArcGIS.ArcGISTiledMapServiceLayer)Map.Layers[0]).TileInfo.Lods[Convert.ToInt32(e.NewValue)].Resolution);
- }
- }
- private void map_ExtentChanged(object o, ESRI.ArcGIS.ExtentEventArgs e)
- {
- ESRI.ArcGIS.ArcGISTiledMapServiceLayer layer = Map.Layers[0] as ESRI.ArcGIS.ArcGISTiledMapServiceLayer;
- int i;
- for (i = 0; i < layer.TileInfo.Lods.Length; i++)
- {
- if (Map.Resolution == layer.TileInfo.Lods[i].Resolution)
- break;
- }
- sliderLOD.Value = i;
- }
- private void btnzoomin_Click(object sender, RoutedEventArgs e)
- {
- sliderLOD.Value += 1;
- }
- private void btnzoomout_Click(object sender, RoutedEventArgs e)
- {
- sliderLOD.Value -= 1;
- }
- }
- //執行了這個介面後,當在首頁面page.xaml.cs中給Map賦值的時候,就能返到set語句中,以便執行綁定事件的代碼
- public class mymap:INotifyPropertyChanged
- {
- private ESRI.ArcGIS.Map map;
- public ESRI.ArcGIS.Map Map
- {
- get{return map;}
- set
- {
- map = value;
- if (PropertyChanged!=null)
- {
- PropertyChanged(this, new PropertyChangedEventArgs("Map"));
- }
- }
- }
- public event PropertyChangedEventHandler PropertyChanged;
- }
- }
複製代碼
做完封裝的工作,來看如何在page.xaml中使用這個控制項。只需要三行代碼:1、註冊user control的命名空間(和對Silverlight API的引用是一樣的,放在頁面中的根項目UserControl裡):
xmlns:uc="clr-namespace:customcontrol"
2、在頁面中添加這個slider:
<Grid x:Name="LayoutRoot" Background="White">
<!--地圖在這裡-->
</esri:Map>
<uc:mapslider x:Name="mapslider1"/>
</Grid>
3、在初始化的時候對我們自訂控制項的Map屬性賦值(page.xaml.cs中):
public Page()
{
InitializeComponent();
mapslider1.Map = Map1;
}
到此應該有這個感覺,封裝比較麻煩,但使用封裝好的控制項非常簡便。這就是Widgets帶給我們的好處。目前的beta版中,SilverlightAPI已經替我們完成5個Widgets的封裝,它們分別是:Magnifier,ToolBar,BookMark,Navigation,MapTip,其中ToolBar內部使用了ToolBarItemCollection和ToolBarItem等類。還是通過一個例子,來看看這幾個控制項都長什麼樣吧(點擊這裡):
下載 (393.61 KB)2009-4-15 23:09
MapTip需要使用到Query Task,以後的小節中再涉及到。現在分別熟悉一下這幾個Widgets的用法。
1、ToolBar和Magnifier:
這個和ADF開發中的ToolBar(工具條)是一樣的,裡面可以添加ToolItem(工具),已實現各種功能,比如平移,縮放等。silverlight中當然要有一些比較好看的效果了,比如把滑鼠放在工具條上選擇工具的時候,會有放大效果,這個效果是預設的,不能設定;點擊一個工具時,該工具會跳動一下,這個是ToolbarItemClickEffect中的Bounce效果(目前只有Bounce和None兩個選擇),也是預設的。此例中ToolBar裡面有三個ToolBarItem,分別是Pan,FullExtent和Magnifier(本身也是一個Widget),下面是ToolBar的布局:
- <Grid Height="110" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,10,10,0" >
- <Rectangle Fill="#22000000" RadiusX="10" RadiusY="10" Margin="0,4,0,0" />
- <Rectangle Fill="#775C90B2" Stroke="Gray" RadiusX="10" RadiusY="10" Margin="0,0,0,5" />
- <Rectangle Fill="#66FFFFFF" Stroke="DarkGray" RadiusX="5" RadiusY="5" Margin="10,10,10,15" />
- <StackPanel Orientation="Vertical">
- <esriWidgets:Toolbar x:Name="MyToolbar" MaxItemHeight="80" MaxItemWidth="80"
- VerticalAlignment="Top" HorizontalAlignment="Center"
- ToolbarItemClicked="MyToolbar_ToolbarItemClicked"
- ToolbarItemClickEffect="Bounce"
- Width="250" Height="80">
- <esriWidgets:Toolbar.Items>
- <esriWidgets:ToolbarItemCollection>
- <esriWidgets:ToolbarItem Text="Pan">
- <esriWidgets:ToolbarItem.Content>
- <Image Source="img/i_pan.png" Stretch="UniformToFill" Margin="5" />
- </esriWidgets:ToolbarItem.Content>
- </esriWidgets:ToolbarItem>
- <esriWidgets:ToolbarItem Text="Full Screen">
- <esriWidgets:ToolbarItem.Content>
- <Image Source="img/i_globe.png" Stretch="UniformToFill" Margin="5" />
- </esriWidgets:ToolbarItem.Content>
- </esriWidgets:ToolbarItem>
- <esriWidgets:ToolbarItem Text="Full Screen">
- <esriWidgets:ToolbarItem.Content>
- <Image Source="img/magglass.png" Stretch="UniformToFill" Margin="5"
- MouseLeftButtonDown="Image_MouseLeftButtonDown"/>
- </esriWidgets:ToolbarItem.Content>
- </esriWidgets:ToolbarItem>
- </esriWidgets:ToolbarItemCollection>
- </esriWidgets:Toolbar.Items>
- </esriWidgets:Toolbar>
- <TextBlock x:Name="StatusTextBlock" Text="" FontWeight="Bold" HorizontalAlignment="Center"/>
- </StackPanel>
- </Grid>
複製代碼
然後是code-behind內容:
private void MyToolbar_ToolbarItemClicked(object sender, ESRI.ArcGIS.Widgets.SelectedToolbarItemArgs e)
{
switch (e.Index)
{
case 0:
//pan
break;
case 1:
Map1.ZoomTo(Map1.Layers.GetFullExtent());
break;
case 2:
break;
}
}
private void Image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
MyMagnifier.Enabled = !MyMagnifier.Enabled;
}
別忘了在page的建構函式中加一句:MyMagnifier.Initialize(Map1);。可以看出,Pan工具不需要任何代碼,因為地圖本身的預設動作就是Pan,而FullExtent也是利用了Map的ZoomTo()。放大鏡的工具是在該圖片被滑鼠左鍵按住的過程中啟用的(設定enabled屬性),只要滑鼠左鍵沒有按住放大鏡圖片,該Widget就設定為不可用。比較有用的是我們可以單獨設定放大鏡自己的圖層及放大倍數,這裡放大鏡使用的就是StreetMap,倍數為3。
2、BookMark:
這個功能和ArcMap(9.3版本)中的BookMark是一樣的,可以像看書一樣,為當前地圖範圍設定一個書籤,便於其他時候快速定位到該範圍。而查看API中的Bookmark.MapBookmark類(可以利用它對書籤的內容進行單個添加或刪除),可以發現其實每個書籤儲存的內容是一個Extent,然後再起一個名字就可以了。添加了bookmark widget後似乎會造成vs中的preview視窗出錯。
<!--bookmark-->
<Canvas>
<esriWidgets:Bookmark x:Name="MyBookmarks" Width="125" HorizontalAlignment="Left" VerticalAlignment="Top"
Margin="20" Background="#99257194" BorderBrush="#FF92a8b3" Foreground="Black"
Loaded="MyBookmarks_Loaded" />
</Canvas>
page.xaml.cs中:
private void MyBookmarks_Loaded(object sender, RoutedEventArgs e)
{
MyBookmarks.Map = Map1;
}
3、Navigation:
這個導航條工具是目前網路地圖必備的一個控制項,但silverlight的功能,可以輕易實現地圖的旋轉(其實也可以在代碼中通過Map.Rotation屬性來設定)。經實驗這個widget只能放在StackPanel或Grid容器裡,如果放在Canvas裡的話地圖中不會顯示。
<!--navigation bar.must be in a stackpanel-->
<StackPanel HorizontalAlignment="Left" VerticalAlignment="Bottom">
<esriWidgets:Navigation x:Name="MyNavigation" Margin="5" />
</StackPanel>
同樣在page的建構函式中添加一句:MyNavigation.Map = Map1;。
API中的Widgets可以簡化我們的工作,拿來即用。但明顯的缺陷就是不靈活,如果想使自己的控制項不那麼千篇一律的話,就需要自己進行開發工作了。
原文地址:http://bbs.esrichina-bj.cn/ESRI/thread-44555-1-1.html