初學arcengine——ICommand 用法

ICommand 用法
在ArcEngine類庫中有大量的Command控件用來與地圖控件進行操作和交互。比如有一系列的地圖瀏覽控件、地圖查詢控件、圖斑選取控件、編輯控件來與MapControl和PageLayoutControl進行交互。這些控件被包含在ESRI.ArcGIS.Controls.dll類庫中,位於ESRI.ArcGIS.Controls命名空間下。
這些內置的Command控件可以單獨實例化來使用,也可以被安置在一個AxToolbarControl工具欄控件中,繼而被存放在一個CommandPool池中以備調用。下面對這兩種方式分別加以說明:
第一種使用方式是實例化一個Command對象並顯式地運行它:
ICommand command = new ControlsOpenDocCommandClass();
command.OnCreate(m_mapControl.Object);
command.OnClick();
其中ControlsOpenDocCommandClass就是一個Command控件,通過調用它的OnCreate方法傳遞給它需要交互的MapControl,然後調用它的OnClick方法就可以運行。上面的例子會激活一個打開地圖文檔的對話框。
另一種方法是更加常用的方法。
由於每個Command對象都是一個COM組件,所以ESRI.ArcGIS.Controls下的各個類只是對底層的COM對象的一種封裝。由於是COM對象,所以每一個Command對象都有自己的CLSID和ProgID,並在安裝Engine Runtime的時候被註冊了,你可以在註冊表的HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\找到這些Command的註冊信息,如果要查找所有Command的信息,請訪問[url=http://edndoc.esri.com/arcobjects/9.2/net/b9a335a2-f653-44a1-8961-89051f2e958f.htm][size=3][color=#3468a4]Built-in commands[/color][/size][/url]。由於是COM組件,在實例化它的過程中,.net需要實例化一個Runtime Callable Wrapper(RCW)對象,來代理對COM組件的調用。
由於大部分對地圖控件的操作都直接或間接的來自於工具欄,比如點擊工具欄上面的放大、縮小、全圖按鈕。那麼實際上我們的絕大部分Command對象都可以被寄放到這個工具欄之中。方法非常簡單:
axToolbarControl1.AddItem("esriControls.ControlsMapZoomInTool");
此處使用的esriControls.ControlsMapZoomInTool就是ControlsMapZoomInToolClass類所指向的COM組件的ProgID,需要所有這些Command的信息時,你應該到[url=http://edndoc.esri.com/arcobjects/9.2/net/b9a335a2-f653-44a1-8961-89051f2e958f.htm][size=3][color=#3468a4]Built-in commands[/color][/size][/url]這個頁面下查找,或在你的Engine幫助文檔中ms-help://ESRI.EDNv9.2/NET_Engine/b9a335a2-f653-44a1-8961-89051f2e958f.htm的位置。
通過AddItem添加到工具欄中的Command控件使用非常方便,添加了它以後你就再不用操心進一步的處理它與地圖控件的交互了。Engine內部是怎麼做到這一點的呢,記得我們在第一種方法中實例化一個Command控件時調用的OnCreate方法嗎,當時我們傳遞給它一個MapControl來告訴它需要控制哪一個地圖控件。而通過axToolbarControl1.AddItem添加的控件,由於ToolbarControl將這個控件放到自己的控件池時,就已經調用了它的OnCreate方法,並傳遞給了它自己的BuddyControl作爲控制對象,於是,一切都變得簡單了。
在實際開發項目中,我們往往不想暴露出ArcEngine內置的ToolBar控件,而是給用戶展示我們自己開發的工具欄控件。另一方面,我們也想使用這種簡單的添加控件機制。如果做到呢,方法就是在設計階段,仍然拖放一個ToolbarControl到窗體上,但是在屬性中將它的Visible設置爲false,這樣就不會顯示出來了,而我們可以往這個工具欄中添加大量的Command控件。
這個隱藏的工具欄如何使用呢,請看下面這個函數:
public void SetCurrentMapTool(string commandName)
{
   //先重置地圖當前工具
   m_Map.CurrentTool = null;
   for (int i = 0; i < m_toolbarControl.CommandPool.Count; i++)
   {
_command = m_toolbarControl.CommandPool.get_Command(i);
if (_command.Name == commandName)
{
   m_Map.CurrentTool = _command as ITool;
   _command.OnClick();
   break;
}
   }
}
前面提到ToolbarControl內部維護一個Command池,在這個池中存放了所有已添加的Command對象,獲取其中的Command可以通過CommandPool的get_Command方法,通過比較Command的名稱,可以得到想要的Command對象。這個名稱可不同於ProgID,它是另一個用來標識Command控件的字符串,具體的請在[url=http://edndoc.esri.com/arcobjects/9.2/net/b9a335a2-f653-44a1-8961-89051f2e958f.htm][size=3][color=#3468a4]Built-in commands[/color][/size][/url]上查找(第一列),比如我們之前添加的ZoomInTool控件,它的ProgID是esriControls.ControlsMapZoomInTool,它的Name是ControlToolsMapNavigation_ZoomIn。
請注意這一行:
m_Map.CurrentTool = _command as ITool;
當Command對象處理的不只是打開地圖,顯示全圖這類沒有與地圖交互的功能時,簡單的使用OnClick即可,但是當需要的是拖動鼠標控制縮放,空間查詢這類必須與地圖進行交互的動作時,就必須設置MapControl的CurrentTool屬性。
通過上面介紹的方法,就可以不僅利用Toolbar控件管理Command功能,又可以提供豐富的UI,保證表現層的靈活性。
內置的一系列Command控件可以滿足我們很多的功能需求,但是仍有稍顯不足的時候,比如Identify控件的全英文界面,會使有些用戶抓狂。這時,我們可以通過自己開發Command控件來擴展出我們需要的功能,並可以像內置Command一樣的使用。 前面提到了如何靈活地使用ArcEngine內置的Command控件,如果這些控件已經滿足你的功能需求,就儘量使用它們,因爲ArcEngine的開發一旦開始自己coding,往往遇到大量的代碼量和性能問題。而ArcEgnine的SDK提供了很多減輕開發人員負擔的模板、代碼段、示例等等。下面我們對Command控件進行的擴展就利用了SDK提供的模板。
由於Command對象封裝了太多的信息,往往使用很方法,進行擴展卻不易。比如內置的Identify控件,你只需要在工具欄中添加它就可以了:
axToolbarControl1.AddItem("esriControls.ControlsMapIdentifyTool");
它的功能極其完善,到與ArcDesktop提供的Identify工具幾乎一樣。但是我們想自定義彈出的對話框,省掉一些功能,把界面中文化,對不起,No door~。於是我們只好硬着頭皮自己開發Identify功能,還有諸如EditingToolbar,MeasureTool這些控件都存在這樣的煩惱。開發它們的難度是很大的,但是利用SDK提供的模板還是可以掃清基本思路上的障礙,並且開發出來以後可以在不同項目中重用。
思路是這樣,要使自己開發的Command控件能夠像內置控件那樣方便使用,你需要將你的Command類實現ICommand接口,如果進一步,這個Command會持久地與MapControl交互,你還需要實現ITool接口。比這高明一點的方法是繼承自BaseCommand或BaseTool抽象類。這樣需要手工編寫實現的代碼更少。最高明的方法則是使用SDK提供的模板創建這樣的Command控件。
在項目中選擇添加新項,選擇ArcGIS類別下的模板Base Command或Base Tool,如圖:
[img=670,382]http://www.cnblogs.com/images/cnblogs_com/renji/CommandWizard1.JPG[/img]
   點擊確定之後會彈出一個對話框,讓你選擇要創建的Command適用的ArcGIS組件,選擇MapControl or PageLayoutControl Command則可使Command用在普通的平面地圖控件上。
[img=353,359]http://www.cnblogs.com/images/cnblogs_com/renji/CommandWizard2.JPG[/img]
   最終生成的代碼文件中,創建了一個類,繼承自BaseCommand,提供了可供COM識別的一系列標籤,實現了BaseCommand的必要方法OnCreate和OnClick。其中重要的部分說明如下:
[Guid("4f2b2bfe-3f62-43ca-9ed3-36c8d233280c")]:使這個全局ID使此組件可以註冊在你的電腦上; [ProgId("GTLControls.Command2")]:提供了這個COM組件的ProgId,這成爲調用AddItem時傳入的參數。 base.m_name:這個名稱成爲你在查找Command時進行比較的字符串名稱。 OnCreate:方法中傳遞的參數hook成爲綁定到這個Command控件的交互對象,被保存在一個IHookHelper成員變量中,通過該成員的Hook屬性即可獲得對交互對象(往往是MapControl的弱引用)。 同時被創建的還有一個bmp圖片,是被添加到工具欄時顯示的按鈕圖片,默認是一個傻傻的兔子。
你需要實現的邏輯往往被放置在OnClick方法中。通過觀察其中的TODO註釋你可以找到在哪裏開始編寫自己的代碼。
在此沒有必要對一個具體的Command對象如何實現進行更詳細的說明,但要使一個自己開發的Command正常工作還是需要注意以下幾點:
1、這個Command必須位於一個Library項目中,當在一個exe項目中創建這樣一個Command對象會無法使用,或者是我還沒找到正確的辦法。
2、這個Library項目的屬性需要勾選爲COM Interop註冊選項,在生成選項卡下。
3、不要忘記在使用它的項目中添加對這個Library項目的引用。[img=1,1]http://imgcache.qq.com/ac/b.gif[/img]
http://apps.hi.baidu.com/share/detail/861726
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章