草庐IT

关于 c#:Notification Window – 防止窗口获得焦点

codeneng 2023-03-28 原文

Notification Window - Preventing the window from ever getting focus

我在让通知框在 c# 中正常运行时遇到了一些问题。基本上,我在屏幕的右下角显示了一个无边界表格,它会显示一条消息几秒钟然后消失。问题是我需要它出现在其他窗口的顶部,而它却无法窃取焦点。理想情况下,我希望它是纯托管代码,尽管查看类似示例我怀疑这是否可能。

目前我正在阻止它在调用 Form.Show() 时窃取焦点:

1
2
3
4
protected override bool ShowWithoutActivation // stops the window from stealing focus
{
    get { return true; }
}

然后忽略鼠标点击:

1
2
3
4
5
6
7
8
9
10
11
12
    private const int WM_MOUSEACTIVATE = 0x0021;
    private const int MA_NOACTIVATEANDEAT = 0x0004;

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_MOUSEACTIVATE)
        {
            m.Result = (IntPtr)MA_NOACTIVATEANDEAT;
            return;
        }
        base.WndProc(ref m);
    }

但是我发现如果我将它们与 TopMost = true (我需要)结合使用,它无论如何都会获得焦点,如果所有其他窗口都被最小化,它也会获得焦点。

那么,有没有什么方法可以完全阻止表单获得焦点(无论是通过鼠标单击、alt-tab 等),同时仍然是最顶部/第二顶部的表单?即使只是将焦点立即返回到它从中窃取的窗口也可以工作(尽管会引入闪烁)。

任何建议将不胜感激,我真的坚持这一点。

编辑:

好的,所以我终于设法使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
protected override bool ShowWithoutActivation // stops the window from stealing focus
{
    get { return true; }
}

// and

const int WS_EX_NOACTIVATE = 0x08000000;
const int WS_EX_TOPMOST = 0x00000008;

protected override CreateParams CreateParams
{
    get
    {
        CreateParams param = base.CreateParams;
        param.ExStyle |= WS_EX_TOPMOST; // make the form topmost
        param.ExStyle |= WS_EX_NOACTIVATE; // prevent the form from being activated
        return param;
    }
}

// and

[DllImport("user32.dll")]
private extern static IntPtr SetActiveWindow(IntPtr handle);
private const int WM_ACTIVATE = 6;
private const int WA_INACTIVE = 0;

private const int WM_MOUSEACTIVATE = 0x0021;
private const int MA_NOACTIVATEANDEAT = 0x0004;

