none
C# モーダルのダイアログの子画面が親画面の背面に移動してしまう場合がある。 RRS feed

  • 質問

  • モーダルのダイアログ画面(子画面)が、親画面の背面に移動してしまう場合があります。

    モーダルの場合、子画面は必ず親画面の前面に表示されると思っていたのですが、
    親画面の背面に移動することを、避けることはできませんか?

    発生するのは、以下の条件です。
    ・モーダルのダイアログ画面。
    ・印刷を2回実行。
    ・リモートデスクトップ。
    (リモートデスクトップ先の画面から、リモートデスクトップ元のプリンタに印刷。)

    [親画面のソースコード]
    using System;
    using System.Windows.Forms;
    namespace WindowsFormsApp3
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
            private void button1_Click(object sender, EventArgs e)
            {
                Form2 f = new Form2();
                f.ShowDialog(this);
            }
        }
    }

    [子画面のソースコード]
    using System;
    using System.Drawing;
    using System.Windows.Forms;
    namespace WindowsFormsApp3
    {
        public partial class Form2 : Form
        {
            public Form2()
            {
                InitializeComponent();
            }
            private void button1_Click(object sender, EventArgs e)
            {
                MyPrint();
                MyPrint();
            }
            private void MyPrint()
            {
                //PrintDocumentオブジェクトの作成
                System.Drawing.Printing.PrintDocument pd = new System.Drawing.Printing.PrintDocument();
                //PrintControllerプロパティをStandardPrintControllerに
                pd.PrintController = new System.Drawing.Printing.StandardPrintController();
                //PrintPageイベントハンドラの追加
                pd.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(pd_PrintPage);
                //印刷を開始する
                pd.Print();
            }
            private void pd_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
            {
                //画像を読み込む
                Image img = Image.FromFile("test.bmp");
                //画像を描画する
                e.Graphics.DrawImage(img, e.MarginBounds);
                //次のページがないことを通知する
                e.HasMorePages = false;
                //後始末をする
                img.Dispose();
            }
        }
    }

    2019年9月17日 13:06

