web-dev-qa-db-ja.com

C#で前面にフォームを表示する方法

皆さん、

他の方法では見えないアプリケーションからフォームを表示する方法を知っている人はいませんか?そしてフォーカスを取得します(つまり、他のウィンドウの上に表示されます)?私はC#.NET 3.5で作業しています。

私は「完全に間違ったアプローチ」をとったのではないかと疑っています...私はnotApplication.Run(new TheForm( ))代わりにI(new TheForm())。ShowModal()...フォームは基本的にモーダルダイアログであり、いくつかのチェックボックスがあります。テキストボックス、および[OK]ボタンと[キャンセル]ボタン。ユーザーはチェックボックスにチェックを入れ、説明(または何でも)を入力して[OK]を押すと、フォームが消え、プロセスはフォームからユーザー入力を読み取り、破棄して処理を続行します。

これは機能しますが、フォームが表示されているときはフォーカスを取得できず、代わりにタスクバー(または何でも)をクリックするまで「ホスト」アプリケーションの背後に表示されます。これは最も厄介な動作であり、多くの「サポートコール」が発生すると予測します。また、既存のVB6バージョンにはこの問題がないため、ユーザビリティが逆になります。また、そうすべきではありません)。

だから...私はシバン全体を再考する必要があると考え始めています...フォームを前もって「通常のアプリケーション」として表示し、処理の残りをOKボタンクリックイベントにアタッチする必要があります。それはうまくいくはずですが、それは私が持っていない時間がかかります(私はすでに時間/予算を超えています)...最初に私は本当に現在のアプローチを機能させるようにする必要があります...迅速かつダーティメソッド。

