4

複数のフォームを持つ大規模なアプリケーションで、WinForms を使用して C# で作業しています。

いくつかの時点で、進行状況画面として別のフォームが表示されます。UI スレッドをフリーズできないため、新しいフォームを新しいスレッドで開始する必要があります。フォームの起動に使っprogressform.ShowDialog()ていますが、新規スレッドなので、クリックAlt + Tabでメインフォームに戻ることができます。これを無効にしたい。

私の考えでは、mainForm.GotFocusイベントに EventHandler を配置し、表示されている場合はフォーカスをリダイレクトできprogressFormます。ただし、GotFocusアプリケーションを切り替えたり、 と の間を移動したりしてもprogressForm、イベントはトリガーされませんmainFormmainFormフォーム自体ではなく、一部の要素にフォーカスがあるためだと思います。

これを行うためのより良い方法を誰かが知っている場合 (私は EventHandler アプローチにコミットしていません)、または EventHandler アプローチの作業コードを知っていれば、問題は解決します。

編集

コメントの通り、Activatedイベントを使ってみました。

// in InitializeForm()
this.Activated += FocusHandler;

// outside of InitializeForm()
void FocusHandler(object sender, EventArgs e)
{
    if (ProgressForm != null)
    {
        ProgressForm.Focus();
    }
}

それでも、クリックしてメイン フォームに戻り、ボタンをクリックすることはできました。

4

1 に答える 1

0

私はいくつかの方法を試してみましたが、これはあなたが望むように機能することがわかりました。全体的なアイデアは、進行状況フォームが表示されたときにメイン UI からいくつかのメッセージをフィルタリングすることです:

public partial class Form1 : Form
{
    [DllImport("user32")]
    private static extern int SetForegroundWindow(IntPtr hwnd);        
    public Form1()
    {
        InitializeComponent();            
    }
    ChildUI child = new ChildUI();
    bool progressShown;
    IntPtr childHandle;
    //I suppose clicking on the button1 on the main ui form will show a progress form.
    private void button1_Click(object sender, EventArgs e)
    {
        if(!progressShown)
           new Thread(() => { progressShown = true; childHandle = child.Handle; child.ShowDialog(); progressShown = false; }).Start();
    }
    protected override void WndProc(ref Message m)
    {
        if (progressShown&&(m.Msg == 0x84||m.Msg == 0xA1||m.Msg == 0xA4||m.Msg == 0xA3||m.Msg == 0x6))  
        //0x84:  WM_NCHITTEST
        //0xA1:  WM_NCLBUTTONDOWN
        //0xA4:  WM_NCRBUTTONDOWN 
        //0xA3   WM_NCLBUTTONDBLCLK   //suppress maximizing ...
        //0x6:   WM_ACTIVATE         //suppress focusing by tab...
        {
            SetForegroundWindow(childHandle);//Bring your progress form to the front
            return;//filter out the messages
        }
        base.WndProc(ref m);
    }
}

プログレス フォームを通常どおり (ダイアログではなく) 表示したい場合は、 を使用してApplication.Run()通常どおりにフォームを表示 ( を使用Show()) while ループを処理せずに、フォームを表示した直後にフォームを終了します。

private void button1_Click(object sender, EventArgs e)
    {
        //progressShown = true;
        //child.Show();
        if (!progressShown)
        {                
            new Thread(() => {
                progressShown = true;
                if (child == null) child = new ChildUI();
                childHandle = child.Handle;
                Application.Run(child);
                child = null;
                progressShown = false;
            }).Start();
        }
    }

私はテストしましたが、それは魅力のように機能します。

于 2013-06-26T02:35:04.290 に答える