protected override void WndProc(ref Message m)
{
    if (m.Msg == WM_MOUSEACTIVATE)
    {
        m.Result = (IntPtr)MA_NOACTIVATEANDEAT; // prevent the form from being clicked and gaining focus
        return;
    }
    if (m.Msg == WM_ACTIVATE) // if a message gets through to activate the form somehow
    {
        if (((int)m.WParam & 0xFFFF) != WA_INACTIVE)
        {

            if (m.LParam != IntPtr.Zero)
            {
                SetActiveWindow(m.LParam);
            }
            else
            {
                // Could not find sender, just in-activate it.
                SetActiveWindow(IntPtr.Zero);
            }

        }
    }

我还在 GotFocus 事件中添加了 Form.Hide() ,这样即使它确实以某种方式获得焦点,它也会尽快关闭并离开用户。

此外,如果有人想知道,所有窗口样式等的常量都可以在 WINUSER.H 中找到,如果可以的话,它的在线地址为 http://www.woodmann.com/fravia/sources/WINUSER.H没找到。

但是,如果有人能看到更优雅的方法,将不胜感激。


在 WPF 中试试这个:

1
ShowActivated="False"

您正在寻找的可能是 WS_EX_NOACTIVATE 扩展窗口样式。单击时不会激活具有此样式的窗口。例如,虚拟键盘窗口具有这种样式。

要将此样式应用于窗口,请覆盖 CreateParams 函数并更改 baseParams.ExStyle.

  • 谢谢,这非常适合防止它获得焦点,它现在甚至不会出现在 alt-tab 中,这太棒了。我仍然遇到的一个小问题是 TopMost = true 似乎覆盖了 ShowWithoutActivation,因此在调用 form.Show() 时它仍然获得焦点。有没有办法解决?
  • 请参阅 Ziketo 对此的回应。还记得投票帮助人们提出的问题。


我不是在这里寻找积分,因为原始发帖人已经发布了一个对他们有用的解决方案,但我想分享我在这个问题上的经验。使用上面的解决方案(在问题的底部而不是在答案形式中)在使用 WndProc 代码时给了我一个 Win32Exception: Error creating window handle error. ,因为它张贴在那里。 ShowWithoutActivationCreateParams 部分可以很好地防止表单激活并仍然保持在最上面。

我想出了一个替代解决方案来防止表单被点击使用 SetWindowLong 使表单透明,因此可以单击它,而 SetLayeredWindowAttributes 将透明度设置为正常,因此您可以看到表单再次,但仍保留单击表单的能力。

注意:在这种状态下,您根本无法与表单进行交互,甚至尝试单击"X"按钮只会单击该位置的表单后面的任何内容,因此您需要使用代码来关闭表单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
public partial class Form1 : Form
{
    private enum GWL : int
    {
        ExStyle = -20
    }

    private enum WS_EX : int
    {
        Transparent = 0x20,
        Layered = 0x80000
    }

    public enum LWA : int
    {
        ColorKey = 0x1,
        Alpha = 0x2
    }

    [DllImport("user32.dll")]
    static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

    [DllImport("user32.dll")]
    static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags);

    protected override bool ShowWithoutActivation
    {
        get { return true; }
    }

    const int WS_EX_NOACTIVATE = 0x08000000;
    const int WS_EX_TOPMOST = 0x00000008;

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams param = base.CreateParams;
            param.ExStyle |= WS_EX_TOPMOST; // make the form topmost
            param.ExStyle |= WS_EX_NOACTIVATE; // prevent the form from being activated
            return param;
        }
    }

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        // Prevent form from showing up in taskbar which also prevents activation by Alt+Tab

        this.ShowInTaskbar = false;

        // Allow the form to be clicked through so that the message never physically interferes with work being done on the computer

        SetWindowLong(this.Handle, (int)GWL.ExStyle, (int)WS_EX.Layered | (int)WS_EX.Transparent);

        // Set the opacity of the form

        byte nOpacity = 255;    // 0 = invisible, 255 = solid, anything inbetween will show the form with transparency
        SetLayeredWindowAttributes(this.Handle, 0, nOpacity, (uint)LWA.Alpha);
    }
}

我还能够通过对上面的 WndProc 代码进行一些小改动来使原始方法发挥作用。

注意:这也使表单无法单击,但行为不同,因为您实际上可以单击最小、最大和"X"按钮,但当您这样做时没有任何反应。当您位于表单边缘时,鼠标光标也会发生变化,好像要调整大小但它不允许调整大小:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public partial class Form1 : Form
{
    protected override bool ShowWithoutActivation
    {
        get { return true; }
    }

    const int WS_EX_NOACTIVATE = 0x08000000;
    const int WS_EX_TOPMOST = 0x00000008;

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams param = base.CreateParams;
            param.ExStyle |= WS_EX_TOPMOST; // make the form topmost
            param.ExStyle |= WS_EX_NOACTIVATE; // prevent the form from being activated
            return param;
        }
    }

    [DllImport("user32.dll")]
    private extern static IntPtr SetActiveWindow(IntPtr handle);
    private const int WM_ACTIVATE = 6;
    private const int WA_INACTIVE = 0;

    private const int WM_MOUSEACTIVATE = 0x0021;
    private const int MA_NOACTIVATEANDEAT = 0x0004;

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_MOUSEACTIVATE)
        {
            m.Result = (IntPtr)MA_NOACTIVATEANDEAT; // prevent the form from being clicked and gaining focus
            return;
        }
        if (m.Msg == WM_ACTIVATE) // if a message gets through to activate the form somehow
        {
            if (((int)m.WParam & 0xFFFF) != WA_INACTIVE)
            {

                if (m.LParam != IntPtr.Zero)
                {
                    SetActiveWindow(m.LParam);
                }
                else
                {
                    // Could not find sender, just in-activate it.
                    SetActiveWindow(IntPtr.Zero);
                }

            }
        }
        else
        {
            base.WndProc(ref m);
        }
    }

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        // Prevent form from showing up in taskbar which also prevents activation by Alt+Tab

        this.ShowInTaskbar = false;
    }
}

