none
継承フォームのビューデザイナ表示について RRS feed

  • 質問

  • visual studio 2017 community で フォームアプリを開発しているのですが、

    ビューデザイナの表示に関して不明点があり質問させて頂きます。

    親クラス[A] のコンストラクタにて カスタムコントロール[B] のインスタンスを生成しており、これを子クラス[C]が継承しています。

    [C]をビューデザイナで表示した際に、[B]がvisualstudioのウィンドウ外([B]のプロパティで設定しているLocation)

    に表示されてしまう現象が発生しているため、表示させない方法があればご教授ください。

    ※そもそもウィンドウ外に表示される時点でvsの不具合ではないかと思っていますが、、、

    2017年8月24日 8:27

回答

  • 難しいことは考えず、とりあえずBをShow/ShowDialogしているすべての箇所に以下のようなコードを仕込んでみれば、どうして表示されるのかわかるかもしれません。

    //Form Bのインスタンス = new B();
    MessageBox.Show(new System.Diagnostics.StackTrace().ToString());
    Bのインスタンス.ShowDialog();
    #たぶん何かのプロパティの変更からのイベントの連鎖で表示されているんだと思いますが

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

    2017年9月5日 9:22
  • [C]画面をデザイナで開こうとした際に[B]が起動してしまうとなると、
    以下のどちらかだと思います。(何回か前の書き込みでも触れましたが)
    1.[A]のコンストラクタにおいてメソッド[α]を呼んでしまっている。
    2.[A]のLoadイベントにおいてメソッド[α]を呼んでしまっている。
    ※基底クラス画面のコンストラクタ及びLoadイベントは、派生クラス画面をデザイナで開く際にも発生します。

    メソッド[α]を呼び出す部分を

    if (!this.DesignMode)
    {
        メソッド[α]の呼び出し
    }
    としたらどうなりますか?
    2017年9月5日 9:27
  • 上記は、継承フォームでも該当するのでしょうか?

    はい。
    下の図は Form1 のコンストラクタにメッセージボックスを埋め込み、継承フォームを作成しようとした直後にメッセージが表示される様子です。

    本当は、[C]のDesignModeプロパティを基準に[A]コンストラクタ内での[B]インスタンス生成を制御したのですが。。。

    DesignMode プロパティは自分で判断するのではなく、外部から Site プロパティを設定することで効力を発揮する設計・実装になっています。
    よって、コンストラクタ時点では「Site プロパティを外部から設定しようがない」ので、コンストラクタでは DesignMode プロパティは false 固定となります。
    (残念ながら、コンストラクタで DesignMode プロパティや Site プロパティを使う方が悪いと言うことになります)

    2017年9月7日 21:42
    モデレータ
  • 確かに、
    コンストラクタ内にMessageBox.Showを埋め込みリビルド→デザイナを開く
    という手順で、デザイナを開くだけでコンストラクタ内のコードが実行されていることが確認できました。

    今回は、本現象の原因が見えないところにあるリスクを回避するため実装方法自体を変更しました。
    原因は判明しませんでしたが、いろいろと勉強になりました。
    返信くださった皆様ありがとうございました。

    • 回答としてマーク cicilala 2017年9月14日 0:55
    2017年9月14日 0:49

