基于插件技术的GIS应用框架(C# + ArcEngine9.3)(十一)

基于插件技术的GIS应用框架(C# + ArcEngine9.3)(十一)

                              ---------------------------其他一些关键的问题

    至此,已将框架部分核心的东西做了一个大概的介绍,当然还有一些大家可能在开发过程中碰到的其他的一些问题,我也同样如此,这一节,就这些零散的问题跟进行一下探讨。

   一、关于MapControl和PageLayoutControl的同步问题

   这个问题其实是老生常谈了,几乎用ArcEngine做应用,不管你使用框架与否,都会碰到这个问题;网上很多代码贴出来用一个名为: ControlsSynchronizer 类来解决这个问题,前提是还得去重写esriControls里的OpenMxdDocument命令,这样一来,觉得有些繁琐,此外,即便这样,假如我用AddData命令来添加的地图,而不是通过OpenMxdDocument来触发MapReplace事件,那么又该如何同步呢?我使用了好几种办法,个人觉得进行硬拷贝相对来说比较可靠,当然,这纯属个人感觉。

       private void CopyAndOverwriteMap()
        {
            IObjectCopy pObjectCopy;
            IMap pMap, pToCopyMap;
            object pCopiedMap, pToOverwriteMap;
       
            pObjectCopy = new ObjectCopy() as IObjectCopy;
            pToCopyMap = axMapControl.Map;
            pCopiedMap = pObjectCopy.Copy(pToCopyMap);

            pMap = axPageLayoutControl.ActiveView.FocusMap;
            pToOverwriteMap = pMap;

            pObjectCopy.Overwrite(pCopiedMap, ref pToOverwriteMap);

            pMap = axPageLayoutControl.ActiveView.FocusMap;
            (pMap as IActiveView).Extent = axMapControl.Extent;
            axPageLayoutControl.Refresh();
        }

 

        private void tabMain_SelectedPageChanged(object sender,             

                             DevExpress.XtraTab.TabPageChangedEventArgs e)
        {
            IObjectCopy pObjectCopy;
            IMap PC, pOverMap, pToCopyMap, pMap;
            object pToOverwritenMap, pIntover, pCopiedMap, pInt;

            if (tabMain.SelectedTabPage == tsMap)
            {      
                pObjectCopy = new ObjectCopy() as IObjectCopy;
                pToCopyMap = axPageLayoutControl.ActiveView.FocusMap;
                pToCopyMap.IsFramed = false;
                pInt = pObjectCopy.Copy(pToCopyMap);
                pCopiedMap = pInt as IMap;
                pMap = axMapControl.ActiveView.FocusMap;
                pIntover = pMap;
                pObjectCopy.Overwrite(pCopiedMap, ref pIntover);
                axMapControl.Refresh(esriViewDrawPhase.esriViewGeography, Type.Missing, Type.Missing);
            }
            else if (tabMain.SelectedTabPage == tsLayout)
            {
                pObjectCopy = new ObjectCopy() as IObjectCopy;
                pToCopyMap = axMapControl.ActiveView.FocusMap;
                pToCopyMap.IsFramed = true;
                pCopiedMap = pObjectCopy.Copy(pToCopyMap);
                pMap = axPageLayoutControl.ActiveView.FocusMap;
                pToOverwritenMap = pMap;
                pObjectCopy.Overwrite(pCopiedMap, ref pToOverwritenMap);
                axPageLayoutControl.Refresh(esriViewDrawPhase.esriViewGeography, Type.Missing, Type.Missing);
            }

      }

    

     二、插件的保存

     实际上这个问题很好办,通过遍历框架上的所有UI对象,读取其Tag属性中保存的插件对象的命名空间,以及它的UI对象的各个属性,即可完整保存。这里,贴上一段代码,演示如何将子菜单递归保存。

        private void SaveItemRecursion(BarSubItem item, XmlDocument xmldoc, XmlNode xmlnode)
        {
            int i, ilinkcnt;
            ilinkcnt = item.ItemLinks.Count;
            for (i = 0; i < ilinkcnt; i++)
            {
                BarItem subitem = item.ItemLinks[i].Item;
                string name = subitem.Name;
                string caption = item.ItemLinks[i].Caption;// subitem.Caption;
                string tag = "";
                string itemtype = "";
                string sVisible = "1";
                bool begingroup = item.ItemLinks[i].BeginGroup;

                if (subitem.Tag != null)
                {
                    tag = subitem.Tag.ToString();
                }
                if (tag == "")
                {
                    continue;
                }
                if (subitem is BarSubItem)             //如果是具有子菜单的菜单项插件
                {
                    itemtype = "subitem";
                    switch ((subitem as BarSubItem).Visibility)
                    {
                        case BarItemVisibility.Always: sVisible = "1"; break;
                        case BarItemVisibility.OnlyInCustomizing: sVisible = "0"; break;
                        case BarItemVisibility.Never: sVisible = "-1"; break;
                    }  
                }
                else if (subitem is BarButtonItem)    //如果是一般按钮插件
                {
                    itemtype = "command";
                }

                //如果是编辑器插件(DevExpress将编辑器进行了分类,本文论述的

                //框架中,只使用了其中的Edit、Combobox和ColorEdit三种)
                else if (subitem is BarEditItem)      
                {
                    BarEditItem edititem = (BarEditItem)subitem;
                    if (edititem.Edit.EditorTypeName == "TextEdit")
                    {
                        itemtype = "edit";
                    }
                    else if (edititem.Edit.EditorTypeName == "ComboBoxEdit")
                    {
                        itemtype = "combobox";
                    }
                    else if (edititem.Edit.EditorTypeName == "ColorEdit")
                    {
                        itemtype = "colorpicker";
                    }
                    else
                    {
                        itemtype = "undefine";
                    }
                }
                XmlElement subitemele = xmldoc.createElement_x_x("item");
                subitemele.SetAttribute("type", itemtype);
                subitemele.SetAttribute("namespace", tag);
                subitemele.SetAttribute("caption", caption);
                if (begingroup)
                {
                    subitemele.SetAttribute("begingroup", "1");
                }
                subitemele.SetAttribute("visible", sVisible);

                xmlnode.AppendChild(subitemele);

                if (subitem is BarSubItem)
                {
                    XmlNode xmlsubnode = subitemele as XmlNode;
                    BarSubItem subsubitem = (BarSubItem)subitem;
                    SaveItemRecursion(subsubitem, xmldoc, xmlsubnode); //递归保存
                }
            }
        }

 

     三、事件代理

     1. IActiveViewEvents

     前面的论述中,基本上都没有提及,想必很多人对这个问题是比较关心的,下面,我们就这个问题进行一下专门的论述。

     在本文论述的框架中,有两类事件需要进行通知,一个是IActiveViewEvents,另外一个就是IWorkspaceEvents。C#提供事件代理机制来处理COM事件,在ArcEngine中也提供了相应的接口,关键是如何让框架进行回调呢?通过以下代码,我们可以对插件如何响应框架中的两类事件有所了解。

((esriCarto.IActiveViewEvents_Event)hook.MapControl.ActiveView).ItemAdded += new             

                    esriCarto.IActiveViewEvents_ItemAddedEventHandler(Custom_ItemAdded);
((esriCarto.IActiveViewEvents_Event)hook.MapControl.ActiveView).ContentsCleared += new

                    esriCarto.IActiveViewEvents_ContentsClearedEventHandler(Custom_ContentsCleared);
((esriCarto.IActiveViewEvents_Event)hook.MapControl.ActiveView).ViewRefreshed += new 

                    esriCarto.IActiveViewEvents_ViewRefreshedEventHandler(Custom_ViewRefreshed);

    如上代码所示,我们要响应MapControl中的ItemAdded 、ContentsCleared 、ViewRefreshed 事件,只需要通过上述方式,直接把你自己的事件处理句柄交给事件代理(如上:Custom_ItemAdded、ContentsCleared、Custom_ViewRefreshed)去处理就OK了,需要注意的是,你自己定义的事件句柄,其参数必须与相应的事件接口中的参数定义保持一致。

    2.IWorkspaceEvents

    对于工作空间事件,处理相对来说就需要进行一下特别的处理,本文中因为没有使用IEngineEditor接口中的EditWorkspace,所以对于当前工作空间的事件处理,也需要自己来编写事件代理来进行。下面的接口定义了工作空间事件及其相应的事件代理。

namespace AxeMap.AxeMapEngine.Interface

{

    public interface IAxWorkspaceEvents
    {         
        /// <summary>
        /// OnStartEditing
        /// </summary>       
        event AxWorkspaceStartEditingEventsHandler OnStartEditing;
        /// <summary>
        /// OnStartEditing
        /// </summary>
        event AxWorkspaceStartEditOperationEventsHandler OnStartEditOperation;
        /// <summary>
        /// OnStartEditing
        /// </summary>
        event AxWorkspaceStopEditingEventsHandler OnStopEditing;
        /// <summary>
        /// OnStopEditOperation
        /// </summary>
        event AxWorkspaceStopEditOperationEventsHandler OnStopEditOperation;
        /// <summary>
        /// OnAbortEditOperation
        /// </summary>
        event AxWorkspaceAbortEditOperationEventsHandler OnAbortEditOperation;
        /// <summary>
        /// OnUndoEditOperation
        /// </summary>
        event AxWorkspaceUndoEditOperationEventsHandler OnUndoEditOperation;
        /// <summary>
        /// OnRedoEditOperation
        /// </summary>
        event AxWorkspaceRedoEditOperationEventsHandler OnRedoEditOperation;

        void FireEvents_OnStartEditing();

        void FireEvents_OnStartEditOperation();

        void FireEvents_OnStopEditing(bool blSaveEdit);

        void FireEvents_OnStopEditOperation(string sAction);

        void FireEvents_OnAbortEditOperation();

        void FireEvents_OnUndoEditOperation();

        void FireEvents_OnRedoEditOperation();
    }

}  

    IAxWorkspaceEvents的实现类

namespace AxeMap.AxeMapEngine.Implement
{
    //定义事件代理
    public delegate void AxWorkspaceStartEditingEventsHandler();

    public delegate void AxWorkspaceStartEditOperationEventsHandler();

    public delegate void AxWorkspaceStopEditingEventsHandler(bool blSaveEdit);

    public delegate void AxWorkspaceStopEditOperationEventsHandler(string sAction);

    public delegate void AxWorkspaceAbortEditOperationEventsHandler();

    public delegate void AxWorkspaceUndoEditOperationEventsHandler();

    public delegate void AxWorkspaceRedoEditOperationEventsHandler();

    public class AxWorkspaceEvents : IAxWorkspaceEvents
    {

        public event AxWorkspaceStartEditingEventsHandler OnStartEditing;

        public event AxWorkspaceStartEditOperationEventsHandler OnStartEditOperation;

        public event AxWorkspaceStopEditingEventsHandler OnStopEditing;

        public event AxWorkspaceStopEditOperationEventsHandler OnStopEditOperation;

        public event AxWorkspaceAbortEditOperationEventsHandler OnAbortEditOperation;

        public event AxWorkspaceUndoEditOperationEventsHandler OnUndoEditOperation;

        public event AxWorkspaceRedoEditOperationEventsHandler OnRedoEditOperation;

        public AxWorkspaceEvents()
        {

        }

        public void FireEvents_OnStartEditing()
        {
            OnStartEditing();
        }

        public void FireEvents_OnStartEditOperation()
        {
            OnStartEditOperation();
        }

        public void FireEvents_OnStopEditing(bool blSaveEdit)
        {
            OnStopEditing(blSaveEdit);
        }

        public void FireEvents_OnStopEditOperation(string sAction)
        {
            OnStopEditOperation(sAction);
        }

        public void FireEvents_OnAbortEditOperation()
        {
            OnAbortEditOperation();
        }

        public void FireEvents_OnUndoEditOperation()
        {
            OnUndoEditOperation();
        }

        public void FireEvents_OnRedoEditOperation()
        {
            OnRedoEditOperation();
        }
    }
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值