ToolbarControl

導讀

  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加文字。還可以選擇只有位圖或只有文字等不同樣式。其中位圖是新建類時自動創建的一個位圖,不需要再自己導入位圖。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章