導讀
ToolbarControl是一個裝載地圖操作命令和工具的控件,該類內部維護一個CommandPool命令池,在這個命令池中存放着所有已經添加的Command對象,獲取其中的Command可以通過CommandPool的get_Command方法,通過比較Command的名稱,可以得到想要的Command對象。
ToolbarControl與MapControl的關係
前面已經提到ToolbarControl是一個裝載“地圖操作”命令和工具的控件,說明ToolbarControl必須和MapControl關聯纔有實際作用,因爲ToolbarControl裏面的每個功能最終都是控制地圖的顯示,而MapControl是用來最終顯示地圖的,所有地圖的展現是在MapControl裏面,而一些基本操作或命令如放大縮小平移什麼的都在ToolbarControl裏面。
ToolbarControl與MapControl的關聯實際上是把CommandPool命令池中的每個Command命令與MapControl做關聯。具體實現看如下代碼,先創建一個打開地圖文檔命令對象command,然後通過OnCreate方法把MapControl的實例對象引用axMapControl1傳遞過去,這樣就完成了關聯。調用onClick方法即可使用該命令。這個例子會激活一個打開地圖文檔的對話框。
ICommand command = new ControlsOpenDocCommandClass();
command.OnCreate(this.axMapControl1.Object);
command.OnClick();
Command的使用
這裏大家可能有個疑問,文章主題是ToolbarControl,爲什麼這裏不說ToolbarControl的使用。我們需要明白ToolbarControl是一系列命令的裝載類,它負責管理這些命令,我們要實現的功能一般都是如何創建一個新的命令,讓他去操作地圖。所以Command是核心,我們必須掌握Command的創建和使用。
1. 實例化一個Command對象
上文中已經提到過,利用ArcEngine提供的Command類創建一個操作地圖的命令,調用OnCreate方法讓該命令和MapControl關聯起來,最後調用OnClick方法讓該命令可用。
ICommand command = new ControlsOpenDocCommandClass();
command.OnCreate(m_mapControl.Object);
command.OnClick();
2. 利用COM對象加載Command命令
由於每個Command對象都是一個COM組件,所以ESRI.ArcGIS.Controls下的各個類只是對底層的COM對象的一種封裝。由於是COM對象,所以每一個Command對象都有自己的CLSID和ProgID,並在安裝Engine Runtime的時候被註冊了,你可以在註冊表的HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\找到這些Command的註冊信息,如果要查找所有Command信息。由於是COM組件,在實例化它的過程中,.net需要實例化一個Runtime Callable Wrapper(RCW)對象,來代理對COM組件的調用。
因爲大部分對地圖控件的操作都直接或間接的來自於工具欄,比如點擊工具欄上面的放大、縮小、全圖按鈕。那麼實際上我們的絕大部分Command對象都可以被寄放到這個工具欄之中。方法非常簡單:
axToolbarControl1.AddItem("esriControls.ControlsMapZoomInTool");
此處使用的esriControls.ControlsMapZoomInTool就是ControlsMapZoomInToolClass類所指向的COM組件的ProgID,需要所有這些Command的信息時,你應該到Command信息。
通過AddItem添加到工具欄中的Command控件使用非常方便,添加了它以後你就再不用操心進一步的處理它與地圖控件的交互了。Engine內部是怎麼做到這一點的呢,記得我們在第一種方法中實例化一個Command控件時調用的OnCreate方法嗎,當時我們傳遞給它一個MapControl來告訴它需要控制哪一個地圖控件。而通過axToolbarControl1.AddItem添加的控件,由於ToolbarControl將這個控件放到自己的控件池時,就已經調用了它的OnCreate方法,並傳遞給了它自己的BuddyControl作爲控制對象,於是,一切都變得簡單了。
3. 自定義Command命令
在實際開發項目中,我們往往不想暴露出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;
}
}
}
請注意這一行:
m_Map.CurrentTool = _command as ITool;
當Command對象只處理打開地圖,顯示全圖這類沒有與地圖交互的功能時,簡單的使用OnClick即可,但是當需要的是拖動鼠標控制縮放,空間查詢這類必須與地圖進行交互的動作時,就必須設置MapControl的CurrentTool屬性。通過上面介紹的方法,就可以不僅利用Toolbar控件管理Command功能,又可以提供豐富的UI,保證表現層的靈活性。
下面以添加打開文件的命令爲例:首先在項目文件下添加一個類,選擇ArcGIS-BascCommand。如下圖:
第二部選擇應用命令的應用類型,如圖所示,這裏選擇ArcMap的地圖操作命令。
新類創建成功後,C#中會預先定義好一部分代碼。開發人員需要自己重寫OnCreate 和 OnClick 兩種方法代碼。其中OnCreate 中會自動定義hook,即鉤子,用於傳遞控件的信息。而在OnClick函數中則需要寫單擊按鈕控件時所觸發的動作。本例是打開地圖文檔,代碼如下:
public OpenNewMapDocument(AxMapControl mainMapCtl)
{
//
// TODO: Define values for the public properties
//相關屬性設置
base.m_category = "Generic"; //localizable text
base.m_caption = "Open"; //localizable text
base.m_message = "This should work in ArcMap/MapControl/PageLayoutControl"; //localizable text
base.m_toolTip = "Open"; //localizable text
base.m_name = "Generic_Open"; //unique id, non-localizable (e.g. "MyCategory_MyCommand")
try
{
//
// TODO: change bitmap name if necessary
//
string bitmapResourceName = GetType().Name + ".bmp";
base.m_bitmap = new Bitmap(GetType(), bitmapResourceName);
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message, "Invalid Bitmap");
}
//初始化
m_MainMapControl = mainMapCtl;
}
其中控件的名稱在類的構造函數中設置。
// TODO: Define values for the public properties
//相關屬性設置
base.m_category = “Generic”; //自定義控件類型
base.m_caption = “Open”; //自定義控件文字,本例子是將控件上的文字設置爲OPen
base.m_message = “This should work in ArcMap/MapControl/PageLayoutControl”; //自定義控件的提示信息
base.m_toolTip = “Open”; //自定義鼠標停留的提示信息
base.m_name = “Generic_Open”; //自定義控件的名稱(如 “MyCategory_MyCommand”)
由於加載地圖文檔需要axMapControl 對象,因此在構造函數的參數中傳入項目中的mapControl,並將其賦值給類中定義的m_MainMapControl 。其需要在類中提前定義,如下:
AxMapControl m_MainMapControl = null; //作爲全局變量
然後就是OnClick函數的代碼:
public override void OnClick()
{
// TODO: Add OpenNewMapDocument.OnClick implementation
OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter = "Map Documents (*.mxd)|*.mxd";
dlg.Multiselect = false;
dlg.Title = "Open Map Document";
if (dlg.ShowDialog() == DialogResult.OK)
{
string docName = dlg.FileName;
IMapDocument mapDoc = new MapDocumentClass();
if (mapDoc.get_IsPresent(docName) && !mapDoc.get_IsPasswordProtected(docName))
{
mapDoc.Open(docName, string.Empty);
IMap map = mapDoc.get_Map(0);
// m_controlsSynchronizer.ReplaceMap(map);
m_MainMapControl.Map = map;
mapDoc.Close();
}
}
}
完成以後需要在項目的load函數中加載該類,因此在form1的load函數中加入如下代碼:
// 添加打開命令按鈕到工具條
OpenNewMapDocument openMapDoc = new OpenNewMapDocument(mainMapControl);
axToolbarControl1.AddItem(openMapDoc, -1, 0, false, -1, esriCommandStyles.esriCommandStyleIconAndText);
就是把命令添加到工具條,其中esriCommandStyles.esriCommandStyleIconAndText 是定義控件的樣式,該形式是Icon加文字。還可以選擇只有位圖或只有文字等不同樣式。其中位圖是新建類時自動創建的一個位圖,不需要再自己導入位圖。