C#: 如何显示一个不可见的窗体

18

我在C#中有以下代码:

Form f = new MyForm();
f.Visible = false;
f.Show();
f.Close();

尽管使用了f.Visible = false,但我仍然看到窗体一闪而过。我需要做什么才能使这个窗体不可见?

在我的应用程序启动画面期间(隐藏地)显示此窗体可以消除显示此窗体时的冷启动延迟,因此我需要这样做。


为什么你要显示然后又关闭它? - FarligOpptreden
我的第一个问题是,为什么您需要显示一个窗体然后立即关闭它?可能有更好的方法。 - Alistair Evans
如果您在myForm OnShow中有一些逻辑,请将其移动到load中,甚至更好的是移动到一个单独的公共方法中,这样您可以从外部调用它,因此您甚至不需要显示它。 - Davide Piras
@Kazar 我正在尝试通过在应用程序的闪屏界面上显示此表单来改善冷启动问题。这解决了问题,但是该表单会在屏幕上闪烁。 - Craig Johnston
@Shekhar:启动画面是一个不同的窗体。 - Craig Johnston
显示剩余3条评论
5个回答

19
如果你想展示表单但不想让其实际可见,可以这样做:
  public Form1()
  {
     InitializeComponent();
     this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
     this.ShowInTaskbar = false;
     this.Load += new EventHandler(Form1_Load);
  }

  void Form1_Load(object sender, EventArgs e)
  {
     this.Size = new Size(0, 0);
  }

如果以后您想显示它,只需将所有内容改回来即可。这是一个示例,在10秒后它将显示该表单:

  Timer tmr = new Timer();
  public Form1()
  {
     tmr.Interval = 10000;
     tmr.Tick += new EventHandler(tmr_Tick);
     tmr.Start();

     InitializeComponent();
     this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
     this.ShowInTaskbar = false;
     this.Load += new EventHandler(Form1_Load);
  }

  void tmr_Tick(object sender, EventArgs e)
  {
     this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Sizable;
     this.ShowInTaskbar = true;
     this.Size = new Size(300, 300);
  }

  void Form1_Load(object sender, EventArgs e)
  {
     this.Size = new Size(0, 0);
  }

2
@Craig - 如果有帮助的话,随意点赞。你甚至还会获得一个很酷的“支持者”徽章 :p - SwDevMan81
我选择这个作为答案,因为它给了我想要的,并且它是最简单的(因此在我看来最不容易出错)。 - Craig Johnston
3
我遇到了一个问题,当将窗口大小设置为零时,窗口在屏幕上是不可见的,但当按下ALT + TAB时,它会出现在任务切换对话框中,尽管我已将ShowInTaskbar = false!采用Kazar提出的使用SetVisibleCore的技术更好,因为窗口完全消失在任何地方。(请参见下文) - Elmue
如何使程序不在 Alt + Tab 或任务栏中显示:https://dev59.com/J3E85IYBdhLWcg3wZyut - Polar
为了将其从alt+tab中隐藏,请使用以下代码替换: this.FormBorderStyle = FormBorderStyle.None;改为 this.WindowState = FormWindowState.Minimized; this.FormBorderStyle = FormBorderStyle.FixedToolWindow; - mat007

13

保持表单不可见最简单的方法就是不显示它。在Winforms中这是非常重要的,调用Show()或将Visible属性设置为true(两者相同)会执行很多操作。这是本地Windows窗口创建的方式。按照典型的.NET“懒惰”方式,任何试图将Visible设置回false的尝试都将失败。

从技术上讲,这是可能的,您需要覆盖SetVisibleCore()方法。像这样:

    protected override void SetVisibleCore(bool value) {
        if (!this.IsHandleCreated) {
            this.CreateHandle();
            value = false;   // Prevent window from becoming visible
        }
        base.SetVisibleCore(value);
    }

这将确保在第一次调用Show()时窗口不会变为可见。当你有NotifyIcon时很方便,你通常希望将图标直接显示在通知区域,并且只在用户点击图标时显示窗口。需要注意的是,OnLoad()直到窗口实际变为可见才会运行,因此必要时应将代码移动到构造函数或覆盖中。


呃,当我的窗体甚至还没有加载时,拥有通知图标的目的是什么? - Shekhar_Pro
迄今为止最常见的例子是...当您启动Visual Studio时,它首先显示闪屏,然后在完全加载IDE后,添加了客户改进程序的通知图标。 - Shekhar_Pro
1
@Shekhar - 更常见的例子包括电池电量、音量控制、Windows 更新状态、Wifi 连接状态和操作中心。 - Hans Passant
1
@Shekhar - 不可以了,服务现在无法与桌面交互。 - Hans Passant
好的,我不知道那个...谢谢你的信息...(我已经为您的答案投票了) :) - Shekhar_Pro
显示剩余2条评论

9
只是因为f.Show()让窗体再次可见,而f.Close()则关闭它...所以flash也会消失。
如果您查看Form.Show()方法的MSDN文档,它明确说明:
显示控件等效于将Visible属性设置为true。 调用Show方法后,直到调用Hide方法,Visible属性返回true。
如果您不想要flash,请根本不要显示窗体。

4
您需要编辑MyForm类,并添加以下覆盖方法:
protected override void SetVisibleCore(bool value)
{
    //just override here, make sure that the form will never become visible
    if (!IsHandleCreated) CreateHandle();
    value = false;
    base.SetVisibleCore(value);
}

然而,你应该问自己是否真的有必要这样做 - 这可能是设计不良的表现。

编辑: 很少需要这样做,我使用它的唯一情况是当我需要一个可以放置COM组件的表单(因为COM组件需要窗口句柄),并且我必须运行Application.Run(formInstance),它调用窗体的Show方法。通过强制使表单始终不可见,您可以获得窗口句柄和消息循环,而看不到任何屏幕上的内容。


这会允许我稍后显示表单,还是它将始终不可见? - Craig Johnston
我会在你的表单中放置一个变量来启用这种行为,然后你创建你的表单,决定是否允许该实例通过设置该变量变得可见,然后显示表单。 - Alistair Evans
1
这并不罕见。有时候你需要一个隐藏的顶级窗口,仅仅是为了接受来自另一个进程的 Windows 消息。 - Elmue
如何处理只需要通知图标和上下文菜单(而没有主窗体)的情况? - tigrou

0
我创建了一个帮助方法,可以显示隐藏的窗体,并且随后的Show调用将像通常一样显示窗口:
public static class FormHelper
{
    public static void ShowInvisible(this Form form)
    {
        // saving original settings
        bool needToShowInTaskbar = form.ShowInTaskbar;
        WindowState initialWindowState = form.WindowState;

        // making form invisible
        form.ShowInTaskbar = false;
        form.WindowState = FormWindowState.Minimized;

        // showing and hiding form
        form.Show();
        form.Hide();

        // restoring original settings
        form.ShowInTaskbar = needToShowInTaskbar;
        form.WindowState = initialWindowState;
    }
}

因此,表单将被呈现(并且Load事件将被触发),而不会出现任何闪烁。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接