【问题标题】:BringToFront() in C#C#中的BringToFront()
【发布时间】:2011-06-10 07:20:31
【问题描述】:

我在这里为客户制作了一个应用程序,但有时他不知道订单是否到货,因为他玩魔兽世界时音量已满。但他说如果有新订单到达,他希望我的小通知窗口出现在他的游戏顶部。

所以,我想我可以只使用BringToFront();,这在全屏应用最大化时似乎可以工作。但是,我注意到在全屏玩 V8 Supercars 时,BringToFront(); 不会将通知窗口置于游戏之上,所以我认为有些游戏有另一种方式来确保它们保持在其他一切之上。

我如何确保每当我需要看到我的表单时,它总是会显示在 anything else 之上?

【问题讨论】:

  • 说真的,他的魔兽世界影响他履行业务职责?我想我看到了问题......我不确定它是否与代码相关......
  • @Paul 说真的,winforms 将在与游戏不同的 UI 堆栈中运行。也许第二台显示器会起作用……谁知道呢。
  • @Paul 可能会编写一个 WoW 机器人来告诉他;p 现在我打赌他会为此付出代价!
  • 使用 FlashWindowEx 并告诉他以窗口(而非全屏)模式播放。 pietschsoft.com/post/2009/01/26/… ...我不建议任何程序窃取键盘焦点,它太容易按回车键或空格键并触发默认按钮处理程序。
  • @Overslacked,同意。如果是窗口游戏会简单。

标签: c# .net winforms


【解决方案1】:

我在同一个话题上苦苦挣扎,尤其是在 Outlook 中单击自定义协议的“链接”时。 (应用程序捕捉到了它,但总是在后台......)

尽管很多解决方案在调试时都有效,但对于“实时部署”,只有以下调用链似乎可以达到预期效果:

(调用,导致链接处理发生在线程中)

this.Invoke(new Action(() => {
  this.Activate();
  //...do stuff
  this.TopMost = true;
  this.BringToFront();
  this.TopMost = false;                              
}));

几乎每次都有效。

【讨论】:

  • 如果您不希望模态但需要 form.show() 以实际导致在顶部看到表单...似乎与这些调用相关的一些框架错误,则此解决方案似乎是必要的。
  • @DAG 我不确定这是否是一个错误。对我来说,当调用form.Show() 时,当前在后台的应用程序不应该自动出现在前面,这似乎很可靠。但是,由于对此有合法的用例,因此如果有对此的本机支持会很好。现在,我已经使用上面的代码创建了一个扩展方法ShowFront() 并使用它,只要我想确保如果应用程序没有当前焦点,显示的窗口从后台出现。
【解决方案2】:
form.TopMost = true;
form.ShowDialog();
form.BringToFront();

应该适用于所有应用程序,包括全屏独占游戏(在我的所有游戏上测试,到目前为止,它有效)。

【讨论】:

    【解决方案3】:

    您可以尝试将通知表单的TopMost 属性设置为true...或通过调用.ShowDialog 而不是.Show 使其成为模态。

    【讨论】:

    • 谢谢@alexD - TopMost 正在使用我的魔兽世界演示版。现在我必须去看看我是否可以为 WoW 创建那个订单通知机器人。感谢@Marc。天才!
    【解决方案4】:

    这是调用windows API函数的VB代码,应该比较容易翻译(注意,这是未经测试的,在论坛上找到的,也可能出现光标有问题)。

    Private Declare Function SetWindowPos Lib "user32" (ByVal hwnd As Long, ByVal _ hWndInsertAfter As Long, ByVal X As Long, ByVal Y As Long, ByVal cx As Long, _ ByVal cy As Long, ByVal wFlags As Long) As Long
    Const HWND_TOPMOST = -1 
    Const SWP_NOMOVE = &H2 
    Const SWP_NOSIZE = &H1 
    Private Sub Form_Load() 
        Call SetWindowPos(Form1.hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE) 
    End Sub
    

    使用以下代码创建一个间隔为 1 的计时器:

    Private Declare Function SetParent Lib "user32" (ByVal hWndChild As Long, ByVal hWndNewParent As Long) As Long 
    Private Declare Function GetForegroundWindow Lib "user32" () As Long 
    Private Sub Timer1_Timer() 
        Dim mhwnd As Long 
        mhwnd = GetForegroundWindow SetParent Form1.hwnd, mhwnd 
    End Sub
    

    以下代码翻译(通过自动化工具):

    const long HWND_TOPMOST = -1;
    const long SWP_NOMOVE = 2;
    const long SWP_NOSIZE = 1;
    
    [DllImport("user32.dll")]
    private static extern long SetWindowPos(long hwnd, long hWndInsertAfter, long X, long Y, long cx, long cy, long wFlags);
    
    private void Form_Load() {
        SetWindowPos(Form1.hwnd, HWND_TOPMOST, 0, 0, 0, 0, (SWP_NOMOVE | SWP_NOSIZE));
    }
    
    [DllImport("user32.dll")]
    private static extern long SetParent(long hWndChild, long hWndNewParent);
    
    [DllImport("user32.dll")]
    private static extern long GetForegroundWindow();
    
    private void Timer1_Timer() {
        long mhwnd;
        mhwnd = GetForegroundWindow;
        SetParent;
        Form1.hwnd;
        mhwnd;
    }
    

    【讨论】:

    • 哦!我喜欢手动从 VB 转换为 C#。谢谢 :-D - 我会继续尝试。
    • 会转换,但不熟悉 C# DLL 导入或 &... VB 语法。很高兴有人编辑。
    【解决方案5】:

    默认情况下,它会出现在屏幕顶部,但不是模型。

    您可以使用Window.Show() 方法来关闭窗口,在不需要时将其可见性更改为 False。 您可能需要使用子窗口的父属性将其设置为主窗口

    【讨论】:

    • 我不确定这与问题(通过 WoW 渲染)有何关系
    • 谢谢,@DumbCode,这些是我已经在使用的东西(应该把它放在我的问题中,抱歉)。但是它们都没有(BringToFront(); 除外)将表单放在前面。窗口.Show();只是显示窗口,我还没有看到它显示在 WoW 之上。
    • 如果我能理解,你可能正在寻找一个模型对话框之类的东西,你希望它出现在所有窗口的顶部,不管它是什么。 WPF Modal Dialog如果我错了请纠正我?
    • 嗯,这就是我想要的 - 但是我和 WPF 似乎相处得不太好。不是我们没有尝试过,只是……我们一直忙于做自己的事情,而我只是没有时间投入了解他。但是谢谢你,我会保留它的书签,以备将来开始使用 WPF 时参考。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-02
    • 2011-04-02
    • 1970-01-01
    • 1970-01-01
    • 2013-05-19
    • 2012-07-23
    相关资源
    最近更新 更多