从系统托盘 Winforms 导航到另一个表单
Navigate to Another Form from System Tray Winforms
我正在开发一个 WinForms 应用程序,我试图在关闭时将表单最小化到系统尝试,而当从系统托盘打开时我想直接转到主应用程序而无需再次登录。
重点是减少进入主应用程序的登录尝试,应用程序应 运行 在后台运行,直到帐户持有人退出应用程序并看到登录屏幕。
这就是我要做的
Program.cs
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Splashscreen());
Application.Run(new SignIn());
}
这是我从登录表单导航到主应用程序的方式
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
waitForm.Close();
this.Hide();
//Nothing to do with this system tray problem, just checking for another valid condition
if(condition == true)
{
MainApp mainapp = new MainApp();
mainapp.ShowDialog();
}
this.Close();
}
登录后进入的主应用
private void MainApp_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
notifyIcon1.Visible = true;
notifyIcon1.ShowBalloonTip(500);
this.Hide();
e.Cancel = true;
}
}
private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
{
this.Show();
notifyIcon1.Visible = false;
WindowState = FormWindowState.Normal;
}
但是,当我执行此操作时,系统托盘图标消失并且无法转到指定页面。在实现这一目标方面有什么想法或经验吗?
提前谢谢大家!
我有一些很久以前(十多年前)挖出来的代码。 Windows10有点破,所以最近有一些改动。您要做的一件事(如果您要取消关闭)是处理 WmQueryEndSession
和 WmEndSession
消息 - 否则您的应用程序将阻止系统关闭。
private const int WmQueryEndSession=0x11;
private const int WmEndSession=0x16;
这里是一些工作代码的摘录。它只是来自存档的 copy/paste。我没有 VS 系统,我现在可以测试这段代码。
这是结束会话代码:
//needed to get this thing to close cleanly. OnSessionEnding and OnSessionEnded didn't work
protected override void WndProc(ref Message m){
switch(m.Msg){
case WmQueryEndSession:
m.Result=(IntPtr) 1; //basically "e.Cancel = false;"
goto case WmEndSession;
case WmEndSession:
forceExit=true;
Close();
return;
default:
base.WndProc(ref m);
break;
}
}
请注意,关于 OnSessionEnding
和 OnSessionEnded
的评论可能来自框架 v1.x 时代;今天可能不是这样
forceExit
标志最初为 false。当用户在按住控制键的情况下单击关闭按钮或从上下文菜单中选择 Quit
时,它会被设置。
private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
if(forceExit)
return; //close and quit
//otherwise
forceExit=false;
if(!ModifierKeys.HasFlag(Keys.Control)) {
WindowState=FormWindowState.Minimized;
e.Cancel=true;
}
}
我的上下文菜单中有一个 Restore
选项(这就是恢复表单的方式)。此应用程序在 通知区域 (也称为 系统托盘 )中的用途最大。在恢复后的状态下,它主要用于更改应用程序设置等。根据评论,我需要在 Win10 出来后 fiddle 这里做一些事情:
private void RestoreCmd_Click(object sender, EventArgs e) {
Show();
//restoring from initially minimized on Windows 10 seems to completely mess up all the control positions and sizes
//so store everything here and restore it below
Dictionary<Control, (Point location, Size size)> controlPositions = null;
if (textBox1.Size.Width != 0)
{
controlPositions = new Dictionary<Control, (Point pos, Size size)>();
foreach (var ctrl in this.Controls.Cast<Control>())
{
controlPositions.Add(ctrl, (location: ctrl.Location, size:ctrl.Size));
}
}
WindowState=FormWindowState.Normal;
//restore all the control positions and sizes
if (controlPositions != null)
{
foreach (var position in controlPositions)
{
position.Key.Size = position.Value.size;
position.Key.Location = position.Value.location;
}
}
}
上下文菜单中有 Hide
和 Quit
个条目:
private void HideCmd_Click(object sender, EventArgs e) {
WindowState=FormWindowState.Minimized;
}
private void QuitCmd_Click(object sender, EventArgs e) {
forceExit=true;
Close();
}
这个应用程序有很多功能。我想我已经提取了所有 show/hide 管理并将其放入此答案中。如果我遗漏了什么,请告诉我。
问题是,隐藏表单会结束 ShowDialog()
模态循环。因此,在 backgroundWorker1_RunWorkerCompleted
中,当 MainApp
表单被隐藏并退出 main 方法中的 Application.Run()
循环时,您的 SignIn
表单将关闭。在您现有的代码中查看我的评论:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
waitForm.Close();
this.Hide();
//Nothing to do with this system tray problem, just checking for another valid condition
if(condition == true)
{
MainApp mainapp = new MainApp();
// this method will exit when mainapp will be hidden:
mainapp.ShowDialog();
}
// this will exit your Application.Run(new SignIn()) in the static Main methods:
this.Close();
}
如您所说,成功登录后不需要 SignIn
实例,您可以按如下方式更改您的应用程序。
在 SignIn
表单中更改如下方法:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
waitForm.Close();
//Nothing to do with this system tray problem, just checking for another valid condition
DialogResult = condition ? DialogResult.OK : DialogResult.Cancel;
}
这样您就可以在 Program.cs
中的 Main
方法中使用 SignIn
的 DialogResult
:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Splashscreen());
using (var signIn = new SignIn())
{
switch (signIn.ShowDialog())
{
case DialogResult.OK:
break;
default:
return;
}
}
Application.Run(new MainApp());
}
其余代码乍一看还不错。
我正在开发一个 WinForms 应用程序,我试图在关闭时将表单最小化到系统尝试,而当从系统托盘打开时我想直接转到主应用程序而无需再次登录。 重点是减少进入主应用程序的登录尝试,应用程序应 运行 在后台运行,直到帐户持有人退出应用程序并看到登录屏幕。
这就是我要做的
Program.cs
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Splashscreen());
Application.Run(new SignIn());
}
这是我从登录表单导航到主应用程序的方式
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
waitForm.Close();
this.Hide();
//Nothing to do with this system tray problem, just checking for another valid condition
if(condition == true)
{
MainApp mainapp = new MainApp();
mainapp.ShowDialog();
}
this.Close();
}
登录后进入的主应用
private void MainApp_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
notifyIcon1.Visible = true;
notifyIcon1.ShowBalloonTip(500);
this.Hide();
e.Cancel = true;
}
}
private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
{
this.Show();
notifyIcon1.Visible = false;
WindowState = FormWindowState.Normal;
}
但是,当我执行此操作时,系统托盘图标消失并且无法转到指定页面。在实现这一目标方面有什么想法或经验吗?
提前谢谢大家!
我有一些很久以前(十多年前)挖出来的代码。 Windows10有点破,所以最近有一些改动。您要做的一件事(如果您要取消关闭)是处理 WmQueryEndSession
和 WmEndSession
消息 - 否则您的应用程序将阻止系统关闭。
private const int WmQueryEndSession=0x11;
private const int WmEndSession=0x16;
这里是一些工作代码的摘录。它只是来自存档的 copy/paste。我没有 VS 系统,我现在可以测试这段代码。
这是结束会话代码:
//needed to get this thing to close cleanly. OnSessionEnding and OnSessionEnded didn't work
protected override void WndProc(ref Message m){
switch(m.Msg){
case WmQueryEndSession:
m.Result=(IntPtr) 1; //basically "e.Cancel = false;"
goto case WmEndSession;
case WmEndSession:
forceExit=true;
Close();
return;
default:
base.WndProc(ref m);
break;
}
}
请注意,关于 OnSessionEnding
和 OnSessionEnded
的评论可能来自框架 v1.x 时代;今天可能不是这样
forceExit
标志最初为 false。当用户在按住控制键的情况下单击关闭按钮或从上下文菜单中选择 Quit
时,它会被设置。
private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
if(forceExit)
return; //close and quit
//otherwise
forceExit=false;
if(!ModifierKeys.HasFlag(Keys.Control)) {
WindowState=FormWindowState.Minimized;
e.Cancel=true;
}
}
我的上下文菜单中有一个 Restore
选项(这就是恢复表单的方式)。此应用程序在 通知区域 (也称为 系统托盘 )中的用途最大。在恢复后的状态下,它主要用于更改应用程序设置等。根据评论,我需要在 Win10 出来后 fiddle 这里做一些事情:
private void RestoreCmd_Click(object sender, EventArgs e) {
Show();
//restoring from initially minimized on Windows 10 seems to completely mess up all the control positions and sizes
//so store everything here and restore it below
Dictionary<Control, (Point location, Size size)> controlPositions = null;
if (textBox1.Size.Width != 0)
{
controlPositions = new Dictionary<Control, (Point pos, Size size)>();
foreach (var ctrl in this.Controls.Cast<Control>())
{
controlPositions.Add(ctrl, (location: ctrl.Location, size:ctrl.Size));
}
}
WindowState=FormWindowState.Normal;
//restore all the control positions and sizes
if (controlPositions != null)
{
foreach (var position in controlPositions)
{
position.Key.Size = position.Value.size;
position.Key.Location = position.Value.location;
}
}
}
上下文菜单中有 Hide
和 Quit
个条目:
private void HideCmd_Click(object sender, EventArgs e) {
WindowState=FormWindowState.Minimized;
}
private void QuitCmd_Click(object sender, EventArgs e) {
forceExit=true;
Close();
}
这个应用程序有很多功能。我想我已经提取了所有 show/hide 管理并将其放入此答案中。如果我遗漏了什么,请告诉我。
问题是,隐藏表单会结束 ShowDialog()
模态循环。因此,在 backgroundWorker1_RunWorkerCompleted
中,当 MainApp
表单被隐藏并退出 main 方法中的 Application.Run()
循环时,您的 SignIn
表单将关闭。在您现有的代码中查看我的评论:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
waitForm.Close();
this.Hide();
//Nothing to do with this system tray problem, just checking for another valid condition
if(condition == true)
{
MainApp mainapp = new MainApp();
// this method will exit when mainapp will be hidden:
mainapp.ShowDialog();
}
// this will exit your Application.Run(new SignIn()) in the static Main methods:
this.Close();
}
如您所说,成功登录后不需要 SignIn
实例,您可以按如下方式更改您的应用程序。
在 SignIn
表单中更改如下方法:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
waitForm.Close();
//Nothing to do with this system tray problem, just checking for another valid condition
DialogResult = condition ? DialogResult.OK : DialogResult.Cancel;
}
这样您就可以在 Program.cs
中的 Main
方法中使用 SignIn
的 DialogResult
:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Splashscreen());
using (var signIn = new SignIn())
{
switch (signIn.ShowDialog())
{
case DialogResult.OK:
break;
default:
return;
}
}
Application.Run(new MainApp());
}
其余代码乍一看还不错。