none
コントロールの継承クラスのコンストラクタに書いた内容がFormのデザイナに書き出される RRS feed

  • 質問

  • いつもお世話になっております。
    環境:WinXP、C#2.0 VS2005

    コントロールの継承クラスのコンストラクタに書いた内容がFormのデザイナに書き出される
    ことになっているかと思うのですが、この仕様が便利に思う時と不便に思う時があります。

    下のようにコンストラクタにカラムを追加してFormに貼り付けると、
    同じコードがFormのデザイナに書き出され、
    実行すると2重に走ってしまって1カラムのはずが2カラム出来てしまいます。

    コントロールに実行時のみ走るメソッドがあればいいのですが見当たりません。
    だからと言ってユーザーに初期化関数を呼ばせるのもどうかと思いますし。

    コンストラクタのコードがデザイナに書き出されない方法はありますでしょうか。
    宜しくお願い致します。



     public class DataGridViewSub : DataGridView
     {
      public int n;

      public DataGridViewSub()
      {
       n = 2;

       DataGridViewTextBoxColumn column = new DataGridViewTextBoxColumn();
       column.Name = "Column2";
       this.Columns.Add( column );
      }
     }



    2009年3月17日 8:42

回答

  • Myon さん の発言:

    下のようにコンストラクタにカラムを追加してFormに貼り付けると、
    同じコードがFormのデザイナに書き出され、
    実行すると2重に走ってしまって1カラムのはずが2カラム出来てしまいます。

    作成されたDataGridViewSubコントロールでColumnsプロパティはどうしたいのでしょうか?
    デザイナ上でさらにカラムを追加できるようにするのですか?コンストラクタで追加したカラムをデザイナで削除できても問題ないのですか?
    デザイナでどのようにあるべきかをよく考えて、それに合わせて整合性が保たれるように実装を考える必要があります。

    Myon さん の発言:

    コントロールに実行時のみ走るメソッドがあればいいのですが見当たりません。
    だからと言ってユーザーに初期化関数を呼ばせるのもどうかと思いますし。

    そういった主旨でDesignModeプロパティはありますが、このプロパティの使用には注意すべき点もあります。
    http://support.microsoft.com/kb/839202/

    Myon さん の発言:

    コンストラクタのコードがデザイナに書き出されない方法はありますでしょうか。
    宜しくお願い致します。

    その認識は正しくありません。
    コンストラクタで追加した要素が、Columnsプロパティの内容をDesigner.csに保存する際に書き込まれているだけです。
    デザイナで自作のクラスを貼り付けた場合、デザイナで自作クラスのコードが実行されますので、Columnsプロパティにはユーザが自分で追加したときと同じように、要素が登録されるわけですから、デザイナの動きとしては正当でしょう。

    設計として、Columnsプロパティをデザイナで編集させない、あるいは見せないといった時は、下記のようにnewキーワードで隠蔽することもできます。

    [System.ComponentModel.Browsable(false)]  
    [System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]  
    public new DataGridViewColumnCollection Columns  
    {  
        get 
        {  
            return base.Columns;  
        }  
    }  
     

    ※このほかに、EditorBrowsable属性といった似たような要素もありますが、省略します。
    解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。
    • 回答としてマーク sk7474 2009年4月6日 8:33
    2009年3月17日 14:30
    モデレータ
  • Myon さん の発言:

    ただ、コンストラクタで作ったカラムのインスタンスは
    やはりFormのデザイナ(InitializeComponent)の中に出てきてしまいます。
    これは仕方がないでしょうか。
    Columns.Addされていないので別に出てきてもいいのですが、
    これも出てこないようにすることは可能でしょうか。

    確かに先のコードだけだと不十分ですね。
    デザイナのプロパティウィンドウではColumnが2つ見える等の点で怪しいように感じました。
    デザイン時のサポートの拡張あたりに手を出さないといけないんだろうか…、朝はちょっと試せる時間がないです。申し訳ない。

    参考
    http://msdn.microsoft.com/ja-jp/library/37899azc.aspx

    Myon さん の発言:

    また、今回は完全隠蔽が目的なのでいいのですが、
    ユーザーにもデザイナ上でカラム追加させたい場合は
    どうなるのでしょうか。
    継承クラスのコンストラクタで1カラム追加、
    デザイナの自動コード生成で1カラム追加、
    ユーザーがデザイナで1カラム追加すると
    合計3カラムできてしまいます。
    この時想定しているのは2カラムです。

    現状はアイデアを持っていません。どうなるかを考えて見て下さい。
    # 先にもデザイナでどう動くか分からないと書きました。コンストラクタで追加した絡むが消せるとか。

    場合によっては、既定のColumnsプロパティを隠蔽し、ご自身で複雑な実装がいるかもしれません。

    解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。
    • 回答としてマーク sk7474 2009年4月6日 8:33
    2009年3月17日 22:25
    モデレータ
  • これ、本当にコンストラクタに必要なのでしょうか?

    本当にコンストラクタでやっているなら、デシリアライズのとき、コンストラクタでカラムが追加されたのち、どこかで削除するというような動きにならないでしょうか。本当に、そんな動きなのかな?

    また、DataGridView ですよね?View ですよね。何かを見せるためのものなのに、見せるはずの何かと違うものを構成するのって、どうでしょう?ここは、「カラムが1つで内容が null のデータ」がバインドされていると考えるほうが自然ではないでしょうか。


    というわけで、「無理にデータを作らなくていいのでは?」と思います。



    DesignMode のほうですが、どこで調べていますか?→件名:【VB.Net2008】Form継承時のデザイン表示について[Insider.NET 会議室](検索キー「designmode site:www.atmarkit.co.jp」)


    Jitta@わんくま同盟
    • 回答としてマーク sk7474 2009年4月6日 8:32
    2009年3月19日 10:35

