公司的WebGIS平台采用Silverlight技术实现,根据Silverlight技术目前的发展情况,要做到团队成员之间组件化配置开发,是有一定复杂度的。既然决定了使用Silverlight技术开发WebGIS平台,那么就只能在Silverlight技术领域寻找解决方案。
第一个映入眼帘的就是MEF,地址为http://mef.codeplex.com/,在下载了示例程序并运行之后,发现其思路极其符合我们要求的:团队中只有一个Silverlight地图框架,其它的功能都是xap包,能够加载并运行于Silverlight地图框架之上,并获得地图句柄,进行地图的相关操作。示例程序中,通过Import和Export机制,解决了不同xap包之间传递不同对象的技术难题,一下子将我们预期完成时间缩短了非常多。一切都在顺利的进行着,直到组件xap需要通过地图控件句柄操作地图控件的时候,问题来了:组件获取不到地图控件句柄。在解决了几天仍然没方法的时候,另一个解决方案出现了:Prism,地址为http://compositewpf.codeplex.com/。
Prism在国内应用情况要比MEF好很多,有很多中文技术blog专门介绍了Prism,其中有许多写的非常好,可以去google。此方案实在是太强大,有兴趣的可以看中文介绍。我在了解几天之后,无奈的将它放弃,不是因为它不好,实在是用不起来。经过和MEF的对比,决定还是在MEF上下功夫,来解决当下遇到的惟一技术问题。
说来也巧,因为开发组件式Silverlight,一定要继承一个自定义类,此自定义类里面写着一些公共的方法,包括获取当前用户信息、部门信息等,然后此类继承UserControl类。最初的想法是通过框架中Export地图控件,在组件中Import地图控件,行不通之后,就仿照权限这一块,将地图控件作为一个属性加入到了自定义的类中,每个继承此类的Silverlight用户控件,自然会访问到地图控件属性,问题一下就解决了。
实现方法:
1、下载Mef_Preview_9
2、新建一个Silverlight应用程序,一个Silverlight类库。Silverlight类库中的程序就把Mef_Preview_9中示例程序Hello的Contracts拿过来就行。Silverlight应用程序引用Contracts和System.ComponentModel.Composition.dll两个dll。Silverlight应用程序中,MainPage.xaml.cs内容如下
public partial class MainPage : UserControl, IPartImportsSatisfiedNotification
{
[Import]
public IDeploymentCatalogService CatalogService { get; set; }
public MainPage()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
ESRI.ArcGIS.Client.ArcGISTiledMapServiceLayer tileMapServiceLayer = new ESRI.ArcGIS.Client.ArcGISTiledMapServiceLayer();
tileMapServiceLayer.Url = "http://192.168.0.205/ArcGIS/rest/services/ghj_map/MapServer";
tileMapServiceLayer.ID = "基础地图";
tileMapServiceLayer.Visible = true;
//MapControl = m_MapControl;
m_MapControl.Layers.Add(tileMapServiceLayer);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
}
private void Menu1_Click(object sender, RoutedEventArgs e)
{
CatalogService.AddXap("WebGIS.UnitSearch.xap");//加载单元查询组件
}
[ImportMany(AllowRecomposition = true)]
public Lazy<Contracts.MapModule, IWidgetMetadata>[] Widgets { get; set; }
#region IPartImportsSatisfiedNotification 成员
public void OnImportsSatisfied()
{
TopWidgets.Items.Clear();
BottomWidgets.Items.Clear();
foreach (var widget in Widgets)
{
widget.Value.MapControl = this.m_MapControl;//此处是关键中的关键
if (widget.Metadata.Location == WidgetLocation.Top)
TopWidgets.Items.Add(widget.Value);
else if (widget.Metadata.Location == WidgetLocation.Bottom)
BottomWidgets.Items.Add(widget.Value);
}
}
#endregion
private void Menu2_Click(object sender, RoutedEventArgs e)
{
CatalogService.RemoveXap("WebGIS.UnitSearch.xap");
}
}
MainPage.xaml内容如下:
<UserControl x:Class="WebGISFramework.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
xmlns:uriMapper="clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
xmlns:esri="clr-namespace:ESRI.ArcGIS.Client;assembly=ESRI.ArcGIS.Client"
xmlns:esriConverters="clr-namespace:ESRI.ArcGIS.Client.ValueConverters;assembly=ESRI.ArcGIS.Client"
xmlns:toolkit="clr-namespace:ESRI.ArcGIS.Client.Toolkit;assembly=ESRI.ArcGIS.Client.Toolkit"
xmlns:symbols="clr-namespace:ESRI.ArcGIS.Client.Symbols;assembly=ESRI.ArcGIS.Client"
xmlns:divtools="clr-namespace:Divelements.SilverlightTools;assembly=Divelements.SilverlightTools"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:esriSymbols="clr-namespace:ESRI.ArcGIS.Client.Symbols;assembly=ESRI.ArcGIS.Client"
d:DesignWidth="640" d:DesignHeight="480">
<Grid x:Name="LayoutRoot">
<Grid Canvas.Top="0" Canvas.ZIndex="9">
<ItemsControl x:Name="TopWidgets" Height="Auto" FontSize="30"></ItemsControl>
<Canvas>
<Button x:Name="Menu1" Click="Menu1_Click" Width="80" Height="25" Content="地块查询"></Button>
<Button x:Name="Menu2" Click="Menu2_Click" Width="80" Height="25" Canvas.Left="50" Content="去掉地块查询"></Button>
</Canvas>
</Grid>
<Grid Canvas.Top="20" Canvas.ZIndex="8">
<esri:Map x:Name="m_MapControl">
</esri:Map>
<ItemsControl x:Name="BottomWidgets" Height="Auto" FontSize="30"></ItemsControl>
</Grid>
</Grid>
</UserControl>
App.xaml.cs中也要做一些修改:
private void Application_Startup(object sender, StartupEventArgs e)
{
DeploymentCatalogService.Initialize();
RootVisual = new MainPage();
}
以上就是Silverlight应用程序的代码。
3、再新建一个Silverlight应用程序,作为组件,可以加载并运行于框架Silverlight之上。这里惟一要注意就是要继承自定义类,不能继承UserControl,否则得不到地图控件句柄。
至此,一个基于Silverlight的WebGIS就OK了。