托盘应用开发
设置启动时不显示窗体
通过重写 OnLoad
来实现
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.Visible = false;
this.ShowInTaskbar = false;
}
异常
在构造函数中添加 this.ShowInTaskbar = false;
写了这句,导致窗体一直显示,出现异常
设置托盘图标
注意事项
- NotifyIcon 必须设置图标,否则不会显示
- ContextMenuStrip:作为菜单,可设置菜单勾选
// 创建 NotifyIcon。
this.notifyIcon1 = new NotifyIcon();
this.notifyIcon1.Icon = this.Icon;
this.notifyIcon1.Visible = true;
this.notifyIcon1.MouseDoubleClick += NotifyIcon1_MouseDoubleClick;
// 创建 ContextMenuStrip。
this.notifyIconMenuStrip = new ContextMenuStrip();
// 创建并初始化 ToolStripMenuItem 对象。
ToolStripMenuItem showFormItem = new ToolStripMenuItem("显示窗体");
showFormItem.Click += (object? sender, EventArgs e) =>
{
NotifyIcon1_MouseDoubleClick(sender, null);
};
ToolStripMenuItem item2 = new ToolStripMenuItem("开机自启动") { CheckOnClick = true, Checked = true };
item2.CheckedChanged += (object? sender, EventArgs e) =>
{
bool isAuto = ((ToolStripMenuItem)sender).Checked;
SetAutoStart(isAuto);
};
ToolStripMenuItem item3 = new ToolStripMenuItem("退出");
item3.Click += (object? sender, EventArgs e) =>
{
Application.Exit(); // 退出应用程序
};
// 将 ToolStripMenuItem 对象添加到 ContextMenuStrip 的 Items 集合中。
this.notifyIconMenuStrip.Items.Add(showFormItem);
this.notifyIconMenuStrip.Items.Add(item2);
this.notifyIconMenuStrip.Items.Add(item3);
// ContextMenu 属性设置当右键点击系统托盘图标时显示的菜单。
notifyIcon1.ContextMenuStrip = this.notifyIconMenuStrip;
其他开机启动方式(不推荐)
- 拷贝快捷方式到启动菜单
- 添加任务几乎
设置气泡消息
- 设置消息标题
- 设置消息内容
- 设置消息图标
- 设置显示时间
- 没找到在那里更改程序集的名称,如案例中为
TSCT
它就显示TSCT
notifyIcon1.BalloonTipIcon = ToolTipIcon.Info;
notifyIcon1.BalloonTipTitle = "提示";
notifyIcon1.BalloonTipText = "培训系统被控端已启动";
notifyIcon1.ShowBalloonTip(3000);
设置开机启动
重要部分!!!
实现向其他软件一样的可以通过界面操作设置软件是否开机启动,采用的方式为修改注册表,有几个注意事项
- 不要设置软件为管理员权限启动,这样开机启动无效(有些电脑管理员启动也有效。暂时搞不懂)
- 修改当前用户的注册表(
Registry.CurrentUser
),不要修改本机的注册表(Registry.LocalMachine
),否则会要求管理员权限,从而导致启动失败
string R_startPath = Application.ExecutablePath;
try
{
RegistryKey R_currentUser = Registry.CurrentUser; //不要使用本地,本地的无法开机启动
RegistryKey? R_run = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
if (autoStart)
{
if (R_run == null)
R_run = Registry.CurrentUser.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
R_run.SetValue(Properties.Resources.RegistryKey, R_startPath);
R_run.Close();
OnMsgEventHandler(MsgType.Info, "软件设置自动启动成功!");
}
else
{
if (R_run != null)
{
R_run.DeleteValue(Properties.Resources.RegistryKey);
R_run.Close();
OnMsgEventHandler(MsgType.Info, "软件禁止自动启动成功!");
}
}
}
catch (Exception e)
{
OnMsgEventHandler(MsgType.Info, $"设置软件的开机状态:{autoStart} 出现异常!" + e.Message);
MessageBox.Show("设置软件的开机状态异常,如那件正常启动,但是下次可能不会自动启动", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
全部代码
可能会存在其他类的引用,可自行判断
using System.Windows.Forms;
public partial class Form1 : Form
{
private NotifyIcon notifyIcon1;
private ContextMenuStrip notifyIconMenuStrip;
// 右键菜单
private ContextMenuStrip itemMenuStrip;
public Form1()
{
InitializeComponent();
InitForm();
InitTrayIcon();
/*
软件每次启动,强制设置为开机启动,启动后可手动禁止开机启动
*/
SetAutoStart(true);
}
private void InitForm()
{
OnMsgEventHandler(MsgType.Info, "软件启动");
this.Text = Properties.Resources.AppTitle + $" V{GetVersion()}";
this.Visible = false;
this.StartPosition = FormStartPosition.CenterScreen;
//this.ShowInTaskbar = false; //此语句导致窗体会显示,必须注释
Program.OnMsgEvent += OnMsgEventHandler;
// 初始化右键菜单
itemMenuStrip = new ContextMenuStrip();
ToolStripMenuItem copyMenuItem = new ToolStripMenuItem("复制");
copyMenuItem.Click += CopyMenuItem_Click;
itemMenuStrip.Items.Add(copyMenuItem);
// 绑定右键菜单到ListBox
listBox1.ContextMenuStrip = itemMenuStrip;
listBox1.DrawMode = DrawMode.OwnerDrawVariable;
listBox1.MeasureItem += ListBox1_MeasureItem;
listBox1.DrawItem += listBox1_DrawItem;
listBox1.HorizontalScrollbar = true; // 设置横向滚动条为可见
}
private void OnMsgEventHandler(MsgType type, string message)
{
MsgInfo msg = new MsgInfo() { Message = DateTime.Now.ToString("HH:mm:ss: ") + message, Type = type };
// 判断是否需要在UI线程中执行
if (this.InvokeRequired)
{
// 使用Invoke在UI线程中执行
this.Invoke(new Action(() =>
{
listBox1.DrawMode = DrawMode.OwnerDrawFixed;
this.listBox1.Items.Add(msg);
}));
}
else
{
// 如果已在UI线程中,直接更新UI
this.listBox1.Items.Add(msg);
}
}
private void ListBox1_MeasureItem(object? sender, MeasureItemEventArgs e)
{
e.ItemHeight = (int)e.Graphics.MeasureString(listBox1.Items[e.Index].ToString(), listBox1.Font, listBox1.Width).Height;
}
private void listBox1_DrawItem(object? sender, DrawItemEventArgs e)
{
if (e.Index < 0) return;
e.DrawBackground();
MsgInfo info = (MsgInfo)listBox1.Items[e.Index];
Color color = Color.White;
switch (info.Type)
{
case MsgType.Error:
color = Color.Red;
break;
case MsgType.Warning:
color = Color.Yellow;
break;
case MsgType.Info:
break;
}
e.DrawBackground();
//e.Graphics.DrawString(info.Message, e.Font, new SolidBrush(color), new PointF(e.Bounds.X, e.Bounds.Y));
e.Graphics.DrawString(info.Message, e.Font, new SolidBrush(color), e.Bounds);
// 获取文本的实际宽度,并设置为横向滚动条的最大值
float textWidth = e.Graphics.MeasureString(info.Message, e.Font).Width;
if (textWidth > listBox1.HorizontalExtent)
{
listBox1.HorizontalExtent = (int)textWidth;
}
e.DrawFocusRectangle();
}
private void button1_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
listBox1.HorizontalExtent = 0;
}
private void button2_Click(object sender, EventArgs e)
{
if (listBox1.Items.Count > 10)
{
for (int i = listBox1.Items.Count - 10; i > -1; i--)
{
listBox1.Items.RemoveAt(i);
}
}
UpdateHorizontalScrollBar();
}
// 更新横向滚动条的宽度
private void UpdateHorizontalScrollBar()
{
int maxWidth = 0;
// 计算当前列表中最长文本的宽度
foreach (MsgInfo item in listBox1.Items)
{
int itemWidth = (int)listBox1.CreateGraphics().MeasureString(item.Message, listBox1.Font).Width;
if (itemWidth > maxWidth)
{
maxWidth = itemWidth;
}
}
// 将最长文本的宽度设置为横向滚动条的最大值
if (maxWidth > listBox1.HorizontalExtent)
{
listBox1.HorizontalExtent = maxWidth;
}
}
private void CopyMenuItem_Click(object? sender, EventArgs e)
{
// 获取选定项的文本
string selectedText = "";
foreach (var item in listBox1.SelectedItems)
{
selectedText += ((MsgInfo)item).Message.ToString() + Environment.NewLine;
}
// 将文本放入剪贴板
Clipboard.SetText(selectedText);
}
private void InitTrayIcon()
{
// 创建 NotifyIcon。
this.notifyIcon1 = new NotifyIcon();
this.notifyIcon1.Icon = this.Icon;
this.notifyIcon1.Visible = true;
this.notifyIcon1.MouseDoubleClick += NotifyIcon1_MouseDoubleClick;
// 创建 ContextMenuStrip。
this.notifyIconMenuStrip = new ContextMenuStrip();
// 创建并初始化 ToolStripMenuItem 对象。
ToolStripMenuItem showFormItem = new ToolStripMenuItem("显示窗体");
showFormItem.Click += (object? sender, EventArgs e) =>
{
NotifyIcon1_MouseDoubleClick(sender, null);
};
ToolStripMenuItem item2 = new ToolStripMenuItem("开机自启动") { CheckOnClick = true, Checked = true };
item2.CheckedChanged += (object? sender, EventArgs e) =>
{
bool isAuto = ((ToolStripMenuItem)sender).Checked;
SetAutoStart(isAuto);
};
ToolStripMenuItem item3 = new ToolStripMenuItem("退出");
item3.Click += (object? sender, EventArgs e) =>
{
Application.Exit(); // 退出应用程序
};
// 将 ToolStripMenuItem 对象添加到 ContextMenuStrip 的 Items 集合中。
this.notifyIconMenuStrip.Items.Add(showFormItem);
this.notifyIconMenuStrip.Items.Add(item2);
this.notifyIconMenuStrip.Items.Add(item3);
// ContextMenu 属性设置当右键点击系统托盘图标时显示的菜单。
notifyIcon1.ContextMenuStrip = this.notifyIconMenuStrip;
ShowStartInfo();
}
private void NotifyIcon1_MouseDoubleClick(object? sender, MouseEventArgs e)
{
this.ShowInTaskbar = true;
this.Show(); // 显示窗体
this.WindowState = FormWindowState.Normal; // 恢复窗体正常大小
}
private void UpdateNoticyIconText(bool isAutoStart)
{
string yes = isAutoStart ? "是" : "否";
this.notifyIcon1.Text = $"{Properties.Resources.AppTitle}\n端口:{Program.port}\n开机启动:{yes}";
}
private void ShowStartInfo()
{
notifyIcon1.BalloonTipIcon = ToolTipIcon.Info;
notifyIcon1.BalloonTipTitle = "提示";
notifyIcon1.BalloonTipText = "培训系统被控端已启动";
notifyIcon1.ShowBalloonTip(3000);
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.Visible = false;
this.ShowInTaskbar = false;
}
protected override void OnFormClosing(FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true; // 取消关闭窗体
this.Hide(); // 隐藏窗体
}
}
//开机启动
private void SetAutoStart(bool autoStart)
{
string R_startPath = Application.ExecutablePath;
try
{
RegistryKey R_currentUser = Registry.CurrentUser; //不要使用本地,本地的无法开机启动
RegistryKey? R_run = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
if (autoStart)
{
if (R_run == null)
R_run = Registry.CurrentUser.CreateSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
R_run.SetValue(Properties.Resources.RegistryKey, R_startPath);
R_run.Close();
OnMsgEventHandler(MsgType.Info, "软件设置自动启动成功!");
}
else
{
if (R_run != null)
{
R_run.DeleteValue(Properties.Resources.RegistryKey);
R_run.Close();
OnMsgEventHandler(MsgType.Info, "软件禁止自动启动成功!");
}
}
}
catch (Exception e)
{
OnMsgEventHandler(MsgType.Info, $"设置软件的开机状态:{autoStart} 出现异常!" + e.Message);
MessageBox.Show("设置软件的开机状态异常,如那件正常启动,但是下次可能不会自动启动", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
UpdateNoticyIconText(autoStart);
}
private string GetVersion()
{
return Assembly.GetExecutingAssembly().GetName().Version.ToString();
}
}