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

本文介绍了一种解决ESRI ArcGIS Engine中MapControl与TOCControl配对失败的问题方法。通过对比自动生成的地图控件代码,发现了BeginInit与EndInit方法的重要性,并最终解决了Thesuppliedbuddyisnotasupportedobject的错误。

做了一个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都会报错,错误信息如下:

错误信息是:“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,这样就出现了上面的异常。



MySchool namespace MySchool { partial class FrmLogin { /// <summary> /// 必需的设计器变量。 /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// 清理所有正在使用的资源。 /// </summary> /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Windows 窗体设计器生成的代码 /// <summary> /// 设计器支持所需的方法 - 不要 /// 使用代码编辑器修改此方法的内容。 /// </summary> private void InitializeComponent() { System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmLogin)); this.btnLogin = new System.Windows.Forms.Button(); this.btnCancel = new System.Windows.Forms.Button(); this.txtUserName = new System.Windows.Forms.TextBox(); this.txtPwd = new System.Windows.Forms.TextBox(); this.cboLoginType = new System.Windows.Forms.ComboBox(); this.lblLoginId = new System.Windows.Forms.Label(); this.lblPwd = new System.Windows.Forms.Label(); this.lblLoginType = new System.Windows.Forms.Label(); this.SuspendLayout(); // // btnLogin // this.btnLogin.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; this.btnLogin.BackColor = System.Drawing.Color.Transparent; this.btnLogin.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("btnLogin.BackgroundImage"))); this.btnLogin.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None; this.btnLogin.Cursor = System.Windows.Forms.Cursors.Hand; this.btnLogin.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(192)))), ((int)(((byte)(128))))); this.btnLogin.FlatAppearance.BorderSize = 0; this.btnLogin.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this.btnLogin.Font = new System.Drawing.Font("宋体", 10.5F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.btnLogin.Location = new System.Drawing.Point(181, 299); this.btnLogin.Name = "btnLogin"; this.btnLogin.Size = new System.Drawing.Size(84, 21); this.btnLogin.TabIndex = 3; this.btnLogin.Text = "登 录"; this.btnLogin.UseVisualStyleBackColor = false; // // btnCancel // this.btnCancel.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("btnCancel.BackgroundImage"))); this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; this.btnCancel.FlatAppearance.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(192)))), ((int)(((byte)(128))))); this.btnCancel.FlatAppearance.BorderSize = 0; this.btnCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat; this.btnCancel.Font = new System.Drawing.Font("宋体", 10.5F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.btnCancel.Location = new System.Drawing.Point(283, 299); this.btnCancel.Name = "btnCancel"; this.btnCancel.Size = new System.Drawing.Size(84, 21); this.btnCancel.TabIndex = 4; this.btnCancel.Text = "取 消"; this.btnCancel.UseVisualStyleBackColor = true; // // txtUserName // this.txtUserName.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.txtUserName.Location = new System.Drawing.Point(254, 190); this.txtUserName.Name = "txtUserName"; this.txtUserName.Size = new System.Drawing.Size(167, 23); this.txtUserName.TabIndex = 0; // // txtPwd // this.txtPwd.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.txtPwd.Location = new System.Drawing.Point(254, 227); this.txtPwd.Name = "txtPwd"; this.txtPwd.Size = new System.Drawing.Size(167, 23); this.txtPwd.TabIndex = 1; this.txtPwd.UseSystemPasswordChar = true; // // cboLoginType // this.cboLoginType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.cboLoginType.Items.AddRange(new object[] { "系统管理员", "学生"}); this.cboLoginType.Location = new System.Drawing.Point(254, 264); this.cboLoginType.Name = "cboLoginType"; this.cboLoginType.Size = new System.Drawing.Size(167, 22); this.cboLoginType.TabIndex = 2; // // lblLoginId // this.lblLoginId.AutoSize = true; this.lblLoginId.BackColor = System.Drawing.Color.Transparent; this.lblLoginId.Font = new System.Drawing.Font("宋体", 10.5F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.lblLoginId.Location = new System.Drawing.Point(181, 194); this.lblLoginId.Name = "lblLoginId"; this.lblLoginId.Size = new System.Drawing.Size(67, 14); this.lblLoginId.TabIndex = 5; this.lblLoginId.Text = "用户名:"; // // lblPwd // this.lblPwd.AutoSize = true; this.lblPwd.BackColor = System.Drawing.Color.Transparent; this.lblPwd.Font = new System.Drawing.Font("宋体", 10.5F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.lblPwd.Location = new System.Drawing.Point(181, 231); this.lblPwd.Name = "lblPwd"; this.lblPwd.Size = new System.Drawing.Size(68, 14); this.lblPwd.TabIndex = 6; this.lblPwd.Text = "密 码:"; // // lblLoginType // this.lblLoginType.AutoSize = true; this.lblLoginType.BackColor = System.Drawing.Color.Transparent; this.lblLoginType.Font = new System.Drawing.Font("宋体", 10.5F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.lblLoginType.Location = new System.Drawing.Point(181, 268); this.lblLoginType.Name = "lblLoginType"; this.lblLoginType.Size = new System.Drawing.Size(82, 14); this.lblLoginType.TabIndex = 7; this.lblLoginType.Text = "登录类型:"; // // FrmLogin // this.AcceptButton = this.btnLogin; this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 14F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("$this.BackgroundImage"))); this.CancelButton = this.btnCancel; this.ClientSize = new System.Drawing.Size(506, 372); this.Controls.Add(this.cboLoginType); this.Controls.Add(this.lblLoginType); this.Controls.Add(this.lblPwd); this.Controls.Add(this.lblLoginId); this.Controls.Add(this.txtPwd); this.Controls.Add(this.txtUserName); this.Controls.Add(this.btnCancel); this.Controls.Add(this.btnLogin); this.Font = new System.Drawing.Font("宋体", 10.5F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.MaximizeBox = false; this.Name = "FrmLogin"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "登录"; this.ResumeLayout(false); this.PerformLayout(); } #endregion private System.Windows.Forms.Button btnLogin; private System.Windows.Forms.Button btnCancel; private System.Windows.Forms.TextBox txtUserName; private System.Windows.Forms.TextBox txtPwd; private System.Windows.Forms.ComboBox cboLoginType; private System.Windows.Forms.Label lblLoginId; private System.Windows.Forms.Label lblPwd; private System.Windows.Forms.Label lblLoginType; } }
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深蓝静音

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值