C#.Net组件开发(高级篇) - 设计时在窗体设计器文件内生成组件的代码
作者:C/S框架网  发布日期:2011/08/26 16:47:37
  C#.Net组件开发(高级篇) - 设计时在窗体设计器文件内生成组件的代码

C#.Net组件开发(高级篇) - 设计时在窗体设计器文件内生成组件的代码



在设计环境下设计组件和窗体设计器是很底层东西,技术非常复杂,水很深!刚学了点皮毛感觉入了门,特别将代码分享出来.在动手实验过程中遇到很多麻烦,因为没搞清这个实时设计的概念,还有这个窗体设计器会自动生成XXX.Designer.cs文件的代码,非常神奇的技术,也许将来对框架改进有帮助,所以想一探究竟.因为我不理解这个代码生成的机制,于是到处找文章,百度搜索关键字太烂了,基本上找不着我想要的,用Google勉强能找到一些文章,也不对口,东拼西凑,认真动手做实验,坚持了几天写了不少代码.


先讲下如何在窗体设计器文件内生成组件的代码,如要生成设计时的代码,参与的对象必须实现IComponent接口,比如往窗体上拖个Button, 打开XXX.Designer.cs文件查看代码:

C# Code:

private void InitializeComponent()
{
   this.button1 = new System.Windows.Forms.Button();
   this.SuspendLayout();
   //
   // button1
   //
   this.button1.Location = new System.Drawing.Point(87, 75);
   this.button1.Name = "button1";
   this.button1.Size = new System.Drawing.Size(75, 23);
   this.button1.TabIndex = 0;
   this.button1.Text = "button1";
   this.button1.UseVisualStyleBackColor = true;
   //
   // frmTester
   //
   this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
   this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
   this.ClientSize = new System.Drawing.Size(292, 266);
   this.Controls.Add(this.button1);
   this.Name = "frmTester";
   this.Text = "frmTester";
   this.ResumeLayout(false);
   
}



可见自动生成了button1相关代码,最重要的是这句:this.Controls.Add(this.button1),将button1对象加入到窗体的控制列表中.在Controls.Add方法上点右键弹出菜单,选择Go to Definition查看源码:

C# Code:

public class Control : Component, IDropTarget, ISynchronizeInvoke, IWin32Window, IBindableComponent, IComponent, IDisposable
{
...略...
// Summary:
// Adds the specified control to the control collection.
//
// Parameters:
// value:
// The System.Windows.Forms.Control to add to the control collection.
//
// Exceptions:
// System.Exception:
// The specified control is a top-level control, or a circular control reference
// would result if this control were added to the control collection.
//
// System.ArgumentException:
// The object assigned to the value parameter is not a System.Windows.Forms.Control.

public virtual void Add(Control value);

...略...
}


可见Add方法接受Control参数,而Control类继承了实现IComponent接口的Component类.

好了,下面看我是如何自动生成button2的代码.

首先建立一个用于测试的组件,命名CSFrameworkComponent,类定义了一组属性(Attribute).给组件指定一个自定义的设计器CSFrameworkDesigner.我们使用CSFrameworkDesigner设计器生成按钮的代码.

C# Code:

[ToolboxBitmap(typeof(CSFrameworkComponent), "ComponentTest.bmp")]
[DesignTimeVisible(true)]
[Designer(typeof(CSFrameworkDesigner), typeof(IDesigner))]
public partial class CSFrameworkComponent : Component
{
   //窗体设计器的接口引用,当拖拉组件到窗体上,值由构造器传入.
   private IContainer _Designer;
   
   public CSFrameworkComponent()
   {
      
   }
   
   public CSFrameworkComponent(IContainer container)
   {
      _Designer = container;
      container.Add(this);
   }
}

//来源:C/S框架网(www.csframework.com) QQ:1980854898



自定义设计器CSFrameworkDesigner


C# Code:

public class CSFrameworkComponentDesigner : ComponentDesigner
{
   private CSFrameworkComponent _CurrentComponent;
   
   public CSFrameworkComponentDesigner()
   : base()
   {
      // 添加菜单到右键菜单和智能标记中。
      DesignerVerb V1 = new DesignerVerb("生成MyNodeComponent的设计时代码", new EventHandler(OnGenerateMyNodeComponentCode));
      DesignerVerb V2 = new DesignerVerb("生成Button的设计时代码", new EventHandler(OnGenerateButtonCode));
      DesignerVerb V3 = new DesignerVerb("www.CSFramework.com C/S框架网", new EventHandler(OnAbout));
      
      this.Verbs.Add(V1);
      this.Verbs.Add(V2);
      this.Verbs.Add(V3);
   }
   
   private void OnAbout(object sender, EventArgs e)
   {
      MessageBox.Show("程序:Jonny Sun \r\n版权:www.CSFramework.com C/S框架网");
   }
   
   private void OnGenerateMyNodeComponentCode(object sender, EventArgs e)
   {
      //
      //在窗体设计器代码中生成自定义MyNodeComponent组件的代码
      //
      //取出窗体设计器
      IDesignerHost host = (IDesignerHost)this.Component.Site.GetService(typeof(IDesignerHost));
      
      //创建一个组件
      MyNodeComponent node = (MyNodeComponent)host.CreateComponent(typeof(MyNodeComponent));
      node.NodeName = "www.CSFramework.com";
      node.ID = DateTime.Now.Millisecond;
      host.Container.Add(node);//在窗体设计器代码中生成代码
      
      MessageBox.Show("已生成" node.NodeName "的代码!请打开frmTester.Designer.cs文件查看.");
   }
   
   public override void Initialize(IComponent component)
   {
      base.Initialize(component);
      
      _CurrentComponent = (CSFrameworkComponent)component;
   }
   
   private void OnGenerateButtonCode(object sender, EventArgs e)
   {
      //
      //在窗体上加入一个Button组件,host.RootComponent=Form
      //
      //取出窗体设计器
      IDesignerHost host = (IDesignerHost)this.GetService(typeof(IDesignerHost));
      IComponentChangeService c = (IComponentChangeService)this.GetService(typeof(IComponentChangeService));
      
      Form form = (Form)host.RootComponent;//RootComponent: 根组件,指Form
      DesignerTransaction tran = host.CreateTransaction();//创建事务
      
      //创建按钮组件
      Button button = (Button)host.CreateComponent(typeof(Button));
      button.Text = "www.CSFramework.com";
      button.Location = new Point(50, 50);
      button.Size = new Size(150, 30);
      
      c.OnComponentChanging(form, null);//通知窗体正在新增控件服务
      form.Controls.Add(button);//Form.Controls.Add, 生成持久化代码
      c.OnComponentChanged(form, null, null, null);//通知窗体修改服务已完成
      
      tran.Commit();//提交事务
      
      MessageBox.Show("已生成" button.Name "的代码!请打开frmTester.Designer.cs文件查看.");
   }
      
}

//来源:C/S框架网(www.csframework.com) QQ:1980854898





完成组件和设计器的代码后重新编译程序,新建一个窗体,往窗体上拖一个CSFrameworkComponent组件,在组件上点右键如下图:

贴图图片






frmTester.Designer.cs文件

贴图图片




C/S框架网|原创精神.创造价值.打造精品


扫一扫加作者微信
C/S框架网作者微信 C/S框架网|原创作品.质量保障.竭诚为您服务

上一篇 下一篇