回答:
うーん、単にForm.ShowWithoutActivationをオーバーライドするだけでは十分ではありませんか?
protected override bool ShowWithoutActivation
{
get { return true; }
}
また、ユーザーにこの通知ウィンドウをクリックさせたくない場合は、CreateParamsをオーバーライドできます。
protected override CreateParams CreateParams
{
get
{
CreateParams baseParams = base.CreateParams;
const int WS_EX_NOACTIVATE = 0x08000000;
const int WS_EX_TOOLWINDOW = 0x00000080;
baseParams.ExStyle |= ( int )( WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW );
return baseParams;
}
}
form1.Enabled = false
、内部コントロールがフォーカスを盗むのを防ぐための設定も必要でした
WS_EX_NOACTIVATE
およびの値WS_EX_TOOLWINDOW
は0x08000000
および0x00000080
です。
PInvoke.netのShowWindowメソッドから盗まれた:
private const int SW_SHOWNOACTIVATE = 4;
private const int HWND_TOPMOST = -1;
private const uint SWP_NOACTIVATE = 0x0010;
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
static extern bool SetWindowPos(
int hWnd, // Window handle
int hWndInsertAfter, // Placement-order handle
int X, // Horizontal position
int Y, // Vertical position
int cx, // Width
int cy, // Height
uint uFlags); // Window positioning flags
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
static void ShowInactiveTopmost(Form frm)
{
ShowWindow(frm.Handle, SW_SHOWNOACTIVATE);
SetWindowPos(frm.Handle.ToInt32(), HWND_TOPMOST,
frm.Left, frm.Top, frm.Width, frm.Height,
SWP_NOACTIVATE);
}
(Alex Lymanがこれに答えました、私はコードを直接貼り付けることによってそれを拡張しています。編集権限を持つ誰かがそこにコピーして、私が気にするすべてのためにこれを削除できます;))
あなたが使用して喜んでいる場合はWin32の P /呼び出しを、あなたが使用することができるのShowWindowの方法を(最初のコードサンプルは、あなたが望むものを正確に行います)。
これは私のために働いたものです。TopMostを提供しますが、フォーカスを盗むことはありません。
protected override bool ShowWithoutActivation
{
get { return true; }
}
private const int WS_EX_TOPMOST = 0x00000008;
protected override CreateParams CreateParams
{
get
{
CreateParams createParams = base.CreateParams;
createParams.ExStyle |= WS_EX_TOPMOST;
return createParams;
}
}
Visual Studioデザイナまたは他の場所でTopMostを設定することを忘れてください。
これは、ここから盗まれ、誤って、借用されています(回避策をクリックしてください):
これを行うことはハックのようですが、うまくいくようです:
this.TopMost = true; // as a result the form gets thrown to the front
this.TopMost = false; // but we don't actually want our form to always be on top
編集:注、これは単にフォーカスを盗むことなく、既に作成されたフォームを発生させるだけです。
WPFでは、次のように解決できます。
ウィンドウに次の属性を入力します。
<Window
x:Class="myApplication.winNotification"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Notification Popup" Width="300" SizeToContent="Height"
WindowStyle="None" AllowsTransparency="True" Background="Transparent" ShowInTaskbar="False" Topmost="True" Focusable="False" ShowActivated="False" >
</Window>
最後の1つの属性は、ShowActivated = "False"が必要な属性です。
別のスレッドで通知フォームを作成して開始し、フォームが開いたらフォーカスをメインフォームに戻します。通知フォームに、Form.Shown
イベントから発生するOnFormOpenedイベントを提供させます。このようなもの:
private void StartNotfication()
{
Thread th = new Thread(new ThreadStart(delegate
{
NotificationForm frm = new NotificationForm();
frm.OnFormOpen += NotificationOpened;
frm.ShowDialog();
}));
th.Name = "NotificationForm";
th.Start();
}
private void NotificationOpened()
{
this.Focus(); // Put focus back on the original calling Form
}
また、NotifcationFormオブジェクトへのハンドルを保持して、メインのフォーム(frm.Close()
)によってプログラムで閉じることができるようにすることもできます。
いくつかの詳細は欠けていますが、うまくいけば、これで正しい方向に進むことができます。
表示する通知の種類を検討する必要がある場合があります。
イベントについてユーザーに知らせることが絶対に重要な場合は、ユーザーが確認するまでメインウィンドウへの他のイベントをブロックする性質があるため、Messagebox.Showを使用することをお勧めします。ただし、ポップアップ失明に注意してください。
重要度が低い場合は、ウィンドウの下部にあるツールバーなど、別の方法で通知を表示することをお勧めします。画面の右下に通知を表示することを書いた-これを行うための標準的な方法は、システムトレイアイコンの組み合わせでバルーンヒントを使用することです。
これはうまくいきます。
参照:OpenIcon-MSDN およびSetForegroundWindow-MSDN
using System.Runtime.InteropServices;
[DllImport("user32.dll")]
static extern bool OpenIcon(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
public static void ActivateInstance()
{
IntPtr hWnd = IntPtr hWnd = Process.GetCurrentProcess().MainWindowHandle;
// Restore the program.
bool result = OpenIcon(hWnd);
// Activate the application.
result = SetForegroundWindow(hWnd);
// End the current instance of the application.
//System.Environment.Exit(0);
}
ロジックだけで処理することもできますが、実際にフォーカスを盗まずにBringToFrontメソッドを使用する上記の提案が最もエレガントであることを認めざるを得ません。
とにかく、私はこれに遭遇し、DateTimeプロパティを使用して解決しました。呼び出しが最近行われた場合は、それ以上のBringToFront呼び出しを許可しません。
たとえば3つのフォーム「Form1、2、および3」を処理するコアクラス「Core」を想定します。各フォームには、DateTimeプロパティと、ウィンドウを前面に表示するためにCoreを呼び出すActivateイベントが必要です。
internal static DateTime LastBringToFrontTime { get; set; }
private void Form1_Activated(object sender, EventArgs e)
{
var eventTime = DateTime.Now;
if ((eventTime - LastBringToFrontTime).TotalMilliseconds > 500)
Core.BringAllToFront(this);
LastBringToFrontTime = eventTime;
}
次に、コアクラスで作品を作成します。
internal static void BringAllToFront(Form inForm)
{
Form1.BringToFront();
Form2.BringToFront();
Form3.BringToFront();
inForm.Focus();
}
余談ですが、最小化されたウィンドウを元の状態(最大化されていない状態)に戻したい場合は、次のようにします。
inForm.WindowState = FormWindowState.Normal;
繰り返しますが、これはBringToFrontWithoutFocusがない場合のパッチソリューションにすぎません。これは、DLLファイルを回避したい場合の提案です。
これがネクロポスティングと見なされるかどうかはわかりませんが、user32の「ShowWindow」メソッドと「SetWindowPos」メソッドで機能しないため、これを行いました。いいえ、この場合、新しいウィンドウを常に前面に表示する必要があるため、「ShowWithoutActivation」のオーバーライドは機能しません。とにかく、フォームをパラメーターとして取るヘルパーメソッドを作成しました。呼び出されると、フォームを表示し、前面に移動して、現在のウィンドウのフォーカスを奪うことなくTopMostにします(見かけ上はそうですが、ユーザーは気づきません)。
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern IntPtr SetForegroundWindow(IntPtr hWnd);
public static void ShowTopmostNoFocus(Form f)
{
IntPtr activeWin = GetForegroundWindow();
f.Show();
f.BringToFront();
f.TopMost = true;
if (activeWin.ToInt32() > 0)
{
SetForegroundWindow(activeWin);
}
}
愚かに聞こえるかもしれませんが、これはうまくいきました:
this.TopMost = true;
this.TopMost = false;
this.TopMost = true;
this.SendToBack();
私は自分のウィンドウTopMostでこれを行う必要がありました。上記のPInvokeメソッドを実装しましたが、上記のTalhaのようにLoadイベントが呼び出されていません。ようやく成功しました。多分これは誰かを助けるでしょう。これが私の解決策です:
form.Visible = false;
form.TopMost = false;
ShowWindow(form.Handle, ShowNoActivate);
SetWindowPos(form.Handle, HWND_TOPMOST,
form.Left, form.Top, form.Width, form.Height,
NoActivate);
form.Visible = true; //So that Load event happens
それを考え出した:window.WindowState = WindowState.Minimized;
。