none
1つのツールボックスから2つのコントロール・コンポーネントを作成したい RRS feed

  • 質問

  • グレープシティ製のSPREAD for Windows Forms(以下SPREAD)がそうだったのですが、
    1つのコントロールをツールボックスから選択してフォーム上へ設置した瞬間に、
    選択したコントロールに加えてコンポーネントを1つ設置したいです。

    SPREADでは、コントロール(FpSpread)を設置すると、自動的にコンポーネント(SheetView)が
    作成され、コントロールのシート要素としてコンポーネントが追加されます。

    コントロールが設置された時に設置されたフォームを取得してコンポーネントを追加すれば
    いいのかなとは思いますが、そのようなタイミングはどこでコードすればよいのでしょうか?

    2013年7月19日 2:18

回答

  • こんな?

    public class TestDesigner : System.Windows.Forms.Design.ControlDesigner
    {
        public override void InitializeNewComponent(System.Collections.IDictionary defaultValues)
        {
            base.InitializeNewComponent(defaultValues);
    
            //System.Diagnostics.Debugger.Launch();
            if (defaultValues.Contains("Parent") && defaultValues["Parent"] is System.ComponentModel.IComponent)
            {
                System.ComponentModel.IComponent component = (System.ComponentModel.IComponent)defaultValues["Parent"];
                if (component.Site != null)
                {
                    var host = (System.ComponentModel.Design.IDesignerHost)component.Site.GetService(typeof(System.ComponentModel.Design.IDesignerHost));
                    if (host != null)
                    {
                        //コンポーネントとしてシリアルポートを追加してみる
                        var port = (System.IO.Ports.SerialPort)host.CreateComponent(typeof(System.IO.Ports.SerialPort));
    
                        //ついでにおまけのボタンも追加してみる
                        if(component is Control)
                        {
                            var button2 =(Button) host.CreateComponent(typeof(Button));
                            button2.Text = "ぼたん2";
                            if (this.Control != null)
                            {
                                button2.Left = this.Control.Left + Control.Width;
                                button2.Top = this.Control.Top;
                            }
    
                            ((Control)component).Controls.Add(button2);
                        }
                    }
                }
            }
        }
    }
    
    [System.ComponentModel.DesignerAttribute(typeof(TestDesigner))]
    class TestButton : Button
    {
    }

    タイミングとかは以前の「コンポーネントを配置した瞬間を判断したい」でAzuleanさんがヒントになること書いてますよね。
    あとはIDesignerHostを得る方法がわかれば追加する方法も見えてくるんじゃないかな。

    別解としてこんなのも

    public class X : Button
    {
        public X()
        {
            if (Environment.StackTrace.Contains("System.Windows.Forms.Design.ControlDesigner"))
            {
                this.ParentChanged += new EventHandler(X_ParentChanged);
            }
        }
    
        void X_ParentChanged(object sender, EventArgs e)
        {
            if (this.Parent != null)
            {
                this.ParentChanged -= X_ParentChanged;
                var component = this.Parent as IComponent;
                if (component != null && component.Site != null && component.Site.DesignMode)
                {
                    var host = (System.ComponentModel.Design.IDesignerHost)component.Site.GetService(typeof(System.ComponentModel.Design.IDesignerHost));
                    if (host != null)
                    {
                        var txb = (TextBox)host.CreateComponent(typeof(TextBox));
                        this.Parent.Controls.Add(txb);
                    }
                }
            }
        }
    }


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)


    • 編集済み gekkaMVP 2013年7月19日 14:18 2個目のコードのイベント解除ミス修正
    • 回答の候補に設定 AzuleanMVP, Moderator 2013年7月20日 0:58
    • 回答としてマーク takiru 2013年7月20日 9:01
    2013年7月19日 11:11

すべての返信

  • こんな?

    public class TestDesigner : System.Windows.Forms.Design.ControlDesigner
    {
        public override void InitializeNewComponent(System.Collections.IDictionary defaultValues)
        {
            base.InitializeNewComponent(defaultValues);
    
            //System.Diagnostics.Debugger.Launch();
            if (defaultValues.Contains("Parent") && defaultValues["Parent"] is System.ComponentModel.IComponent)
            {
                System.ComponentModel.IComponent component = (System.ComponentModel.IComponent)defaultValues["Parent"];
                if (component.Site != null)
                {
                    var host = (System.ComponentModel.Design.IDesignerHost)component.Site.GetService(typeof(System.ComponentModel.Design.IDesignerHost));
                    if (host != null)
                    {
                        //コンポーネントとしてシリアルポートを追加してみる
                        var port = (System.IO.Ports.SerialPort)host.CreateComponent(typeof(System.IO.Ports.SerialPort));
    
                        //ついでにおまけのボタンも追加してみる
                        if(component is Control)
                        {
                            var button2 =(Button) host.CreateComponent(typeof(Button));
                            button2.Text = "ぼたん2";
                            if (this.Control != null)
                            {
                                button2.Left = this.Control.Left + Control.Width;
                                button2.Top = this.Control.Top;
                            }
    
                            ((Control)component).Controls.Add(button2);
                        }
                    }
                }
            }
        }
    }
    
    [System.ComponentModel.DesignerAttribute(typeof(TestDesigner))]
    class TestButton : Button
    {
    }

    タイミングとかは以前の「コンポーネントを配置した瞬間を判断したい」でAzuleanさんがヒントになること書いてますよね。
    あとはIDesignerHostを得る方法がわかれば追加する方法も見えてくるんじゃないかな。

    別解としてこんなのも

    public class X : Button
    {
        public X()
        {
            if (Environment.StackTrace.Contains("System.Windows.Forms.Design.ControlDesigner"))
            {
                this.ParentChanged += new EventHandler(X_ParentChanged);
            }
        }
    
        void X_ParentChanged(object sender, EventArgs e)
        {
            if (this.Parent != null)
            {
                this.ParentChanged -= X_ParentChanged;
                var component = this.Parent as IComponent;
                if (component != null && component.Site != null && component.Site.DesignMode)
                {
                    var host = (System.ComponentModel.Design.IDesignerHost)component.Site.GetService(typeof(System.ComponentModel.Design.IDesignerHost));
                    if (host != null)
                    {
                        var txb = (TextBox)host.CreateComponent(typeof(TextBox));
                        this.Parent.Controls.Add(txb);
                    }
                }
            }
        }
    }


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)


    • 編集済み gekkaMVP 2013年7月19日 14:18 2個目のコードのイベント解除ミス修正
    • 回答の候補に設定 AzuleanMVP, Moderator 2013年7月20日 0:58
    • 回答としてマーク takiru 2013年7月20日 9:01
    2013年7月19日 11:11
  • 大変具体的なご回答ありがとうございます。

    以前に「コンポーネントを配置した瞬間を判断したい」で教えて頂いた内容は把握していたのですが、
    何がなんだか明確に理解できておらず、どういう風に実装すればという状態でした。
    まだまだ分からないことが多いです。
    本日は確認ができない為、明日調べながら実装し、確認してみます。ありがとうございました。

    2013年7月19日 15:48