すべての返信

  • BringToFront() か Active() を書くと、いけたような気がします。


    子画面:
    public Form2()
    {
        InitializeComponent();
    
        // コンストラクタか、Load か、Shown に書きます。Shown イベントかな
        this.BringToFront();
        this.Activate();
    }


    • 回答としてマーク okakenx 2019年9月18日 21:24
    • 回答としてマークされていない okakenx 2019年9月18日 21:24
    2019年9月18日 1:13
  • 早速の回答ありがとうございます。
    説明不足でした。
    背面に移動するのは、
    Form2画面の表示時ではなく、
    Form2画面の印刷ボタン押下後にです。(button1_Click)
    • 回答としてマーク okakenx 2019年9月18日 21:24
    • 回答としてマークされていない okakenx 2019年9月18日 21:24
    2019年9月18日 9:52
  • okakenxさん、こんにちは。フォーラムオペレーターのHarukaです。
    MSDNフォーラムにご投稿くださいましてありがとうございます。

    私のテストでは、問題を再現できませんでした。 また、モーダルダイアログは親画面の後ろに移動すべきではないと思います。
    モーダルフォームとは何かを説明するForm.Modal Propertyについて詳しく知ることをお勧めします。

    どうぞよろしくお願いします。


    MSDN/ TechNet Community Support Haruka

    ~参考になった投稿には「回答としてマーク」をご設定ください。なかった場合は「回答としてマークされていない」も設定できます。同じ問題で後から参照した方が、情報を見つけやすくなりますので、
    ご協力くださいますようお願いいたします。また、MSDNサポートに賛辞や苦情がある場合は、MSDNFSF@microsoft.comまでお気軽にお問い合わせください。~

    2019年9月19日 8:13
    モデレータ
  • 回答ありがとうございます。
    確かに再現性なしです。(再現率は10%未満)
    「リモートデスクトップ」という特殊な環境で、
    印刷負荷が高く画面が固まりやすい時に再現しやすいです。

    2019年9月19日 10:34
  • リモートデスクトップだったかリモートアップだったか、両方だったか忘れましたが、自分も昔そういう問題の対応をした覚えがあります。


    MyPrint() メソッドの一番最後とか、戻したいタイミングの場所に書いてもダメですか?
    TopMost プロパティも混ぜてみました。
    (Windows API もあるけど)

    private void MyPrint()
    {
        ~
        
        //印刷を開始する
        pd.Print();
        
        BringToFront();
        Activate();
        TopMost = false;
        TopMost = true;
        TopMost = false;
    }

    DoEvents(); も入れたかもしれません・・・。

    参考
    フォームが別アプリケーションの後ろに隠れてしまう
    https://social.msdn.microsoft.com/Forums/ja-JP/ad87c390-461e-4c49-b9a7-28a19491838f/12501124571254012512123642102912450125031252212465125401247112?forum=vbgeneralja

    2019年9月19日 14:41
  • okakenxさん、こんにちは。フォーラムオペレーターのHarukaです。
    ご返信いただきありがとうございます。

    >「リモートデスクトップ」という特殊な環境で、
    →「リモートデスクトップ」について詳しく教えていただけますでしょうか。 
    また、2つの提案があります。
    まず、環境を変更して同じことを行い、動作するかどうかを確認することをお勧めします。
    次に、ブレークポイントを設定して、どの行が機能していないかを確認することをお勧めします。

    どうぞよろしくお願いします。


    MSDN/ TechNet Community Support Haruka

    ~参考になった投稿には「回答としてマーク」をご設定ください。なかった場合は「回答としてマークされていない」も設定できます。同じ問題で後から参照した方が、情報を見つけやすくなりますので、
    ご協力くださいますようお願いいたします。また、MSDNサポートに賛辞や苦情がある場合は、MSDNFSF@microsoft.comまでお気軽にお問い合わせください。~

    2019年9月20日 8:31
    モデレータ
  • ゴーストウィンドウ(ウィンドウが白くなって応答なしと表示され、Windows が代わりに表示するダミーのウィンドウ)になっている場合、Z オーダー(前後関係)が変わってしまう可能性があります。
    基本的には応答なしにならない、メインスレッドで処理しっぱなしにしないことが望ましいです。

    たとえば、button1_Click の中で数秒以上かかる処理をずっと実行している(極端な例:Thread.Sleep(10000) )と「応答なし」と表示され、問題が起きるかもしれません。
    これが原因だったとしたら、基本的には、メインスレッドで処理しっぱなしにならないように設計・実装を気をつけるしかありません。

    2019年9月20日 13:13
    モデレータ
  • sutefu7さん、回答ありがとうございます。
    BringToFront();Activate();TopMost等は、どこの場所に書いても背面移動発生しましたが、
    Application.DoEvents();を書いたら、背面移動発生しなくなりました。
    再現性ないので、もしかしたら1万回に1回発生するかもしれませんが、
    少なくとも発生する確率は格段に減りました。ありがとうございます。
    あとは、なぜ発生しなくなったのか、説明がつけばいいのですが。

    Haruka6002さん、回答ありがとうございます。
    「リモートデスクトップ」は、
    リモートデスクトップ元が、Windows7Professional(64bit)またはWindows10Professional(64bit)
    リモートデスクトップ先が、WindowsServer2016(64bit)です。
    「リモートデスクトップ」でない環境では、背面移動発生しません。
    教えて頂いた2つの提案を参考にさせて頂きます。
    現実的には、前出のApplication.DoEvents();でしのぐつもりです。

    Azuleanさん、回答ありがとうございます。
    ご指摘の通り、別スレッドにするのが理想かもしれません。
    ただ、それほど厳密なシステムでもないので、
    現実的には、前出のApplication.DoEvents();でしのぐつもりです。

    2019年9月20日 13:37
  • okakenxさん、こんにちは。フォーラムオペレーターのHarukaです。
    ご返信いただきありがとうございます。

    >リモートデスクトップ元が、Windows7Professional(64bit)またはWindows10Professional(64bit)
    リモートデスクトップ先が、WindowsServer2016(64bit)です。
    →デスクトップのソースとデスクトップの宛先を使用する理由は何ですか。
    モーダルフォームとメイン画面フォームは同じアプリ内にあるべきだと思われますが、もしそうなら、なぜ2つの異なる環境を使用するのですか。

    上記の情報をご提供いただければ、問題をより良く解決できる可能性があります。

    どうぞよろしくお願いします。


    MSDN/ TechNet Community Support Haruka

    ~参考になった投稿には「回答としてマーク」をご設定ください。なかった場合は「回答としてマークされていない」も設定できます。同じ問題で後から参照した方が、情報を見つけやすくなりますので、
    ご協力くださいますようお願いいたします。また、MSDNサポートに賛辞や苦情がある場合は、MSDNFSF@microsoft.comまでお気軽にお問い合わせください。~

    2019年9月24日 8:27
    モデレータ
  • Haruka6002さん、回答ありがとうございます。
    > デスクトップのソースとデスクトップの宛先を使用する理由は何ですか。
    に関してですが、
    当該exeが動作する環境が、リモートデスクトップ先にしかなく、
    各担当者は、リモートデスクトップで、それを使用するシステムであるからです。
    なお、pd.Print();する印刷先は、各担当者の手元(リモートデスクトップ元)のプリンターです。
    > モーダルフォームとメイン画面フォームは同じアプリ内にあるべきだと思われますが、もしそうなら、なぜ2つの異なる環境を使用するのですか。
    に関してですが、
    誤解を招いてしまったようです。
    モーダルフォームとメイン画面フォームは同じアプリ内です。
    2019年10月5日 12:36
  • okakenxさん、こんにちは。フォーラムオペレーターのHarukaです。
    ご返信いただきありがとうございます。

    すみませんが、問題がよく把握できませんので、
    英語となりますが、https://social.msdn.microsoft.com/Forums/vstudio/en-US/home?forum=csharpgeneralまでご投稿いただくこともご検討ください。

    どうぞよろしくお願いいたします。


    MSDN/ TechNet Community Support Haruka
    ~参考になった投稿には「回答としてマーク」をご設定ください。なかった場合は「回答としてマークされていない」も設定できます。同じ問題で後から参照した方が、情報を見つけやすくなりますので、 ご協力くださいますようお願いいたします。また、MSDNサポートに賛辞や苦情がある場合は、MSDNFSF@microsoft.comまでお気軽にお問い合わせください。~

    2019年10月21日 2:46
    モデレータ