为什那么有的控件需要BeginInit和EndInit,有的不需要?

cvcjkkj 2014-08-02 12:41:01
例如button,textBox,MonthCalendar就没有BeginInit和EndInit。
而当我使用一个NumericUpDown控件的时候,发现设计器为我生成的代码是像下面这样:

private void InitializeComponent()
{
this.numericUpDown1 = new System.Windows.Forms.NumericUpDown();
((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit();
this.SuspendLayout();
//
// numericUpDown1
//
this.numericUpDown1.Location = new System.Drawing.Point(0, 0);
this.numericUpDown1.Name = "numericUpDown1";
this.numericUpDown1.Size = new System.Drawing.Size(120, 22);
this.numericUpDown1.TabIndex = 0;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(282, 255);
this.Controls.Add(this.numericUpDown1);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit();
this.ResumeLayout(false);
}

我的问题在于:
(1)为什么NumericUpDown需要搞一个BeginInit和EndInit出来,难道需要在初始化窗口的过程中去控制它的刷新吗?
(2)为什么不是在设置了numericUpDown1实例之后立刻EndInit(),而是要在所有的代码之后EndInit()? 这个时机是如何控制的?
谢谢。
...全文
1205 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
cvcjkkj 2014-08-02
  • 打赏
  • 举报
回复
引用 1 楼 gomoku 的回复:
谢谢,我吧你的这My类拷贝到的我的程序里面,然后:

            My m = new My();
            m.Max = 20;
            m.BeginInit();
            m.Current = 3;
            m.Current = 4;
            m.EndInit();
发现,果然BeginInit期间,这个Initializing是true,也就是if括号当中的语句不会执行。 非常感谢你的解释!
gomoku 2014-08-02
  • 打赏
  • 举报
回复
如果一个组件实现ISupportInitialize接口,那么设计器就会生成BeginInit和EndInit。 该接口的最大作用就是,把多个BeginInit和EndInit之间的命令当成一锤子买卖来对待。 比如下面的My类,有个最大值和当前值,限定当前值不能大于最大值。 难题是设计器很难保证要首先设置最大值,然后再设置当前值(可能其他控件也会设置My实例)。 如果支持了ISupportInitialize,那么My类就理解现在还是初始化阶段,不用麻烦去检查错误,不用麻烦去处理每个变动。 具体的ISupportInitialize 见微软的http://msdn.microsoft.com/zh-cn/library/System.ComponentModel.ISupportInitialize(v=vs.110).aspx
class My : Component, ISupportInitialize
{
    private bool Initializing { get; set; }

    public int Max { get; set; }

    private int current;
    public int Current
    {
        get { return current; }
        set 
        {
            if (current > Max && !Initializing)
            {
                throw new InvalidOperationException("too big");
            }
            current = value;
        }
    }


    public void BeginInit()
    {
        Initializing = true;
    }

    public void EndInit()
    {
        if (this.Current > this.Max) throw new Exception("...");
        Initializing = false;
    }
}
不用工具箱的话,自己手工添加,需要注意一个问题,就是要用Aximp.exe来包装一下ocx件的类,然后再程序中引用生成的dll就可以了。 aximp [options]{file.dll | file.ocx} The following command generates MediaPlayer.dll and AxMediaPlayer.dll for the Media Player control msdxm.ocx. aximp c:\systemroot\system32\msdxm.ocx 将 ActiveX 件的 COM 类型库中的类型定义转换为 Windows 窗体件。 Windows 窗体只能承载 Windows 窗体件,即从 Control 派生的类。Aximp.exe 生成可承载于 Windows 窗体上的 ActiveX 件的包装类。这使您得以使用可应用于其他 Windows 窗体件的同一设计时支持和编程方法论。若要承载 ActiveX 件,必须生成从 AxHost 派生的包装件。此包装件包含基础 ActiveX 件的一个实例。它知道如何与 ActiveX 件通信,但它显示为 Windows 窗体件。这个生成的件承载 ActiveX 件并将其属性、方法和事件公开为生成件的属性、方法和事件。 如果不包装一下直接用,会出现 灾难性 错误。上面已经说明了原因。 在项目中引用生成的ax开头的dll,在窗体代码中增加: 声明一个公有的件对象: public AxISPICRECLib.AxISPICREC AxISPICREC; 在InitializeComponent()方法内初始化件: AxISPICREC = new AxISPICRECLib.AxISPICREC();//必须new对象,否则窗体设计器出问题 ((System.ComponentModel.ISupportInitialize)(this.AxISPICREC)).BeginInit();//初始化开始 this.Controls.Add(this.AxISPICREC);//添加件 ((System.ComponentModel.ISupportInitialize)(this.AxISPICREC)).EndInit(); this.AxISPICREC.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject("AxISPICREC.OcxState")));//设计件状态 如果遇到“正试图在 os 加载程序锁内执行托管代码”这个错误,请设置“调试”--“异常” "----"Managed Debugging Assistants"中勾掉"LoaderLock" 就可以了。

110,580

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