有关关于 c#:Notification Window – 防止窗口获得焦点的更多相关文章

  1. ruby - 无法在 60 秒内获得稳定的 Firefox 连接 (127.0.0.1 :7055) - 2

    我使用的是Firefox版本36.0.1和Selenium-Webdrivergem版本2.45.0。我能够创建Firefox实例,但无法使用脚本继续进行进一步的操作无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055)错误。有人能帮帮我吗? 最佳答案 我遇到了同样的问题。降级到firefoxv33后一切正常。您可以找到旧版本here 关于ruby-无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055),我们在StackOverflow上找到一个类

  2. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  3. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  4. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  5. ruby - (Ruby || Python) 窗口管理器 - 2

    我想用这两种语言中的任何一种(最好是ruby​​)制作一个窗口管理器。老实说,除了我需要加载某种X模块外,我不知道从哪里开始。因此,如果有人有线索,如果您能指出正确的方向,那就太好了。谢谢 最佳答案 XCB,X的下一代API使用XML格式定义X协议(protocol),并使用脚本生成特定语言绑定(bind)。它在概念上与SWIG类似,只是它描述的不是CAPI,而是X协议(protocol)。目前,C和Python存在绑定(bind)。理论上,Ruby端口只是编写一个从XML协议(protocol)定义语言到Ruby的翻译器的问题。生

  6. ruby-on-rails - Rails 3.2 防止使用错误保存对象 - 2

    我有一个ActiveRecord对象,我想在不对模型进行永久验证的情况下阻止它被保存。您过去可以使用errors.add执行类似的操作,但它看起来不再有效了。user=User.lastuser.errors.add:name,"namedoesn'trhymewithorange"user.valid?#=>trueuser.save#=>true或user=User.lastuser.errors.add:base,"myuniqueerror"user.valid?#=>trueuser.save#=>true如何在不修改用户对象模型的情况下防止将用户对象保存在Rails3.2中

  7. ruby-on-rails - 关于 Ruby 的一般问题 - 2

    我在我的rails应用程序中安装了来自github.com的acts_as_versioned插件,但有一段代码我不完全理解,我希望有人能帮我解决这个问题class_eval我知道block内的方法(或任何它是什么)被定义为类内的实例方法,但我在插件的任何地方都找不到定义为常量的CLASS_METHODS,而且我也不确定是什么here,并且有问题的代码从lib/acts_as_versioned.rb的第199行开始。如果有人愿意告诉我这里的内幕,我将不胜感激。谢谢-C 最佳答案 这是一个异端。http://en.wikipedia

  8. ruby - 防止SQL注入(inject)/好的Ruby方法 - 2

    Ruby中防止SQL注入(inject)的好方法是什么? 最佳答案 直接使用ruby?使用准备好的语句:require'mysql'db=Mysql.new('localhost','user','password','database')statement=db.prepare"SELECT*FROMtableWHEREfield=?"statement.execute'value'statement.fetchstatement.close 关于ruby-防止SQL注入(inject

  9. ruby - 我怎样才能更好地了解/了解更多关于 Ruby 的知识? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。我最近开始学习Ruby,这是我的第一门编程语言。我对语法感到满意,并且我已经完成了许多只教授相同基础知识的教程。我已经写了一些小程序(包括我自己的数组排序方法,在有人告诉我谷歌“冒泡排序”之前我认为它非常聪明),但我觉得我需要尝试更大更难的东西来理解更多关于Ruby.关于如何执行此操作的任何想法?

  10. ruby - 我可以从 Ruby 中的系统调用中获得连续输出吗? - 2

    当您在Ruby脚本中使用系统调用时,您可以像这样获得该命令的输出:output=`ls`putsoutput这就是thisquestion是关于。但是有没有办法显示系统调用的连续输出?例如,如果您运行此安全复制命令,以通过SSH从服务器获取文件:scpuser@someserver:remoteFile/some/local/folder/...它显示随着下载进度的连续输出。但是这个:output=`scpuser@someserver:remoteFile/some/local/folder/`putsoutput...不捕获该输出。如何从我的Ruby脚本中显示正在进行的下载进度?

随机推荐