如何在运行时创建MapContro并绑定到TocControl

做了一个MDI程序,想在代码中动态创建地图控件,代码如下:

        private void tabbedView1_QueryControl(object sender, DevExpress.XtraBars.Docking2010.Views.QueryControlEventArgs e)
        {
            Panel panel = new Panel();
            ESRI.ArcGIS.Controls.AxMapControl axMapControl = new ESRI.ArcGIS.Controls.AxMapControl();
            axMapControl.Location = new System.Drawing.Point(0, 0);
            axMapControl.Size = new System.Drawing.Size(100, 100);
            axMapControl.Dock = DockStyle.Fill;
            axMapControl.Name = "mapControl";
            this.axTOCControl1.SetBuddyControl(axMapControl);
            panel.Location = new System.Drawing.Point(0, 0);
            panel.Size = new System.Drawing.Size(100, 100);
            panel.Dock = DockStyle.Fill;
            panel.Controls.Add(axMapControl);
            e.Control = panel;
        }

代码每次执行到SetBuddyControl都会报错,错误信息如下:

如何在运行时创建MapContro并绑定到TocControl_第1张图片

错误信息是:“The supplied buddy is not a supported object”,查看SetBuddyControl的说明,里面说他的参数可以使一下任何一种:MapControl, PageLayoutControl, SceneControl, GlobeControl or object implementing ITOCBuddy,而我们赋给的正是一个MapControl,这是没有问题的。检查发现,上述代码在执行到SetBuddyControl时,axMapControl对象是无法转换为ITOCBuddy接口对象的。这里很蹊跷,因为当我们把一个地图控件拖入窗体时,该控件也是按照上述方式创建的,为何到了这里就不行呢?因此对比窗体自动生成地图控件的代码,发现里面是这样写的:

            this.axMapControl1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.axMapControl1.Location = new System.Drawing.Point(0, 0);
            this.axMapControl1.Name = "axMapControl1";
            this.axMapControl1.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject("axMapControl1.OcxState")));
            this.axMapControl1.Size = new System.Drawing.Size(247, 185);
            this.axMapControl1.TabIndex = 0;

逐一排查,发现最可疑的地方就是OcxState,搜索了相关信息,得到的答案是OcxState存储的是控件的状态信息,既然我们的代码没有这一行,那我们就加上试一下,于是我拿另个绘制在窗体上的地图控件的OcxState赋给它,代码如下:

        private void tabbedView1_QueryControl(object sender, DevExpress.XtraBars.Docking2010.Views.QueryControlEventArgs e)
        {
            Panel panel = new Panel();
            ESRI.ArcGIS.Controls.AxMapControl axMapControl = new ESRI.ArcGIS.Controls.AxMapControl();
            axMapControl.Location = new System.Drawing.Point(0, 0);
            axMapControl.Size = new System.Drawing.Size(100, 100);
            axMapControl.Dock = DockStyle.Fill;
            axMapControl.Name = "mapControl";
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
            axMapControl.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject("axLicenseControl1.OcxState")));
            this.axTOCControl1.SetBuddyControl(axMapControl);
            panel.Location = new System.Drawing.Point(0, 0);
            panel.Size = new System.Drawing.Size(100, 100);
            panel.Dock = DockStyle.Fill;
            panel.Controls.Add(axMapControl);
            e.Control = panel;
        }

实验发现,问题依旧,这表明这个问题和OcxState没有什么关系。继续研究,经过仔细对比,发现在InitializeComponent中,还有两行,那就是所有控件都需要调用的BeginInit和EndInit方法,那么问题是不是跟这个有关呢?于是做如下实验:

        private void tabbedView1_QueryControl(object sender, DevExpress.XtraBars.Docking2010.Views.QueryControlEventArgs e)
        {
            Panel panel = new Panel();
            ESRI.ArcGIS.Controls.AxMapControl axMapControl = new ESRI.ArcGIS.Controls.AxMapControl();
            axMapControl.BeginInit();
            axMapControl.Location = new System.Drawing.Point(0, 0);
            axMapControl.Size = new System.Drawing.Size(100, 100);
            axMapControl.Dock = DockStyle.Fill;
            axMapControl.Name = "mapControl";
            panel.Location = new System.Drawing.Point(0, 0);
            panel.Size = new System.Drawing.Size(100, 100);
            panel.Dock = DockStyle.Fill;
            panel.Controls.Add(axMapControl);
            axMapControl.EndInit();
            this.axTOCControl1.SetBuddyControl(axMapControl);
            e.Control = panel;
        }

很幸运,问题就解决了。搜索了一下 BeginInit和EndInit,在MSDN中的说法是,这两个方法是 ISupportInitialize接口中方法, ISupportInitialize接口用于实现对对象进行批量初始化处理时的通知事务。调用 BeginInit通知对象批量初始化开始,调用 EndInit告诉对象批量初始化结束。使用这个接口的意义在于:对象内部某些属性可能具有相互依赖性,因此一些具有依赖性的处理需要在初始化完成之后才能进行。而 ISupportInitialize正是为了实现这个功能而生,它的BeginInit方法的作用就是告诉对象当前正在初始化,从而不要去执行那些需要在初始化完成之后才能进行的操作。这里,我们使用ArcGIS engine的MapControl也存在这个问题,在AxMapControl没有调用EndInit之前,其内部的一些属性是拒绝访问的,因此当我们把new出来的这个AxMapControl对象作为伙伴对象赋给TocControl的时候,该对象认为初始化还没有结束,从而拒绝访问或者返回null,这样就出现了上面的异常。



你可能感兴趣的:(如何在运行时创建MapContro并绑定到TocControl)