に関連していますが、デザイナ表示関連で注意点。
デザイナ表示時にコンストラクタが動く
継承Formやコントロールを使っていると、時々デザイナが表示できない場合がある。
例外をたどるとForm1で例外が発生してるのは分かるんだけど、初めてこういう状況になると戸惑うんだよね。
結論として
継承フォームやコントロールは
デザイナで開く時にコンストラクタとコントロール描画に関連するイベントが実行される。
サンプルに挙げている例外は、継承フォームをデザイナモードで開いた時に発生しています。
実際のソースコードは以下のようになっている。
継承元 Form1
継承先 Form2
継承先コントロールでは何もしていないのにもかかわらず、
デザイナ実行時にはForm1のコンストラクタとForm1_Loadが実行されるので
ArrayListのキャストに失敗してデザイナの描画ができないというオチになってます。
(いちいち例外発生コードを書かなくてもthrowすればよかった)
上の例は極端だけど
例えばアプリケーション実行中にのみ実態が作られるオブジェクトを
親フォームのコンストラクタやイベントで参照してたりすると
「オブジェクト参照がオブジェクト インスタンスに設定されていません。」(NullReferenceException)
なんて訳の分からない状態になってしまうんですね。
解決策としては
1.デザインモードか判断し、デザイン時は実行させない。
2.デザイン時を判定する必要がないようにロジックを変更する。
の2点になるかと思うんですが、絶対的に2をお勧めしておきます。
デザインモードか判断し、デザイン時は実行させない。
サンプルコードの「//デザインモード時は実行しない」部分のコメントアウトを外すと
this.DesignModeプロパティによってコードを回避することができます。
が、このプロパティ、不良品のようで・・・
コンストラクタや入れ子になったコントロールでは常にfalseが返ってきます。
不安定なので使わないほうが良いでしょう。
デザインモード(this.DesignMode)を正しく得ることができない場合があります。
また、DesignModeプロパティのおかしな挙動回避のために
MSDNのフォーラムで回避策の模索がされているようです。
入れ子させた UserControl の DesignMode が false になるのを回避したい
結局のところ、
C# Tipsさんのところに記載しているような以下のようなロジックを自分で実装することになります。
メインはAppDomain.CurrentDomain.FriendlyNameプロパティでしょうか。
デザイン時に"DefaultDomain"を、ビルド実行時にはアセンブリファイル名を返すようで、
コンストラクタ内でもデザイン時か否かを判断できそうですが・・・
いやーな記事を発見。
デザイン時の判定、DefaultDomainではだめ
どうもClickOnceでばら撒いているとうまく動かないみたいです。
上記のコードの他の部分でうまく検証されていればいいのですが、裏が取れていません。
というわけで
コードによる回避のほうがよいのでしょう。
コードによる回避が正解とは言い切れないので、一応、私がはまってたこと。
デザイナを開くときに例外が発生して、デザインモードか調べて回避し、ビルド、
また別のイベントで例外が見つかってビルド・・・を繰り返していると時々
「サービス System.Windows.Forms.Design.IEventHandlerService は既にサービス コンテナーに存在します。パラメーター名: serviceType」
こんな例外が発生します。
こうなればもう少しw
Visual Studioを再起動すると、継承フォームのデザイナが見ることができます。
- ▼この記事を読んだ方は、こんな記事も読んでいます。▼
-
- PInvoke.net Visual Studio Extensionを使ってみた
- 【.NET】継承フォームのデザイナ表示時に例外が発生する【form】
- 【Visual Studio】シンボルの検索結果をすべて取得(コピー)する方法
- 【.NET】"&"(アンパサンド)が表示できない【C#】
- リソースファイルがソリューションエクスプローラ内でバラけて別れる(分裂する)