すべての返信

  • Myon さん の発言:

    下のようにコンストラクタにカラムを追加してFormに貼り付けると、
    同じコードがFormのデザイナに書き出され、
    実行すると2重に走ってしまって1カラムのはずが2カラム出来てしまいます。

    作成されたDataGridViewSubコントロールでColumnsプロパティはどうしたいのでしょうか?
    デザイナ上でさらにカラムを追加できるようにするのですか?コンストラクタで追加したカラムをデザイナで削除できても問題ないのですか?
    デザイナでどのようにあるべきかをよく考えて、それに合わせて整合性が保たれるように実装を考える必要があります。

    Myon さん の発言:

    コントロールに実行時のみ走るメソッドがあればいいのですが見当たりません。
    だからと言ってユーザーに初期化関数を呼ばせるのもどうかと思いますし。

    そういった主旨でDesignModeプロパティはありますが、このプロパティの使用には注意すべき点もあります。
    http://support.microsoft.com/kb/839202/

    Myon さん の発言:

    コンストラクタのコードがデザイナに書き出されない方法はありますでしょうか。
    宜しくお願い致します。

    その認識は正しくありません。
    コンストラクタで追加した要素が、Columnsプロパティの内容をDesigner.csに保存する際に書き込まれているだけです。
    デザイナで自作のクラスを貼り付けた場合、デザイナで自作クラスのコードが実行されますので、Columnsプロパティにはユーザが自分で追加したときと同じように、要素が登録されるわけですから、デザイナの動きとしては正当でしょう。

    設計として、Columnsプロパティをデザイナで編集させない、あるいは見せないといった時は、下記のようにnewキーワードで隠蔽することもできます。

    [System.ComponentModel.Browsable(false)]  
    [System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)]  
    public new DataGridViewColumnCollection Columns  
    {  
        get 
        {  
            return base.Columns;  
        }  
    }  
     

    ※このほかに、EditorBrowsable属性といった似たような要素もありますが、省略します。
    解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。
    • 回答としてマーク sk7474 2009年4月6日 8:33
    2009年3月17日 14:30
    モデレータ
  •  ご回答ありがとうございました。

    今回はColumnsをユーザーにデザイナ上で触らせたくないため、
    Browsable(false)、
    DesignerSerializationVisibility.Hiddenにて解決いたしました。
    これにより2重にColumns.Addされることはなくなり、
    実行時に想定どおり1カラムのみ表示されるようになりました。

    ただ、コンストラクタで作ったカラムのインスタンスは
    やはりFormのデザイナ(InitializeComponent)の中に出てきてしまいます。
    これは仕方がないでしょうか。
    Columns.Addされていないので別に出てきてもいいのですが、
    これも出てこないようにすることは可能でしょうか。

    また、今回は完全隠蔽が目的なのでいいのですが、
    ユーザーにもデザイナ上でカラム追加させたい場合は
    どうなるのでしょうか。
    継承クラスのコンストラクタで1カラム追加、
    デザイナの自動コード生成で1カラム追加、
    ユーザーがデザイナで1カラム追加すると
    合計3カラムできてしまいます。
    この時想定しているのは2カラムです。

    DesignModeというのは調べましたが
    よくわかりませんでした。
    常にFalseを返すような気がします。

    EditorBrowsableはインテリセンスに出てこないのは
    困るので、今回は見送らせていただきました。




     

    2009年3月17日 16:33
  • Myon さん の発言:

    ただ、コンストラクタで作ったカラムのインスタンスは
    やはりFormのデザイナ(InitializeComponent)の中に出てきてしまいます。
    これは仕方がないでしょうか。
    Columns.Addされていないので別に出てきてもいいのですが、
    これも出てこないようにすることは可能でしょうか。

    確かに先のコードだけだと不十分ですね。
    デザイナのプロパティウィンドウではColumnが2つ見える等の点で怪しいように感じました。
    デザイン時のサポートの拡張あたりに手を出さないといけないんだろうか…、朝はちょっと試せる時間がないです。申し訳ない。

    参考
    http://msdn.microsoft.com/ja-jp/library/37899azc.aspx

    Myon さん の発言:

    また、今回は完全隠蔽が目的なのでいいのですが、
    ユーザーにもデザイナ上でカラム追加させたい場合は
    どうなるのでしょうか。
    継承クラスのコンストラクタで1カラム追加、
    デザイナの自動コード生成で1カラム追加、
    ユーザーがデザイナで1カラム追加すると
    合計3カラムできてしまいます。
    この時想定しているのは2カラムです。

    現状はアイデアを持っていません。どうなるかを考えて見て下さい。
    # 先にもデザイナでどう動くか分からないと書きました。コンストラクタで追加した絡むが消せるとか。

    場合によっては、既定のColumnsプロパティを隠蔽し、ご自身で複雑な実装がいるかもしれません。

    解決した場合は、参考になった返信に「回答としてマーク」のボタンを利用して、回答に設定しましょう(複数に設定できます)。
    • 回答としてマーク sk7474 2009年4月6日 8:33
    2009年3月17日 22:25
    モデレータ
  • これ、本当にコンストラクタに必要なのでしょうか?

    本当にコンストラクタでやっているなら、デシリアライズのとき、コンストラクタでカラムが追加されたのち、どこかで削除するというような動きにならないでしょうか。本当に、そんな動きなのかな?

    また、DataGridView ですよね?View ですよね。何かを見せるためのものなのに、見せるはずの何かと違うものを構成するのって、どうでしょう?ここは、「カラムが1つで内容が null のデータ」がバインドされていると考えるほうが自然ではないでしょうか。


    というわけで、「無理にデータを作らなくていいのでは?」と思います。



    DesignMode のほうですが、どこで調べていますか?→件名:【VB.Net2008】Form継承時のデザイン表示について[Insider.NET 会議室](検索キー「designmode site:www.atmarkit.co.jp」)


    Jitta@わんくま同盟
    • 回答としてマーク sk7474 2009年4月6日 8:32
    2009年3月19日 10:35
  •  ご回答ありがとうございました。
    返信が遅れまして申し訳ありませんでした。

    同じカラム構成のグリッドを複数の画面に出すことを考えております。
    グリッドのユーザーがデザイナに貼り付けただけで
    カラムが自動的に出来ると言うことで、
    コンストラクタでAddカラムしていますが、
    実行時にカラム数が倍になることが問題になっています。
    (DataTableのバインドは行わないと考えています)

    Azlean様
    >デザイン時のサポートの拡張あたりに手を出さないといけないんだろうか
    すみません、全く無知の領域なのでこれからの勉強が必要です。

    ># 先にもデザイナでどう動くか分からないと書きました。コンストラクタで追加した絡むが消せるとか。
    出来ればユーザーによるカラムのカスタマイズも可能にしたいので、
    隠蔽せずに済むならそのほうがいいと考えています。
    特にユーザーによるカラムの追加は将来ありえそうです。
    カラムの削除はユーザーに削除されてもそれなりに動くように作っています。
    また、多数のユーザーがいることも考えられますので、
    出来ればColumnsを隠蔽して、別のものでカスタマイズさせたり、
    ユーザーに外部メソッドを呼ばせたりするのは避けて、
    マニュアル不要の標準的な方法でカスタマイズ可能にしたいです。

    Jitta様
    >また、DataGridView ですよね?View ですよね。何かを見せるためのものなのに、見せるはずの何かと違うものを構成するのって、どうでしょう?ここは、「カラムが1つで内容が null のデータ」がバインドされていると考えるほうが自然ではないでしょうか。
    コンストラクタでカラムを登録すること自体まずいということでしょうか。
    決まったカラム構成の表を何枚も出したい時は
    どのようにするのがよいのでしょうか。

    >件名:【VB.Net2008】Form継承時のデザイン表示について
    リンクありがとうございました。
    質問者様と全く同じことをやっていました。
    コンストラクタの中ではDesignModeが常にfalseとのことなのですが、
    コンストラクタからタイマーを起動し、デザイナで見に行くと、
    DesignMode=trueであることが確認できました。
    理解は出来たのですが、使い道がよくわからない感じです。


     

    2009年3月21日 17:35
  • こんにちは。中川俊輔です。

    Azuleanさん、Jittaさん、回答ありがとうございます。

    Myonさん、フォーラムのご利用ありがとうございます。
    有用な情報と思われたため、Azuleanさん、Jittaさんの回答へ回答マークをつけさせていただきました。
    またなにかありましたら、新しく質問を投稿してみてください。

    今後ともフォーラムをよろしくお願いします。
    それでは!
    マイクロソフト株式会社 フォーラム オペレータ 中川 俊輔
    2009年4月6日 8:39
  • コンストラクタでカラムを登録すること自体まずいということでしょうか。
    決まったカラム構成の表を何枚も出したい時は
    どのようにするのがよいのでしょうか。

    登録するのはまずいと思います。そうすると、データをバインドすることができない事にならないでしょうか?(べつのデータも表示される)

    ですから、空(ダミー、デフォルト)のデータをバインドしてやればいいのではないでしょうか。



    コンストラクタの中ではDesignModeが常にfalseとのことなのですが、
    コンストラクタからタイマーを起動し、デザイナで見に行くと、
    DesignMode=trueであることが確認できました。

    当てずっぽうですが。

    コンストラクターは、オブジェクトができただけでコンテナーにリンクされていません。オブジェクトができただけの状態では、デザイン モード、つまりデザイナーがオブジェクトを作ったのか、実行モードなのか、わかるはずがありません。どちらなのかがわかるのは、コンテナーに登録され、そのコンテナーから「実はデザイナーなのだよ」と教えられたときではないでしょうか。

    タイマーを起動し、というのは、コンストラクターをすでに離れていますから、当然わかりますよね。


    Jitta@わんくま同盟
    2009年4月7日 12:43
  • Jitta様
    ご回答ありがとうございます。返信が遅れまして申し訳ありませんでした。

    カラムを先に登録しておいて、その後DataTableがバインドされたら、
    登録したカラムは残り、バインドしたカラムは後に追加されるという認識です。
    (カラム名が一致すればマージされる?)
    ですのでバインドしようと思えば出来るかと思うのですが、
    ここでのグリッドではテーブルのバインドは想定しておらず、
    ある決まったクラスのオブジェクトを投げ込むことで、
    それに相当する行を追加していくという動きになっています。(ぶっちゃけ、「通信ログ」です。)
    もちろん、テーブルにそのメソッドを設けることも出来ますが、
    サイズが大きくなるとバインドに時間がかかるため、避けています。
    ということで、とりあえずはユーザーにカラム作成メソッドを呼ばせるのが
    一番いいのかなという気がしてきています。

    DesignModeの件はお蔭様で理解できて来ました。
    ありがとうございます。

    2009年4月15日 3:02