皆さん、
他の方法では見えないアプリケーションからフォームを表示する方法を知っている人はいませんか?そしてフォーカスを取得します(つまり、他のウィンドウの上に表示されます)?私は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年間のプログラマー。だから私は「何かを知っている」と言っています。
どんな洞察も大歓迎です...そして、ここまで読んでくれてありがとう。意識は(明らかに)私の得意ではありません。
乾杯。キース。
単に
yourForm.TopMost = true;
IWin32Windowオブジェクトを取得するForm.ShowDialog()のオーバーロードがあります。そのIWin32Windowは、フォームの親ウィンドウとして扱われます。
System.Windows.Forms.Formとして親ウィンドウがある場合は、先に進んでそれを渡します。そうでない場合は、HWNDを取得し(FindWindow()へのP/Invokingによる)、HWNDを返すだけのダミーIWin32Window実装を作成します( 詳細 )。
Form.Activate()
は私の場合うまくいきました。
Application.Run
_を使用すると正常に機能すると述べました。では、なぜ_Application.Run
_を使用したくないのですか?OnLoad
またはOnShown
からBringToFront()
を呼び出してみましたか?これは、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);
}
}
私が取り組んできたアプリケーションからこれをハッキングしました。さまざまなチームが作成した一連のモジュールをロードする大規模なアプリケーションがあります。これらのモジュールの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;
}
}
}
Activate()
も私のために働きました。
BringToFront()
はこの場合何もしませんでした。理由はわかりません。
これは完璧に仕事をしました:
formxx.WindowState = FormWindowState.Normal;
formxx.BringToFront();
formxx.Topmost=true;
formxx.Focus();
プロジェクトでコードを取得しました。
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;
}
動作はXPに固有であるように見えます...したがって、Vistaでは再現できません。
http://www.gamedev.net/community/forums/topic.asp?topic_id=218484
EDIT:PS:就寝時刻を過ぎています(午前2時;-)。
あなたの応答に感謝します...私が試すことができる「いくつかのこと」があります...私はそれらを試すために明日オフィスに行くかもしれません...ええ、ええ...私は一度人生を過ごしましたが、私はそれを交換しました散髪と仕事のため;-)
乾杯。キース。