利用ArcGIS Engine、VS .NET和Windows控件開發GIS應用
Dixon整理
此過程說明適合那些使用.NET建立和部署應用的開發者,它描述了使用ArcGIS控件建立和部署應用的方法和步驟。
你可以在下面的目錄下找到相應的樣例程序:
<安裝目錄>/DeveloperKit/Samples/Developer_Guide_Scenarios/ ArcGIS_Engine/Building_an_ArcGIS_Control_Application/Map_Viewer
注:ArcGIS樣例程序不包含在ArcGIS Engine開發工具包“典型”安裝方式中。如果你沒有安裝它們,則可以重新運行開發工具包安裝向導,選擇“定制”或“修改”方式,並選擇軟件開發包下的樣例項進行安裝。
一、項目描述
利用視窗控件建立應用程序的目標是演示並使你熟悉在微軟Visual Studio .NET API中使用標准ArcGIS控件開發和部署GIS應用所需的步聚。本節中使用了Visual Studio .NET開發環境中的MapControl、 PageLayoutControl、TOCControl和ToolbarControl等視窗控件。COM、Java和C++程序員應該參考如下章節:利用ActiveX建立應用程序、利用可視化JavaBeans建立應用程序、建立命令行方式的Java應用和建立命令行方式的C++應用。
本節演示了創建查看ArcMap和ArcGIS桌面應用圖形文檔的GIS應用程序的步驟。此節包含了以下技術:
l 在微軟Visual Studio .NET中加載和嵌入ArcGIS控件。
l 向PageLayoutControl和MapControl中加載圖形文檔。
l 設置ToolbarControl和TOCControl的綁定控件。
l 處理窗口縮放。
l 向ToolbarControl添加ArcGIS Engine命令和工具。
l 創建彈出式菜單
l 在TOCControl中管理標簽編輯
l 在MapControl中繪制圖形。
l 為MapControl、PageLayoutControl和ToolbarControl創建定制工具。
l 用戶化ToolbarControl。
l 在Windows操作系統中部署應用。
二、概述
本方案使用微軟Visual Studio .NET開發環境加以實現,並使用了ESRI interop程序集(Interop Assemblies),它服務於被放置在.NET窗體上的、位於.NET 窗體控件(.NET Windows Controls)中的ArcGIS控件,這些程序集在托管的.NET代碼和非托管的COM代碼之間起了橋梁作用。對COM ArcGIS控件(COM ArcGIS Controls)成員的引用都要經過Interop程序集,然后到達實際的COM對象。同樣,也從COM對象經過Interop程序集到達.NET應用程序。每個ArcGIS Engine控件具有方法、屬性與事件,它們能夠被控件嵌入的容器(如,.NET窗體)訪問。每個控件對象及其功能可以與其他ESRI ArcObjects和自定義控件組合使用,創建用戶化的客戶應用程序。
此方案是使用了C#和Visual Basic .NET兩種語言創建,但以下技術實現集中傾向於C#方案。許多開發者可能會感覺用Visual Basic .NET更舒服,那是因為他們已經比較熟悉Visual Basic 6.0代碼,然而,對於Java和C++程序員來說,他們將會覺得對C#程序語言的語法更熟悉。無論你使用哪種開發環境,對於使用ArcGIS控件的好壞既依賴於你的編程環境技術,也依賴於你所掌握的ArcObjects技術。
在本方案中,使用ToolbarControl、TOCControl、PageLayoutControl和MapControl來為應用程序提供用戶界面。這些ArcGIS控件與其他ArcObjects和ArcGIS Engine命令被開發者一起使用,用來創建一個GIS視窗應用。
三、設計
此方案在設計時,首先強調了ArcGIS 控件如何互相之間進行交互,其次,向開發者解釋說明了ArcGIS 控件對象模型的一部分。
每個.NET ArcGIS Engine控件包含有一套能夠被嵌入其內的窗口即時訪問的屬性頁。這些屬性些為控件屬性和方法的選擇提供了捷徑,並且允許開發者不寫任何代碼即可創建一個應用程序。本方案並沒有使用屬性頁,而是采用寫代碼的方式建立應用程序。關於屬性頁的更進一步的信息,請參考ArcGIS開發幫助(ArcGIS Developer Help)。
四、條件需求
要順利地完成以下方案,你需要以下條件(對於部署的需求將在后續的部署章節涉及到):
l 安裝具有授權文件的ArcGIS Engine開發工具包(Developer Kit),使之能夠用於開發。
l 安裝有微軟Visual Studio .NET 2003開發環境和微軟.NET Framework 1.1及其相應協議。
l 熟悉微軟Windows操作系統和Microsoft Visual Studio .NET的工作知識,會用C#或Visual Basic .NET編程語言。當然,此方案中提供了一些如何在Microsoft Visual Studio .NET中使用ArcGIS控件的信息,但它不能替代對開發環境的培訓。
l 不需要對ESRI其它軟件有足夠的經驗,但如果以前對ArcObjects有所接觸並對ArcGIS應用(如,ArcCatalog,ArcMap)有一個基本了解,則對於開發更有利。
l 訪問來自本方案的樣例數據和代碼,它位於:
<安裝目錄>/DeveloperKit/Samples/Developer_Guide_Scenarios/ ArcGIS_Engine/Building_an_ArcGIS_Control_Application/Map_Viewer
本方案中使用到的控件和庫如下:
l AxMapControl |
l AxTOCControl |
l AxPageLayoutControl |
l AxToolbarControl |
l ESRI.ArcGIS.Carto |
l ESRI.ArcGIS.System |
l ESRI.ArcGIS.Display |
l ESRI.ArcGIS.SystemUI |
l ESRI.ArcGIS.Geometry |
l ESRI.ArcGIS.Utility |
l esriMapControl |
l esriTOCControl |
l esriPageLayoutControl |
l esriToolbarControl |
五、實現
下面的實現過程中提供了你成功完成方案所需所有代碼。假設你對於開發環境已經有了一定的知識,所以下面沒有逐步地詳細介紹如何用Microsoft Visual Studio .NET開發應用。
(一) 加載ArcGIS控件
在你為應用程序編寫代碼之前,應該先將應用程序將用到的ArcGIS控件和其他ArcGIS Engine庫引用裝載到開發環境之中。
1. 啟動Visual Studio .NET,並從新建項目對話框中創建一個新的Visual C# “Windows應用程序”項目。
2. 將項目命名為“Controls”,並選擇位置存取該項目。
3. 在“工具箱”的“Windows窗體”標簽欄中單擊右鍵,然后從上下文菜單中選擇“添加/移除項(I)…”。
4. 在“自定義工具箱”中選擇“.NET Framework組件”,並復選“AxMapControl”,“AxPageLayoutControl”,“AxTOCControl”和“AxToolbarControl”,單擊確定按鈕。這樣所選擇的控件將顯示在工具箱的Windows窗體標簽欄中。
5. 單擊項目菜單,並選擇“添加引用(R)…”。
6. 在添加引用對話框中,雙擊“ESRI.ArcGIS.Carto”,“ESRI.ArcGIS.Display”,“ESRI.ArcGIS.Geometry”,“ESRI.ArcGIS.System”,“ESRI.ArcGIS.SystemUI”,“ESRI.ArcGIS.Utility”。單擊確定。
注:對於ESRI .NET程序集,將通過具體實例來說明,並使用.NET框架提供的COM傳送服務從你的C#項目中調用ESRI對象庫中的實體對象。
(二) 在容器中嵌入ArcGIS控件
在你能夠訪問每個控件的事件、屬性和方法之前,需要將控件嵌入到.NET容器中。一旦將控件嵌入窗體內,它們將圖形化應用程序的用戶界面。
1. 在設計模式下打開.NET窗體。
2. 雙擊工具箱Windows標簽欄中的AxMapControl控件,將MapControl加入到窗體上。
3. 再將AxPageLayoutControl、AxTOCControl和AxToolbarControl如上添加到窗體中。
4. 重新調整窗體上各個控件的大小和位置,調整結果如下所示。
5. 在窗體上雙擊顯示窗體代碼窗口,在代碼窗口的頂部增加“using”命令:
using System;
using System.Windows.Forms;
// ArcGIS Engine引用
using ESRI.ArcGIS.SystemUI;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.ToolbarControl;
using ESRI.ArcGIS.TOCControl;
注:需注意C#是區分大小寫的。當你鍵入“ESRI.”時,智能敏感的自動完成功能將允許你通過按Tab鍵完成下一節。
(三) 加載Map文檔到MapControl與PageLayoutControl
單獨的數據層或者使用ArcMap、ArcGIS桌面應用程序產生的圖形文檔,能夠被加載到MapControl和PageLayoutControl中。你可以加載樣例圖形文檔,或者加載你自己的圖形文檔。后面你將增加一個瀏覽圖形文檔的對話框。
1. 選擇Form_Load事件,並輸入下列代碼(如果你使用你自己的圖形文檔,要替換為正確的文件名):
// 使用相對路徑向PageLayoutControl加載一個圖形文檔
string filename = @"../../../../../../../../Data//ArcGIS_Engine_Developer_Guide//gulf of st. lawrence.mxd";
if ( axPageLayoutControl1.CheckMxFile(filename) )
{
axPageLayoutControl1.LoadMxFile(filename, "");
}
2. 在設計模式顯示窗體並從屬性窗選擇axPageLayoutControl1控件,顯示axPageLayoutControl事件。在OnPageLayoutReplaced事件上雙擊向代碼窗口添加該事件的處理函數。
3. 在axPageLayoutControl1_OnPageLayoutReplaced事件中鍵入以下向MapControl加載樣例圖形文檔的代碼。當文檔被裝載入PageLayoutControl時OnPageLayoutReplaced事件將會被觸發。
private void axPageLayoutControl1_OnPageLayoutReplaced(object sender, ESRI.ArcGIS.PageLayoutControl.IPageLayoutControlEvents_OnPageLayoutReplacedEvent e)
{
// 加載同樣的文檔到MapControl
axMapControl1.LoadMxFile(axPageLayoutControl1.DocumentFilename, null, null);
// 設置MapControl顯示范圍至數據的全局范圍
axMapControl1.Extent = axMapControl1.FullExtent;
}
(四) 設置ToolbarControl與TOCControl控件的綁定控件
對於此應用程序,TOCControl和ToolbarControl控件將與PageLayoutControl相互協作,而不是MapControl。為此PageLayoutControl必須設置為綁定控件。TOCControl使用綁定的ActiveView顯示圖形、圖層和符號。而位於ToolbarControl上的任何命令、工具或菜單項會受綁定控件的顯示影響。
1. 在Form_Load事件中的加載文檔代碼的后面鍵入以下紅色部分內容:
private void Form1_Load(object sender, System.EventArgs e)
{
// 使用相對路徑向PageLayoutControl加載一個圖形文檔
string filename = @"../../../../../../../../Data//ArcGIS_Engine_Developer_Guide//gulf of st. lawrence.mxd";
if ( axPageLayoutControl1.CheckMxFile(filename) )
{
axPageLayoutControl1.LoadMxFile(filename, "");
}
// 設置綁定控件
axTOCControl1.SetBuddyControl(axPageLayoutControl1);
axToolbarControl1.SetBuddyControl(axPageLayoutControl1);
}
2. 生成並運行應用程序。圖形文檔被加載到PageLayoutControl,並且TOCControl列出了圖形文檔中的數據圖層。使用TOCControl通過復選和取消復選框控制圖層的可見性。默認地,圖形文檔的焦點圖(focus map)被裝入MapControl控件。在這種當前情況下,ToolbarControl控件顯示是空的,因為沒有為它添加任何命令。試着縮放窗體,你會注意到控件不會改變尺寸。
(五) 處理窗口縮放
當窗口在運行時進行縮放時,PageLayoutControl和MapControl不會自動改變自身的尺寸。要改變控件的尺寸以便它們總是與匹配窗口的范圍,你必須將控件錨定在窗口上。如果PageLayoutControl或MapControl包含大量的數據,在窗口縮放期間重繪這些數據顯得相當重要。為了提高執行效率,你可以禁止數據重繪直到縮放操作完成后再重繪之。在縮放時,可以用一個可伸縮的位圖來替代重繪數據。
1. 在設計模式顯示窗體並從屬性窗口中選擇axPageLayoutControl1。單擊Anchor屬性,將axPageLayoutControl1錨定在窗體的頂、左、底和右部。
2. 錨定axMapControl控件到窗體的頂、左和底部。
3. 在Form_Load事件的開頭增加以下代碼:
// 當縮放時禁止重繪
this.SetStyle(ControlStyles.EnableNotifyMessage, true);
4. 向類增加以下常量:
public class Form1 : System.Windows.Forms.Form
{
// ……
private const int WM_ENTERSIZEMOVE = 0x231;
private const int WM_EXITSIZEMOVE = 0x232;
// ……
}
5. 向重載的OnNotifyMessage方法中增加下列代碼:
protected override void OnNotifyMessage(Message m)
{
base.OnNotifyMessage (m);
// 以下為手工添加的代碼
if ( m.Msg == WM_ENTERSIZEMOVE)
{
axMapControl1.SuppressResizeDrawing(true, 0);
axPageLayoutControl1.SuppressResizeDrawing(true, 0);
}
else if ( m.Msg == WM_EXITSIZEMOVE)
{
axMapControl1.SuppressResizeDrawing(false, 0);
axPageLayoutControl1.SuppressResizeDrawing(false, 0);
}
}
6. 生成並運行應用程序,試着縮放窗口。
注:禁止縮放時重畫方法是通過檢查發送到窗體的Windows消息工作的。當窗口開發縮放時,Windows發送WM_ENTERSIZEMOVE窗口消息。此時,我們禁止在MapControl和PageLayoutControl上繪制圖形,而是使用“stretchy bitmap”繪制。當Windows發送WM_EXITSIZEMOVE消息時,窗體結束縮放,這時我們全部重繪新的范圍。
(六) 向ToolbarControl增加命令
ArcGIS Engine提供了120多個命令和工具,它們與MapControl、PageLayoutControl和ToolbarControl直接相互協作。這些命令和工具為你提供了大量的經常使用的地圖導航、圖形管理、地物選擇等方面的GIS功能。現在將在你的應用程序中增加這些命令和工具的一部分。
1. 在Form_Load事件中的加載文檔代碼之前添加如下代碼。
// 增加打開檔命令
string progID;
progID = "esriControlToolsGeneric.ControlsOpenDocCommand";
axToolbarControl1.AddItem(progID, -1, -1, false, 0,
esriCommandStyles.esriCommandStyleIconOnly);
// 增加PageLayout導航命令
progID = "esriControlToolsPageLayout.ControlsPageZoomInTool";
axToolbarControl1.AddItem(progID, -1, -1, true, 0,
esriCommandStyles.esriCommandStyleIconOnly);
progID = "esriControlToolsPageLayout.ControlsPageZoomOutTool";
axToolbarControl1.AddItem(progID, -1, -1, true, 0,
esriCommandStyles.esriCommandStyleIconOnly);
progID = "esriControlToolsPageLayout.ControlsPagePanTool";
axToolbarControl1.AddItem(progID, -1, -1, true, 0,
esriCommandStyles.esriCommandStyleIconOnly);
progID = "esriControlToolsPageLayout.ControlsPageZoomWholePageCommand";
axToolbarControl1.AddItem(progID, -1, -1, true, 0,
esriCommandStyles.esriCommandStyleIconOnly);
progID = "esriControlToolsPageLayout.ControlsPageZoomPageToLastExtentBackCommand";
axToolbarControl1.AddItem(progID, -1, -1, true, 0,
esriCommandStyles.esriCommandStyleIconOnly);
progID = "esriControlToolsPageLayout.ControlsPageZoomPageToLastExtentForwardCommand";
axToolbarControl1.AddItem(progID, -1, -1, true, 0,
esriCommandStyles.esriCommandStyleIconOnly);
// 增加地圖導航命令
progID = "esriControlToolsMapNavigation.ControlsMapZoomInTool";
axToolbarControl1.AddItem(progID, -1, -1, true, 0,
esriCommandStyles.esriCommandStyleIconOnly);
progID = "esriControlToolsMapNavigation.ControlsMapZoomOutTool";
axToolbarControl1.AddItem(progID, -1, -1, true, 0,
esriCommandStyles.esriCommandStyleIconOnly);
progID = "esriControlToolsMapNavigation.ControlsMapPanTool";
axToolbarControl1.AddItem(progID, -1, -1, true, 0,
esriCommandStyles.esriCommandStyleIconOnly);
progID = "esriControlToolsMapNavigation.ControlsMapFullExtentCommand";
axToolbarControl1.AddItem(progID, -1, -1, true, 0,
esriCommandStyles.esriCommandStyleIconOnly);
// 使用相對路徑向PageLayoutControl加載一個圖形文檔
// ……
2. 生成並運行應用程序。現在ToolbarControl包含了ArcGIS Engine命令和工具,你可以使用它們導航加載到PageLayoutControl中的圖形文檔。使用頁面布局命令對當前的頁面布局進行導航控制,要對存在於數據框架中的數據進行導航則使用地圖命令。利用找開文檔命令可以瀏覽並加載其他的圖形文檔。
(七) 給PageLayoutControl添加彈出式菜單
與給跟綁定控件協作的ToolbarControl增加ArcGIS Engine命令一樣,按照前面的步驟,你也可以從ArcGIS Engine命令創建彈出式菜單。下面將向你的應用程序中增加與PageLayoutControl協作的彈出式菜單。當在PageLayoutControl可視區域點擊鼠標右鍵的時候,彈出式菜單將顯示。
1. 向類中添加如下的成員變量(紅色部分):
public class Form1 : System.Windows.Forms.Form
{
private ESRI.ArcGIS.MapControl.AxMapControl axMapControl1;
private ESRI.ArcGIS.PageLayoutControl.AxPageLayoutControl axPageLayoutControl1;
private ESRI.ArcGIS.TOCControl.AxTOCControl axTOCControl1;
private ESRI.ArcGIS.ToolbarControl.AxToolbarControl axToolbarControl1;
private IToolbarMenu m_ToolbarMenu = new ToolbarMenuClass(); // 彈出式菜單
// ……
2. 在Form_Load事件中向ToolbarControl增加命令代碼的后面加載文檔代碼的前面增加如下代碼。
private void Form1_Load(object sender, System.EventArgs e)
{
// 前面是增加地圖導航的代碼……
// 共享ToolbarControl的命令池
m_ToolbarMenu.CommandPool = axToolbarControl1.CommandPool;
// 向ToolbarMenu增加命令
progID = "esriControlToolsPageLayout.ControlsPageZoomInFixedCommand";
m_ToolbarMenu.AddItem(progID, -1, -1, false,
esriCommandStyles.esriCommandStyleIconAndText);
progID = "esriControlToolsPageLayout.ControlsPageZoomOutFixedCommand";
m_ToolbarMenu.AddItem(progID, -1, -1, false,
esriCommandStyles.esriCommandStyleIconAndText);
progID = "esriControlToolsPageLayout.ControlsPageZoomWholePageCommand";
m_ToolbarMenu.AddItem(progID, -1, -1, false,
esriCommandStyles.esriCommandStyleIconAndText);
progID = "esriControlToolsPageLayout.ControlsPageZoomPageToLastExtentBackCommand";
m_ToolbarMenu.AddItem(progID, -1, -1, true,
esriCommandStyles.esriCommandStyleIconAndText);
progID = "esriControlToolsPageLayout.ControlsPageZoomPageToLastExtentForwardCommand";
m_ToolbarMenu.AddItem(progID, -1, -1, false,
esriCommandStyles.esriCommandStyleIconAndText);
// 設置與PageLayoutControl掛接
m_ToolbarMenu.SetHook(axPageLayoutControl1);
// 后面是加載圖形文檔的代碼……
// ……
3. 在設計模式顯示窗體並從屬性窗口中選擇axPageLayoutControl1,顯示axPageLayoutControl事件。雙擊OnMouseDown事件,向代碼窗口中增加事件處理代碼。
4. 在axPageLayoutControl1_OnMouseDown事件中增加如下代碼:
private void axPageLayoutControl1_OnMouseDown(object sender, ESRI.ArcGIS.PageLayoutControl.IPageLayoutControlEvents_OnMouseDownEvent e)
{
// 彈出ToolbarMenu
if ( e.button == 2)
{
m_ToolbarMenu.PopupMenu(e.x, e.y, axPageLayoutControl1.hWnd);
}
}
5. 生成並運行應用程序。在PageLayoutControl的顯示區域單擊右鍵以顯示彈出菜單,並為頁面布局導航。
(八) 在TOCControl中控制標簽編輯
TOCControl默認允許用戶自動地切換圖層的可見性並改變顯示在目錄表中的名稱。你可以增加代碼防止用戶在編輯名稱時輸入空的字符串。
1. 在Form_Load事件的開始增加下列代碼。
private void Form1_Load(object sender, System.EventArgs e)
{
// 當縮放時禁止重繪
this.SetStyle(ControlStyles.EnableNotifyMessage, true);
// 設置標簽編輯為手動方式
axTOCControl1.LabelEdit = esriTOCControlEdit.esriTOCControlManual;
// 后面是加載文檔代碼
// ……
2. 在設計模式顯示窗體並從屬性窗口選擇AxTOCControl1控件,顯示AxTOCControl事件。雙擊OnEndLabelEdit向代碼窗口添加事件處理函數。
3. 在axTOCControl1_OnEndLabelEdit事件中添加以下代碼:
private void axTOCControl1_OnEndLabelEdit(object sender, ESRI.ArcGIS.TOCControl.ITOCControlEvents_OnEndLabelEditEvent e)
{
// 禁止在編輯標簽時鍵入空字串
string newLabel = e.newLabel;
if ( newLabel.Trim() == "" )
{
e.canEdit = false;
}
}
4. 生成並生成應用程序。編輯TOCControl控件的地圖、圖層、標題或圖例類的標簽,在其上點擊一次,然后再點一次調用標簽編輯。試着用空字串替代標簽。在編輯期間,你可以隨時使用鍵盤上的ESC鍵取消編輯。
(九) 在MapControl上繪制圖形
你可以將MapControl作為縮略圖窗體使用,並在其上繪制顯示PageLayoutControl內的焦點地圖的當前范圍。當你瀏覽PageLayoutControl數據框架內的數據時,你將看到縮略圖窗口也進行了更新。
注:使用地圖導航工具導航焦點圖(活動圖)將改變PageLayoutControl中焦點地圖的范圍並引起MapControl更新。使用頁面布局工具導航頁面布局將改變頁面布局的范圍(不是PageLayoutControl中的焦點圖的范圍),而MapControl將不更新。
1. 向類中增加下列成員變量:
public class Form1 : System.Windows.Forms.Form
{
private ESRI.ArcGIS.MapControl.AxMapControl axMapControl1;
private ESRI.ArcGIS.PageLayoutControl.AxPageLayoutControl axPageLayoutControl1;
private ESRI.ArcGIS.TOCControl.AxTOCControl axTOCControl1;
private ESRI.ArcGIS.ToolbarControl.AxToolbarControl axToolbarControl1;
private IToolbarMenu m_ToolbarMenu = new ToolbarMenuClass(); // 彈出式菜單
private IEnvelope m_Envelope; // MapControl繪制的范圍
private Object m_FillSymbol; // 在MapControl上繪制范圍使用的符號
private ITransformEvents_VisibleBoundsUpdatedEventHandler
visBoundsUpdatedE; // PageLayoutControl的焦點圖事件
注:聲明的變量visBoundsUpdatedE是一個托管。托管是一個類,它能夠擁有對指定方法的引用,並使它鏈接到一個特定的事件。在事件和方法之間的鏈接過程有時在.NET中被稱作wiring。
2. 創建一個叫CreateOverviewSymbol的新函數。這個函數是創建你將在MapControl中使用的符號的地方,此符號是用來描述PageLayoutControl焦點地圖數據范圍的。函數中增加的代碼如下:
private void CreateOverviewSymbol()
{
// 獲取IRGBColor接口
IRgbColor color = new RgbColor();
// 設置顏色屬性
color.RGB = 255;
// 獲取ILine符號接口
ILineSymbol outline = new SimpleLineSymbol();
// 設置線符號屬性
outline.Width = 1.5;
outline.Color = color;
// 獲取IFillSymbol接口
ISimpleFillSymbol simpleFillSymbol = new SimpleFillSymbolClass();
// 設置填充符號屬性
simpleFillSymbol.Outline = outline;
simpleFillSymbol.Style = esriSimpleFillStyle.esriSFSHollow;
m_FillSymbol = simpleFillSymbol;
}
3. 從Form_Load事件在TOCControl標簽編輯代碼之前調用CreateOverviewSymbol函數。
private void Form1_Load(object sender, System.EventArgs e)
{
// 當縮放時禁止重繪
this.SetStyle(ControlStyles.EnableNotifyMessage, true);
// 創建MapControl使用的符號
CreateOverviewSymbol();
// 下面是標簽編輯處理代碼
// ……
}
4. 增加下列OnVisibleBoundsUpdated函數。此函數將與地圖范圍改變時觸發的事件相連接,並用來設置新的地圖可見邊界范圍框。通過刷新MapControl,你強制它重繪其上顯示的圖形。
private void OnVisibleBoundsUpdated(IDisplayTransformation sender, bool sizeChanged)
{
// 設置新的可見范圍
m_Envelope = sender.VisibleBounds;
// 改變MapControl的前景狀態
axMapControl1.ActiveView.PartialRefresh(
esriViewDrawPhase,esriViewForeground, null, null);
}
5. PageLayoutControl默認的事件接口是IPageLayoutControlEvents。這些事件不告訴我們數據邊框內的地圖范圍。為此你需要使用PageLayoutControl的焦點地圖的ItransformEvents接口。在PageLayoutControl_OnPageLayoutReplaced事件處理中的加載文檔代碼前面增加以下代碼。
private void axPageLayoutControl1_OnPageLayoutReplaced(object sender, ESRI.ArcGIS.PageLayoutControl.IPageLayoutControlEvents_OnPageLayoutReplacedEvent e)
{
// 獲取PageLayoutControl中焦點地圖的IActiveView對象
IActiveView activeView = (IActiveView)
axPageLayoutControl1.ActiveView.FocusMap;
// 捕捉PageLayoutControl的焦點圖的ITransformEvents事件
visBoundsUpdatedE = new ITransformEvents_VisibleBoundsUpdatedEventHandler(OnVisibleBoundsUpdated);
((ITransformEvents_Event)activeView.ScreenDisplay
.DisplayTransformation).VisibleBoundsUpdated += visBoundsUpdatedE;
// 獲取焦點圖的范圍
m_Envelope = activeView.Extent;
// 后面是加載地圖文檔的代碼
// ……
6. 在設計模式下顯示窗體並從屬性窗中選擇axMapControl1,顯示axMapControl事件。雙擊OnAfterDraw向代碼窗口中增加事件處理。
7. 向axMapControl1_OnAfterDraw事件處理中增加以下代碼,使用前面創建的符號繪制MapControl顯示邊框。
private void axMapControl1_OnAfterDraw(object sender, ESRI.ArcGIS.MapControl.IMapControlEvents2_OnAfterDrawEvent e)
{
if ( m_Envelope == null)
{
return;
}
// 如果前景狀態被重繪
esriViewDrawPhase viewDrawPhase = (esriViewDrawPhase)e.viewDrawPhase;
if ( viewDrawPhase == esriViewDrawPhase.esriViewForeground )
{
IGeometry geometry = m_Envelope;
axMapControl1.DrawShape(geometry, ref m_FillSymbol);
}
}
生成並運行應用程序。使用你先前已經加好的地圖導航工具改變PageLayoutControl中焦點地圖的范圍。新的范圍被繪制在MapControl上。
(十) 創建自定義工具
創建協同MapControl和PageLayoutControl一起運作的自定義命令和工具,與你或許已經做過的創建ESRI ArcMap應用程序命令非常相似。你將創建一個在PageLayoutControl鼠標點擊位置添加包含當天日期的文本元素的自定義工具。不管用何種方法,創建同MapControl和ToolbarControl協作的命令與同PageLayoutControl一樣。
這個自定義工具的相關代碼與其他本方案源代碼一樣很有用。如果你想要直接使用自定義命令,而不自己創建它,請直接到第24步。
1. 從新建項目對話框創建一個新的Visual C# “類庫”項目。
2. 將項目命名為“Commands”,並選擇保存位置存貯之。
3. 單擊項目菜單並選擇“添加引用(R)…”。
4. 在添加引用對話框中,復選“ESRI.ArcGIS.Carto”,“ESRI.ArcGIS.Display”,“ESRI.ArcGIS.Geometry”,“ESRI.ArcGIS.System”,“ESRI.ArcGIS.SystemUI”,“ESRI.ArcGIS..Utility”和“ESRI.ArcGIS.ControlCommands”。
5. 在項目中增加一個類,名字叫AddDateTool。
6. 點擊項目菜單並選擇添加現有項,瀏覽樣例源碼目錄並找到date.bmp文件將其加入到你的項目。
7. 在解決方案資源管理器中點擊date.bmp在屬性窗口顯示其屬性。改變生成操作屬性為嵌入的資源。這張位圖將被用來作為命令按鈕的外觀。
8. 改變AddDateTool的命名空間的名稱為CSharpDotNETCommands。
namespace CSharpDotNETCommands
{
……
注:要在Visual Basi .NET中改變命名空間的名稱,則在解決方案資源管理器的項目上點擊右鍵並選擇屬性,在項目屬性頁中選擇常規並改變根命名空間后,按確定。
9. 在AddDateTool類代碼窗口的頂部增加以下引用。
using System;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.SystemUI;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.ControlCommands;
using ESRI.ArcGIS.Utility.BaseClasses;
using System.Runtime.InteropServices;
10. 指定AddDateTool類繼承自ESRI BaseTool抽象類,並增加密封(sealed)類修飾。
public sealed class AddDateTool : BaseTool
{
……
注:抽象類是不能被實例化的類,通常僅包含部分實現代碼,或者不包含任何實現代碼。它們與接口密切相關;但與接口有明顯的區別,也就是說,一個類可能實現任意數量的接口,但它僅能夠從一個抽象類中繼承。繼承了ESRI BaseTool抽象類,你便可以比直接實現esriSystemUI ICommand和ITool接口更快速、簡便地創建命令和工具。
密封類修飾說明一個類不能被繼承。此類的設計是為了限制其他類從該類繼承。
11. 向AddDateTool類的構造函數中增加下列代碼:
public sealed class AddDateTool : BaseTool
{
public AddDateTool()
{
// 獲取程序集中的資源數組
string[] res = GetType().Assembly.GetManifestResourceNames();
// 設置工具屬性
base.m_bitmap = new System.Drawing.Bitmap(
GetType().Assembly.GetManifestResourceStream(res[0]));
base.m_caption = "添加日期";
base.m_category = "CustomCommands";
base.m_message = "在頁面布局中增加一個日期元素";
base.m_name = "CustomCommands_Add Date";
base.m_toolTip = "添加日期";
}
}
注:類構造函數是一個當類創建時被調用的方法。它可以用來初始化類成員變量。構造函數名與類名相同;與其他方法不同的是它沒有返回類型。
程序中只個別地替換實現了位圖、標題、目錄、名稱、消息和提示方法,你可以設置從這此方法返回的值,且依賴於BaseTool類為這此方法提供的實現。其它的成員保留BaseTool類返回的默認值。
12. 向AddDateTool類增加下列成員變量。
public sealed class AddDateTool : BaseTool
{
// HookHelper對象處理通過OnCreate事件的回調
private IHookHelper m_HookHelper = new HookHelperClass();
……
13. 在類視圖窗口中,定位到BaseCommand類的OnCreate方法,右鍵點擊之顯示上下文菜單。選擇增加,然后重載並增加該方法至代碼窗口。
14. 在重載的OnCreate方法中增加以下代碼。
public override void OnCreate(object hook)
{
m_HookHelper.Hook = hook;
}
注:要在Visual Basic .NET中重載屬性和方法,從代碼窗口頂部的“Class Name”組合框中選擇“Overrides”,從“Method Name”組合框中選擇屬性或方法。
15. 在類視圖中定位到BaseCommand類的Enabled屬性並在其上點擊右鍵顯示上下文菜單。選擇添加,然后點重寫增加該屬性至代碼窗口。
16. 增加以下代碼,重寫BaseTool類的默認Enabled值。
public override bool Enabled
{
get
{
// 設置使能屬性
if ( m_HookHelper.ActiveView != null )
{
return true;
}
else
{
return false;
}
}
}
注:ICommand_OnCreate事件向命令工作的應用程序傳送一個句柄或回調。在這種情況下,它可以是MapControl,PageLayoutControl或ToolbarControl。除向OnCreate事件增加代碼外,你可以使用HookHelper判斷傳向命令的回調類型。命令或工具需要知道如何處理傳送的回調,所以必須對ArcGIS Control傳送的類型作檢查。HookHelper用來控件回調並返回ActiveView忽略的回調類型(MapControl、PageLayoutControl和ToolbarControl都是這樣)。
17. 在類視圖中定位到BaseTool基類的OnMouseDown方法,並在其上點擊右鍵顯示上下文菜單。選擇添加,然后重載並增加該屬性至代碼窗口。
18. 增加下列代碼,重載BaseTool類實現的默認OnMouseDown函數。
public override void OnMouseDown(int Button, int Shift, int X, int Y)
{
// TODO: 添加 AddDateTool.OnMouseDown 實現
base.OnMouseDown (Button, Shift, X, Y);
// 獲取活動視圖
IActiveView activeView = m_HookHelper.ActiveView;
// 創建新的文本元素
ITextElement textElement = new TextElementClass();
// 創建文本符號
ITextSymbol textSymbol = new TextSymbolClass();
textSymbol.Size = 25;
// 設置文本元素屬性
textElement.Symbol = textSymbol;
textElement.Text = DateTime.Now.ToShortDateString();
// 對IElementQI
IElement element = (IElement) textElement;
// 創建頁點
IPoint point = new PointClass();
point = activeView.ScreenDisplay.DisplayTransformation.ToMapPoint(X, Y);
// 設置元素圖形
element.Geometry = point;
// 增加元素到圖形繪制容器
activeView.GraphicsContainer.AddElement(element, 0);
// 刷新圖形
activeView.PartialRefresh(esriViewDrawPhase.esriViewGraphics,
null, null);
}
19. ArcGIS Engine期望自定義命令是一個COM類;因此,你必須指定你所創建的.NET類也成為一個COM類,它是通過創建一個COM可調用包裝(callable wrapper)實現的。在解決方案資源管理器窗口中,在Commands項目上右擊鼠標鍵並從上下文菜單中選擇屬性。
20. 在項目屬性頁對話框中選擇配置屬性;並點擊生成。在右面的面板中,改變為“為Com Interop注冊”為True,點確定。
注:設置“為Com Interop注冊”屬性為True會調用程序集注冊工具(Regasm.exe)。這將增加客戶端期望找到的類信息。
如果“為Com Interop注冊”屬性設為False,則使項目不要是一個C#類庫類型。
21. 在AddDateTool類的代碼編寫窗口的AddDateTool類聲明的開始位置增加下列代碼,指定COM需要的屬性。
[ClassInterface(ClassInterfaceType.None)]
[Guid("D880184E-AC81-47E5-B363 -781F4DC4528F")]
注:新的GUID可能通過Visual Studio .NET中的GuidGen.exe實用工具生成,或者從工具菜單中選擇創建GUID。GUID應該像上面的格式並不包含大括號(curly braces)。
22. 向AddDateTool類成員變量的后面增加下列代碼。此代碼定義了一些函數,這些函數使用目錄實用工具向ESRI控件命令(ESRI Control Commands)組件目錄注冊和取消注冊AddDateTool類。
// 在“ESRI Controls Commands”組件目錄注冊
#region Component Category Registration
[ComRegisterFunction()]
[ComVisible(false)]
static void RegisterFunction(String sKey)
{
string fullKey = sKey.Remove(0, 18) + @"/nImplemented Categories";
Microsoft.Win32.RegistryKey regKey =
Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(fullKey, true);
if (regKey != null)
{
regKey.CreateSubKey("{B284D891-22EE-4F12-A0A9-B1DDED9197F4}");
}
}
[ComUnregisterFunction()]
[ComVisible(false)]
static void UnregisterFunction(String sKey)
{
string fullKey = sKey.Remove(0, 18) + @"/Implemented Categories";
Microsoft.Win32.RegistryKey regKey =
Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(fullKey, true);
if (regKey != null)
{
regKey.DeleteSubKey("{B284D891-22EE-4F12-A0A9-B1DDED9197F4}");
}
}
#endregion
23. 生成工程。
24. 在方案開始創建的Visual Studio .NET “Windows應用程序”項目中,增加地圖導航命令代碼的后面增加以下代碼。
private void Form1_Load(object sender, System.EventArgs e)
{
// 前面是命令導航代碼……
// 添加自定義日期工具
progID = "CSharpDotNETCommands.AddDateTool";
axToolbarControl1.AddItem(progID, -1, -1, true, 0,
esriCommandStyles.esriCommandStyleIconAndText);
// 后面是ToolbarMenu相關代碼……
}
25. 生成並運行應用程序,使用添加日期工具向PageLayoutControl上增加一個包含當天日期的文本元素。
(十一) 自定義ToolbarControl
同在Form_Load事件中向ToolbarControl控件增加ArcGIS Engine命令和工具一樣,你也可以使用定制對話框和自定義ToolbarControl的方式添加命令和工具。要實現它,就要將ToolbarControl置為定制模式並顯示定制對話框。
1. 向類中增加下列成員變量:
……
private ITransformEvents_VisibleBoundsUpdatedEventHandler
visBoundsUpdatedE; // PageLayoutControl的焦點圖事件
private ICustomizeDialog m_CustomizeDialog = new
CustomizeDialogClass(); // CurtomizeDialog被ToolbarControl使用
private ICustomizeDialogEvents_OnStartDialogEventHandler
startDialogE; // CustomizeDialog啟動事件
private ICustomizeDialogEvents_OnCloseDialogEventHandler
closeDialogE; // CustomizeDialog關閉事件
……
注:Visual Studio .NET提供了當程序集對COM interop開放時執行的函數在系統中被注冊和取消注冊的功能。這就允許你在定制對話框可能找到的組件目錄中注冊你自己的類。
2. 創建一個叫CreateCustomizeDialog的新函數,這個函數是你通過增加如下代碼創建自定義對話框的地方。
private void CreateCustomizeDialog()
{
// 設置自定義對話框事件
startDialogE = new
ICustomizeDialogEvents_OnStartDialogEventHandler(OnStartDialog);
((ICustomizeDialogEvents_Event)m_CustomizeDialog).OnStartDialog +=
startDialogE;
closeDialogE = new
ICustomizeDialogEvents_OnCloseDialogEventHandler(OnCloseDialog);
((ICustomizeDialogEvents_Event)m_CustomizeDialog).OnCloseDialog +=
closeDialogE;
// 設置標題
m_CustomizeDialog.DialogTitle = "自定義ToolbarControl項目";
// 顯示“從文件添加”按鈕
m_CustomizeDialog.ShowAddFromFile = true;
// 設置將增加新項目的ToolbarControl
m_CustomizeDialog.SetDoubleClickDestination(axToolbarControl1);
}
注:設置ComVisible屬性為false確保此方法不能被COM客戶端直接調用。當程序集通過COM注冊時,它不影響被調用的方法。
3. 在Form_Load事件中調用CreateOverviewSymbol子過程以前調用CreateCustomizeDialog函數。
private void Form1_Load(object sender, System.EventArgs e)
{
// 當縮放時禁止重繪
this.SetStyle(ControlStyles.EnableNotifyMessage, true);
// 為ToolbarControl創建自定義對話框
CreateCustomizeDialog();
……
}
4. 在窗體上增加一個名叫“chkCustomize”的復選框,並將標題命名為“定制”。
5. 在設計模式顯示窗體並從屬性窗口選擇chkCustomize控件,顯示chkCustomize事件。在CheckedChanged事件上雙擊向代碼窗口增加相應的事件處理。
6. 向chkCustomize_CheckedChanged事件中增加下列代碼。
private void chkCustomize_CheckedChanged(object sender, System.EventArgs e)
{
// 顯示或隱藏自定義對話框
if (chkCustomize.Checked == false )
{
m_CustomizeDialog.CloseDialog();
axToolbarControl1.Customize = false;
}
else
{
m_CustomizeDialog.StartDialog(axToolbarControl1.hWnd);
axToolbarControl1.Customize = true;
}
}
7. 增加下以下OnStartDialog和OnCloseDialog事件處理函數。這些函數將與自定義對話框打開或關閉時觸發的事件緊密連接。
private void OnStartDialog()
{
axToolbarControl1.Customize = true;
}
private void OnCloseDialog()
{
axToolbarControl1.Customize = false;
chkCustomize.Checked = false;
}
8. 生成並運行應用程序,選擇定制復選框使ToolbarControl進入自定義模式,並打開自定義對話框。
9. 在自定義ToolbarControl項目對話框中的左邊目錄(Categories)列表中選擇“Graphic Element”項,然后在右邊的命令(Commands)列表中“Select Elements”項上雙擊將其加入到ToolbarControl工具欄中。右鍵點擊ToolbarControl上的任何一個項目,你可以調整它的顯示樣式和組合特性。
10. 結束定制應用。使用選擇工具移動包含日期的文本元素。
六、部署
要將應用程序成功地部署到另一台機器上,必須為應用程序配置協議。首先,它必須檢查產品協議是否有效,其次,它必須初始化協議。如果協議配置不正確有,應用程序將不能運行。
注:當采用ESRI ArcObjects開發獨立運行的程序時,應用程序負責檢查並配置協議選項。它通過實現CoClass AoInitialize和IAoInitialize接口來支持協議配置。應用程序運行時,在任何ESRI ArcObject功能被訪問之前協議初始化必須先被執行。如果初始化失敗將導致應用程序錯誤。
1. 向類中增加下列成員變量。
public class Form1 : System.Windows.Forms.Form
{
private ESRI.ArcGIS.MapControl.AxMapControl axMapControl1;
private ESRI.ArcGIS.PageLayoutControl.AxPageLayoutControl axPageLayoutControl1;
private ESRI.ArcGIS.TOCControl.AxTOCControl axTOCControl1;
private ESRI.ArcGIS.ToolbarControl.AxToolbarControl axToolbarControl1;
// 應用初始化對象
private IAoInitialize m_AoInitialize = new AoInitializeClass();
// 后面是彈出菜單變量聲明代碼
……
2. 在Form_Load事件的最開始位置增加下列代碼。
private void Form1_Load(object sender, System.EventArgs e)
{
// 創建新的AoInitialize對象
if ( m_AoInitialize == null)
{
System.Windows.Forms.MessageBox.Show(
"初始化失敗,程序不能運行!");
this.Close();
}
// 判斷產品是否有效
esriLicenseStatus licenseStatus = (esriLicenseStatus)
m_AoInitialize.IsProductCodeAvailable(
esriLicenseProductCode.esriLicenseProductCodeEngine);
if (licenseStatus == esriLicenseStatus.esriLicenseAvailable )
{
licenseStatus = (esriLicenseStatus)
m_AoInitialize.Initialize(esriLicenseProductCode.esriLicenseProductCodeEngine);
if (licenseStatus != esriLicenseStatus.esriLicenseCheckedOut )
{
System.Windows.Forms.MessageBox.Show(
"初始化失敗,應用程序不能運行!");
this.Close();
}
}
else
{
System.Windows.Forms.MessageBox.Show(
"ArcGIS Engine產品無效,此程序不能運行!");
this.Close();
}
// 當縮放時禁止重繪
this.SetStyle(ControlStyles.EnableNotifyMessage, true);
// 后面是創建自定義對話框的代碼……
……
}
3. 在設計模式顯示窗體並在屬性窗口選擇Form1,顯示窗體事件。在Closing事件上雙擊向代碼窗口增加事件處理代碼。
4. 在Form_Closing事件中增加以下代碼:
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// 釋放COM對象並關閉AoInitialize對象
ESRI.ArcGIS.Utility.COMSupport.AOUninitialize.Shutdown();
m_AoInitialize.Shutdown();
}
5. 在Release模式下生成項目和解決方案。
要將應用程序成功地部署到用戶機器上:
l 要將應用程序的可執行文件和包含自定義命令的動態鏈接庫DLL發布到用戶機器上。程序集注冊工具(RegAsm.exe)必須被用來向注冊表增加關於自定義類的信息。
l 用戶機器上需要安裝有ArcGIS Engine運行時庫和標准ArcGIS Engine協議。
l 客戶機上需要安裝Microsoft .NET Framework 1.1。
七、附加資源
下列資源可以幫助你理解和應用在本方案中在在的概念和技術。
l 在ArcGIS Engine開發工具包中包含了其他可用的文檔:ArcGIS開發幫助,組件幫助,對象模型圖表和適合於初學者的樣例程序。
l ArcGIS開發在線——一個Web站點,提供了最新的ArcGIS開發信息,包括程序樣例和技術文檔。請訪問http://arcgisdeveloperonline.esri.com/
l ESRI在線討論組——Web站點,從其他ArcGIS開發者提供無償援助。請訪問http://support.esri.com/並點擊用戶論壇頁簽。
l 微軟Visual Studio .NET開發環境中的文檔。