だから、誰もが。 「魔法の」Windows API呼び出しを考えています(私は知っています

トワイライトゾーン:これは職場での問題のようです。WindowsでVisual Studio 2008を使用していますXP SP3 ... Vista UlimateのVisual C#2008で自宅でSSCCE(下記参照)の問題を再現できませんでした...これで問題ありません。

また、昨日職場でEXEを実行したときにフォームが表示されたが、IDE(我慢)...自宅では、フォームはどちらの方法でもうまく表示されます。

関連する場合も関連しない場合もありますが、プロジェクトがデバッグモードで実行され、「オンザフライ」でコードを編集しているときに、Visual Studioがクラッシュして焼けました...メッセージ。エラーメッセージは、「現在のプロジェクトではないため、このプロジェクトをデバッグできない、または何か...」というものでした。したがって、プロセスエクスプローラーでそれを強制終了しました。ファイル、私が受け入れた申し出。

using System;
using System.Windows.Forms;

namespace ShowFormOnTop {
    static class Program {
        [STAThread]
        static void Main() {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            //Application.Run(new Form1());
            Form1 frm = new Form1();
            frm.ShowDialog();
        }
    }
}

背景:既存のVB6実装を.NETに移植しています...これは、 MapInfoという「クライアント」GISアプリケーションの「プラグイン」です 。既存のクライアントは「見えないように動作しました」と私の指示は「新しいバージョンを可能な限り古いバージョンに近づける」ことで、これは十分に機能します(数年のパッチ適用後)。サポートされていない言語で書かれているため、移植する必要があります。

私について:私は一般的にC#と.NETにかなり慣れていますが、ボトムスワイプ証明書を持っていますが、私はプロです10年間のプログラマー。だから私は「何かを知っている」と言っています。

どんな洞察も大歓迎です...そして、ここまで読んでくれてありがとう。意識は(明らかに)私の得意ではありません。

乾杯。キース。

21
corlettk

単に

yourForm.TopMost = true;
47
cablehead

IWin32Windowオブジェクトを取得するForm.ShowDialog()のオーバーロードがあります。そのIWin32Windowは、フォームの親ウィンドウとして扱われます。

System.Windows.Forms.Formとして親ウィンドウがある場合は、先に進んでそれを渡します。そうでない場合は、HWNDを取得し(FindWindow()へのP/Invokingによる)、HWNDを返すだけのダミーIWin32Window実装を作成します( 詳細 )。

4
ChrisV

Form.Activate()は私の場合うまくいきました。

4
Esen
  1. _Application.Run_を使用すると正常に機能すると述べました。では、なぜ_Application.Run_を使用したくないのですか?
  2. OnLoadまたはOnShownからBringToFront()を呼び出してみましたか?
3
P Daddy

これは、20回の試行の後、私が書いた最終的な解決策です。

/* A workaround for showing a form on the foreground and with focus,
 * even if it is run by a process other than the main one
 */
public static void ShowInForeground(this Form form, bool showDialog = false)
{
    if (showDialog)
    {
        //it's an hack, thanks to http://stackoverflow.com/a/1463479/505893
        form.WindowState = FormWindowState.Minimized;
        form.Shown += delegate(Object sender, EventArgs e) {
            ((Form)sender).WindowState = FormWindowState.Normal;
        };
        form.ShowDialog();
    }
    else
    {
        //it's an hack, thanks to http://stackoverflow.com/a/11941579/505893
        form.WindowState = FormWindowState.Minimized;
        form.Show();
        form.WindowState = FormWindowState.Normal;

        //set focus on the first control
        form.SelectNextControl(form.ActiveControl, true, true, true, true);
    }
}
2
bluish

私が取り組んできたアプリケーションからこれをハッキングしました。さまざまなチームが作成した一連のモジュールをロードする大規模なアプリケーションがあります。これらのモジュールの1つを作成し、この初期化中にログインダイアログを開く必要がありました。 '.TopMost = true'に設定されていましたが、うまくいきませんでした。

WindowsFormsSynchronizationContextを使用してダイアログボックスを開き、ダイアログボックスの結果を取得します。

私はめったにGUIコーディングを行わず、これがやり過ぎかもしれないと疑っていますが、動けなくなると助けになるかもしれません。見つけることができるすべての例がそれを使用しなかったため、SendOrPostCallbackに状態が渡される方法を理解するのに問題がありました。

また、これは動作中のアプリケーションから取得されますが、いくつかのコードを削除し、詳細の一部を変更しました。コンパイルできない場合はおApび申し上げます。

public bool Dummy()
{

// create the login dialog
DummyDialogForm myDialog = new DummyDialogForm();

// How we show it depends on where we are. We might be in the main thread, or in a background thread
// (There may be better ways of doing this??)
if (SynchronizationContext.Current == null)
{
    // We are in the main thread. Just display the dialog
    DialogResult result = myDialog.ShowDialog();
    return result == DialogResult.OK;
}
else
{
    // Get the window handle of the main window of the calling process
    IntPtr windowHandle = Process.GetCurrentProcess().MainWindowHandle;

    if (windowHandle == IntPtr.Zero)
    {
        // No window displayed yet
        DialogResult result = myDialog.ShowDialog();
        return result == DialogResult.OK;
    }
    else
    {
        // Parent window exists on separate thread
        // We want the dialog box to appear in front of the main window in the calling program
        // We would like to be able to do 'myDialog.ShowDialog(windowHandleWrapper)', but that means doing something on the UI thread
        object resultState = null;
        WindowsFormsSynchronizationContext.Current.Send(
            new SendOrPostCallback(delegate(object state) { resultState = myDialog.ShowDialog(); }), resultState);

        if (resultState is DialogResult)
        {
            DialogResult result = (DialogResult) resultState;
            return result == DialogResult.OK;
        }
        else
            return false;

    }
}

}

1
alex

Activate()も私のために働きました。

BringToFront()はこの場合何もしませんでした。理由はわかりません。

1
user2162266

これは完璧に仕事をしました:

formxx.WindowState = FormWindowState.Normal;
formxx.BringToFront();
formxx.Topmost=true;
formxx.Focus();
0

プロジェクトでコードを取得しました。

private static extern bool SetForegroundWindow(
IntPtr hWnd); 
public static void ShowToFront(Form form)
{
    FormWindowState oldState = form.WindowState;
    form.WindowState = FormWindowState.Minimized;
    form.Show();

    form.Activate();
    form.TopLevel = false;
    form.TopLevel = true;
    form.SelectNextControl(form.ActiveControl, true, true, true, true);
    SetForegroundWindow(form.Handle);
    form.Focus();
    form.WindowState = oldState;
}
0
phuong

動作はXPに固有であるように見えます...したがって、Vistaでは再現できません。

http://www.gamedev.net/community/forums/topic.asp?topic_id=218484

EDIT:PS:就寝時刻を過ぎています(午前2時;-)。

あなたの応答に感謝します...私が試すことができる「いくつかのこと」があります...私はそれらを試すために明日オフィスに行くかもしれません...ええ、ええ...私は一度人生を過ごしましたが、私はそれを交換しました散髪と仕事のため;-)

乾杯。キース。

0
corlettk