すべての返信

  • いくつか確認させて下さい。

    1.「フォームアプリを開発」とありますが、Windowsフォームでよろしいですか?
    2.「カスタムコントロール[B] のインスタンスを生成しており」とありますが、生成及び配置でよろしいですか?
    3.「[C]をビューデザイナで表示」とありますが、Windowsフォームデザイナーでよろしいですか?
    4.「[B]がvisualstudioのウィンドウ外」とありますが、Windowsフォームデザイナーのウインドウですか?
      (言葉の通り受け取るとVisualStudio自体のウインドウ外と見えるのですがそうではないですよね?)

    上記の内容が全て想定通りだったとしてですが、
    「[C]をビューデザイナで表示した際に、[B]がvisualstudioのウィンドウ外([B]のプロパティで設定しているLocation)」
    は当たり前に見えます。

    ([B]のプロパティで設定しているLocation)がFormサイズより大きいだけですよね?
    この場合にForm外に描画されるのはvsの不具合ではなく実装者のバグです。

    以上、見当違いでしたら申し訳ありません。

    2017年8月24日 12:08
  • 言葉足らずで申し訳有りません。

    1.「フォームアプリを開発」とありますが、Windowsフォームでよろしいですか?
    > Windowsフォームです。

    2.「カスタムコントロール[B] のインスタンスを生成しており」とありますが、生成及び配置でよろしいですか?
    > [B]はSystem.Windows.Formを継承したクラスで、[A]のコンストラクタ内ではインスタンス生成のみ
      行っており、ShowDialogメソッド等を呼び出している訳ではありません。

    3.「[C]をビューデザイナで表示」とありますが、Windowsフォームデザイナーでよろしいですか?
    > Windowsフォームデザイナーで間違い有りません。(ソースを選択し、Shift+F7で表示)

    4.「[B]がvisualstudioのウィンドウ外」とありますが、Windowsフォームデザイナーのウインドウですか?
      (言葉の通り受け取るとVisualStudio自体のウインドウ外と見えるのですがそうではないですよね?)
    > 言葉の通り、VisualStudio自体のウインドウ外です。デザイナの枠に収まっていないという意味ではありません。


    説明不足な点がありましたらご指摘ください。

    2017年8月25日 2:24
  • 2.「カスタムコントロール[B] のインスタンスを生成しており」とありますが、生成及び配置でよろしいですか?
    > [B]はSystem.Windows.Formを継承したクラスで、[A]のコンストラクタ内ではインスタンス生成のみ
      行っており、ShowDialogメソッド等を呼び出している訳ではありません。

    カスタムコントロール[B]の話です。[C]の話ではないのですが、本当に生成のみですか?
    ※配置という表現がまずかったかもしれません(すみません)が、[A]フォーム.Controls.Addしていませんか?

    4.「[B]がvisualstudioのウィンドウ外」とありますが、Windowsフォームデザイナーのウインドウですか?
      (言葉の通り受け取るとVisualStudio自体のウインドウ外と見えるのですがそうではないですよね?)
    > 言葉の通り、VisualStudio自体のウインドウ外です。デザイナの枠に収まっていないという意味ではありません。

    VisualStudio自体のウインドウ外に表示されてしまうって事ですか?
    申し訳無いのですが、ちょっと現象がイメージ出来ません。
    お手数をお掛けしますが、実際の画面のキャプチャーをアップして頂きたいです。

    2017年8月29日 9:23
  • カスタムコントロール[B]の話です。[C]の話ではないのですが、本当に生成のみですか?
    ※配置という表現がまずかったかもしれません(すみません)が、[A]フォーム.Controls.Addしていませんか?


    [B]はFormを継承したクラスですので、Controls.Addはしていません。

    VisualStudio自体のウインドウ外に表示されてしまうって事ですか?
    申し訳無いのですが、ちょっと現象がイメージ出来ません。
    お手数をお掛けしますが、実際の画面のキャプチャーをアップして頂きたいです。


    画像の添付権限の申請に時間がかかりました。。。
    下図が本事象の発生状態です(赤枠部)。

    ※秘情報にあたる箇所は伏せさせていただいています。

    2017年8月31日 1:18
  • [B]はFormを継承したクラスですので、Controls.Addはしていません。

    ご自身の書き込みを読み返してください。
    当初は、

    親クラス[A] のコンストラクタにて カスタムコントロール[B] のインスタンスを生成しており、これを子クラス[C]が継承しています。

    とあったのを拠り所に不明点を確認させて頂いております。(カスタムコントロール[B]と明記されています)

    ちなみに、キャプチャー頂いた部分の赤枠の部分と右の画像が一切繋がらないのですが、おそらく[C]画面のインスタンスであろう赤枠の画面に出ている文字列は、右側の[C]画面のデザイナ上におけるどのコントロールが出てしまっていると思われますか?

    「どうしたいのに、どうなってしまう」や、「どうしたいがどこが間違っているか」という具体性が無いと回答は得にくいと思います。
    ※「具体的に書いている」と思っているかもしれませんが、正直な所全然わかりません。

    もしかして、「[C]のサイズがデザイナ表示時よりも実行時の方が小さい」事が関わっていて、基底クラスのLoadイベントは派生クラスのデザイン表示時にも発生するのを考慮していないとかが影響しているのかなぁ・・・

    2017年9月1日 6:20
  • カスタムコントロールという表現は誤りで、[B]はメッセージボックスを独自の仕様で表示する

    System.Windows.Formを継承した派生クラスです。

    誤解を招き申し訳有りません。当方、Windowsフォームアプリ開発初心者のためご容赦ください。。。

    改めて説明させていただくと、A~Cは以下のようなクラスです。

     [A]:System.Windows.Formを継承した本アプリの画面基底クラス

     [B]:System.Windows.Formを継承したメッセージボックス表示用クラス、[A]コンストラクタ内でインスタンス生成される

     [C]:[A]を継承した各画面クラス

    「どうしたいのに、どうなってしまう」や、「どうしたいがどこが間違っているか」という具体性が無いと回答は得にくいと思います。 ※「具体的に書いている」と思っているかもしれませんが、正直な所全然わかりません。

    やりたいこと:メッセージボックスの表示に際し、独自のロジックを噛ませたいだけ

    知りたいこと①:そもそも"やりたいこと"を成すための実装方法がおかしいのかどうか(実装方法として妥当かではなく、バグを作りこんでいるのか、という観点で"おかしい"のかどうか)

    知りたいこと②:このような作りの場合、添付画像のように[C]のデザイン表示時に[B]のデザインがvisualStudioのウィンドウ枠外に表示されてしまうのが当たり前なのか

    技術も知識も乏しく拙い文章で申し訳ないです。

    2017年9月5日 3:08
  • やっと分かったかもしれません!!

    関係性としては以下で良いですか?
    [A] スタートアップフォームとして起動する各種画面[C]のスーパークラス
    [B] メッセージ表示用の画面クラス([A]のコンストラクタでインスタンス生成され、[C]のデザイン表示時に起動する)
    [C] [A]を継承した各種画面

    対応ですが、[B]をShowDialogで起動しているのであれば、
    [B]のStartupPositionプロパティをCenterParentにしたらいかがでしょうか?
    ※これが初期値のWindowsDefaultLocationになっている事が今回の原因だと思われます。

    ・・・これも見当違いでしたらまたまたすみません


    • 編集済み aviator__ 2017年9月5日 3:19
    2017年9月5日 3:18
  • 関係性としては以下で良いですか?
    [A] スタートアップフォームとして起動する各種画面[C]のスーパークラス
    [B] メッセージ表示用の画面クラス([A]のコンストラクタでインスタンス生成され、[C]のデザイン表示時に起動する)
    [C] [A]を継承した各種画面
    上記に関して"[C]のデザイン表示時に起動する"という点のみ認識異なります。

    情報が小出しで申し訳ないのですが、
    以下が[B]の起動ロジック(のつもり)となっております。

      [A]のメソッド[α]内で以下を記述
        [B]のインスタンス.StartPosition = FormStartPosition.CenterParent;
        [B]のインスタンス.ShowDialog();

      [α]の呼び出しはの画面[C]のボタン押下イベント内に記述
      ※[C]のLoadイベントではありません。

    しかしながら、本現象は[α]の呼び出しを行っていない画面[C]をデザイナで開いた際にも発生します。

    対応ですが、[B]をShowDialogで起動しているのであれば、
    [B]のStartupPositionプロパティをCenterParentにしたらいかがでしょうか?
    起動方法については前述の通りで、[B]のStartPositionプロパティは
    [B].Designer.cs内でCenterParentに設定しています。


    あくまで、アプリ実行中に特定の画面で特定のボタンを押下した際にのみ
    [B]が開いて欲しいというのが思いで、開発中に画面[C]をデザイナで表示した際に、
    [B]が表示されてしまうこと自体が無知な私にとっては想定外の現象です。

    visualStudioでデザイナを開いた際に内側で何が行われているのか
    詳しく認識できていないのですが、少なくとも[A]および[C]のDesigner.cs内に
    [B]に関する記述はなく、ロードイベント内でShowDialogをコールしている訳でも
    ないので、表示されてしまう理由に検討がつかない状況です。

    aviator__さんが見当違いなのではなく、そもそも当方のアプリの作りがダメなのだと思います。。。
    ビルドは正常に通りますし、生成されたexeを起動しても想定通りの動作をするのですが
    あまりにも不可思議で現状見えていない潜在バグがあるのではと。。。

    長々とお付き合いいただき、またいろいろと検討いただきありがとうございました。
    勉強し直して、とりあえず現状の作りを直す方向で考えます。
    2017年9月5日 5:32
  • 難しいことは考えず、とりあえずBをShow/ShowDialogしているすべての箇所に以下のようなコードを仕込んでみれば、どうして表示されるのかわかるかもしれません。

    //Form Bのインスタンス = new B();
    MessageBox.Show(new System.Diagnostics.StackTrace().ToString());
    Bのインスタンス.ShowDialog();
    #たぶん何かのプロパティの変更からのイベントの連鎖で表示されているんだと思いますが

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

    2017年9月5日 9:22
  • [C]画面をデザイナで開こうとした際に[B]が起動してしまうとなると、
    以下のどちらかだと思います。(何回か前の書き込みでも触れましたが)
    1.[A]のコンストラクタにおいてメソッド[α]を呼んでしまっている。
    2.[A]のLoadイベントにおいてメソッド[α]を呼んでしまっている。
    ※基底クラス画面のコンストラクタ及びLoadイベントは、派生クラス画面をデザイナで開く際にも発生します。

    メソッド[α]を呼び出す部分を

    if (!this.DesignMode)
    {
        メソッド[α]の呼び出し
    }
    としたらどうなりますか?
    2017年9月5日 9:27
  • Visual Studio のデザイナでは、自分が書いたコードが実行されることがあります。
    たとえば、以下のケースです。

    • ユーザーコントロールを自作し、それを他のフォームに貼り付けたとき(ユーザーコントロールのコードが Visual Studio 内で実行される)
    • 継承コントロールを作成し、そのデザイナを表示したとき(その継承元のコード)

    こういったケースで、コンストラクタ、描画処理、プロパティ設定・取得コードなどで、Visual Studio から実行されたくない場合は、すでに指摘のあるとおり、DesignMode プロパティをチェックする必要があります。

    なお、DesignMode プロパティはユーザーコントロールの中のユーザーコントロールなどの特定状況下では設定されないことがあります。
    その場合は、親をたどって調べる、実行プロセスが devenv.exe かどうかで判定するなど、さらなる工夫が必要です。

    // それがいやなら継承しないとか、ユーザーコントロールを使わないとかになります…。

    2017年9月5日 13:17
    モデレータ
  • gekkaさんのおっしゃる下記コードを、[A]コンストラクタ内の[B]インスタンス生成箇所前後①、

    メソッド[α]内の[B]インスタンス.ShowDialog()呼び出し前後②に差し込んだところ、

    ①の出力内容は前後で変化なし(内容はいまいちよく分かりませんでした。。。)、

    ②は出力されませんでした。(メソッド[α]はコンストラクタ・Loadイベント内でコールしていないため)

    MessageBox.Show(new System.Diagnostics.StackTrace().ToString());

    上記から、メソッド[α]および[B]に対するShowDialogメソッドは無関係と判断し、

    [A]コンストラクタ内の[B]インスタンス生成箇所をコメントアウトしたところ本現象は発生しませんでした。

    (当然かもしれませんが。。。)

    2017年9月6日 2:52
  • 1.[A]のコンストラクタにおいてメソッド[α]を呼んでしまっている。
    2.[A]のLoadイベントにおいてメソッド[α]を呼んでしまっている。

    上記2点どちらも該当しません。

    [A]コンストラクタ内で実行している内容としては以下2点となります。

      ①InitializeComponent()呼び出し

      ②[B]インスタンス生成

    ①に関しては、デザイナ用の各種コンポーネントの初期化を実施しているだけで、

    メソッド内をすべて確認しましたが、メソッド[α]の呼び出しに繋がるような記述はありませんでした。

    if (!this.DesignMode) の挿入箇所については、

    メソッド[α]の呼び出しは一部の画面でしか行っておらず、

    メソッド[α]の呼び出しを行わない画面[C]にて検証を行っているため、以下の箇所に挿入し検証してみました。

      ・[A]コンストラクタ内の[B]インスタンス生成箇所

      ・メソッド[α]内の[B]インスタンス.ShowDialog()呼び出し箇所

    結果、どちらも解消には繋がりませんでした。

    (調べてみるとコンストラクタ内部ではデザインモードの取得は正しく行われないらしい。。。)

    2017年9月6日 3:03
  • Visual Studio のデザイナでは、自分が書いたコードが実行されることがあります。
    たとえば、以下のケースです。

    • ユーザーコントロールを自作し、それを他のフォームに貼り付けたとき(ユーザーコントロールのコードが Visual Studio 内で実行される)
    • 継承コントロールを作成し、そのデザイナを表示したとき(その継承元のコード)

    上記は、継承フォームでも該当するのでしょうか?

    なお、DesignMode プロパティはユーザーコントロールの中のユーザーコントロールなどの特定状況下では設定されないことがあります。
    その場合は、親をたどって調べる、実行プロセスが devenv.exe かどうかで判定するなど、さらなる工夫が必要です。

    実行プロセス自体はdevenv.exeのようなので、

    これを見て判定する手法が確実かもしれませんのでちょっと調べてみます。

    本当は、[C]のDesignModeプロパティを基準に[A]コンストラクタ内での[B]インスタンス生成を制御したのですが。。。

    2017年9月6日 4:14
  • 上記は、継承フォームでも該当するのでしょうか?

    はい。
    下の図は Form1 のコンストラクタにメッセージボックスを埋め込み、継承フォームを作成しようとした直後にメッセージが表示される様子です。

    本当は、[C]のDesignModeプロパティを基準に[A]コンストラクタ内での[B]インスタンス生成を制御したのですが。。。

    DesignMode プロパティは自分で判断するのではなく、外部から Site プロパティを設定することで効力を発揮する設計・実装になっています。
    よって、コンストラクタ時点では「Site プロパティを外部から設定しようがない」ので、コンストラクタでは DesignMode プロパティは false 固定となります。
    (残念ながら、コンストラクタで DesignMode プロパティや Site プロパティを使う方が悪いと言うことになります)

    2017年9月7日 21:42
    モデレータ
  • 確かに、
    コンストラクタ内にMessageBox.Showを埋め込みリビルド→デザイナを開く
    という手順で、デザイナを開くだけでコンストラクタ内のコードが実行されていることが確認できました。

    今回は、本現象の原因が見えないところにあるリスクを回避するため実装方法自体を変更しました。
    原因は判明しませんでしたが、いろいろと勉強になりました。
    返信くださった皆様ありがとうございました。

    • 回答としてマーク cicilala 2017年9月14日 0:55
    2017年9月14日 0:49