wpf c# 托盘图标应用程序在 30 分钟后终止
wpf c# tray icon app terminates after 30 minutes
以下应用程序在系统托盘图标中显示磁盘 activity。它正常运行大约 30-40 分钟,然后终止,在桌面上留下图标。就好像它作为一个不必要的后台任务被系统杀死了。为什么会发生这种情况,我该如何预防?
public partial class MainWindow : Window
{
public System.Windows.Forms.NotifyIcon ni = new System.Windows.Forms.NotifyIcon();
public MainWindow()
{
InitializeComponent();
ni.Visible = true;
ni.Text = "disktray"; // tooltip text show over tray icon
CreateTextIcon("0");
ni.DoubleClick +=
delegate (object sender, EventArgs args)
{
//this.Show();
//this.WindowState = WindowState.Normal;
ni.Visible = false;
ni.Dispose();
System.Windows.Application.Current.Shutdown();
};
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
CreateTextIcon("0");
DispatcherTimer timer = new DispatcherTimer()
{
Interval = TimeSpan.FromMilliseconds(1024)
};
timer.Tick += Timer_Tick;
timer.Start();
this.Hide();
}
private void Timer_Tick(object sender, EventArgs e)
{
Diskpercent();
string iii = diskpercentvalue.ToString();
CreateTextIcon(iii);
}
public PerformanceCounter myCounter =
new PerformanceCounter("PhysicalDisk", "% Disk Time", "_Total");
public int diskpercentvalue = 0;
public void Diskpercent()
{
var d = Convert.ToInt32(myCounter.NextValue());
if (d > 99) d = 99; // can go over 100%
diskpercentvalue = d;
}
public System.Drawing.Font fontToUse =
new System.Drawing.Font("Microsoft Sans Serif", 16, System.Drawing.FontStyle.Regular, GraphicsUnit.Pixel);
public System.Drawing.Brush brushToUse = new SolidBrush(System.Drawing.Color.White);
public Bitmap bitmapText = new Bitmap(16, 16);
public IntPtr hIcon;
public void CreateTextIcon(string str)
{
//System.Drawing.Font fontToUse = new System.Drawing.Font("Microsoft Sans Serif", 16, System.Drawing.FontStyle.Regular, GraphicsUnit.Pixel);
//System.Drawing.Brush brushToUse = new SolidBrush(System.Drawing.Color.White);
//Bitmap bitmapText = new Bitmap(16, 16);
Graphics g = System.Drawing.Graphics.FromImage(bitmapText);
//IntPtr hIcon;
g.Clear(System.Drawing.Color.Transparent);
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
g.DrawString(str, fontToUse, brushToUse, -4, -2);
hIcon = (bitmapText.GetHicon());
ni.Icon = System.Drawing.Icon.FromHandle(hIcon);
}
}
转到 App.xaml.cs 并像下面那样实现它。诀窍是永远不要关闭 MainWindow,因为关闭的 Window 无法再次显示。而是取消关闭并隐藏它。
using System.ComponentModel;
using System.Windows;
namespace BackgroundApplication
{
public partial class App : Application
{
private System.Windows.Forms.NotifyIcon _notifyIcon;
private bool _isExit;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainWindow = new MainWindow();
MainWindow.Closing += MainWindow_Closing;
_notifyIcon = new System.Windows.Forms.NotifyIcon();
_notifyIcon.DoubleClick += (s, args) => ShowMainWindow();
_notifyIcon.Icon = BackgroundApplication.Properties.Resources.MyIcon;
_notifyIcon.Visible = true;
CreateContextMenu();
}
private void CreateContextMenu()
{
_notifyIcon.ContextMenuStrip =
new System.Windows.Forms.ContextMenuStrip();
_notifyIcon.ContextMenuStrip.Items.Add("MainWindow...").Click += (s, e) => ShowMainWindow();
_notifyIcon.ContextMenuStrip.Items.Add("Exit").Click += (s, e) => ExitApplication();
}
private void ExitApplication()
{
_isExit = true;
MainWindow.Close();
_notifyIcon.Dispose();
_notifyIcon = null;
}
private void ShowMainWindow()
{
if (MainWindow.IsVisible)
{
if (MainWindow.WindowState == WindowState.Minimized)
{
MainWindow.WindowState = WindowState.Normal;
}
MainWindow.Activate();
}
else
{
MainWindow.Show();
}
}
private void MainWindow_Closing(object sender, CancelEventArgs e)
{
if (!_isExit)
{
e.Cancel = true;
MainWindow.Hide(); // A hidden window can be shown again, a closed one not
}
}
}
}
去App.xaml除掉Startup-Uri,这样当你启动应用程序时,只有NotifyIcon被添加到通知区域
<Application x:Class="BackgroundApplication.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BackgroundApplication">
<Application.Resources>
</Application.Resources>
</Application>
取自:
https://www.thomasclaudiushuber.com/2015/08/22/creating-a-background-application-with-wpf/
注意:如果你想访问变量,你在App.xaml.cs中创建一个public只读属性:
public System.Windows.Forms.NotifyIcon NotifyIcon { get { return _notifyIcon; } }
然后你可以像这样在 MainWindow 中使用它:
((App)App.Current).NotifyIcon
此行导致内存泄漏:
hIcon = (bitmapText.GetHicon());
hIcon需要销毁:
hIcon = (bitmapText.GetHicon());
ni.Icon = System.Drawing.Icon.FromHandle(hIcon);
DestroyIcon(hIcon);
将此代码添加到 class 以定义 DestroyIcon:
[DllImport("user32.dll", SetLastError = true)]
static extern bool DestroyIcon(IntPtr hIcon);
参见:
https://msdn.microsoft.com/en-us/library/system.drawing.icon.fromhandle(v=vs.110).aspx
以下应用程序在系统托盘图标中显示磁盘 activity。它正常运行大约 30-40 分钟,然后终止,在桌面上留下图标。就好像它作为一个不必要的后台任务被系统杀死了。为什么会发生这种情况,我该如何预防?
public partial class MainWindow : Window
{
public System.Windows.Forms.NotifyIcon ni = new System.Windows.Forms.NotifyIcon();
public MainWindow()
{
InitializeComponent();
ni.Visible = true;
ni.Text = "disktray"; // tooltip text show over tray icon
CreateTextIcon("0");
ni.DoubleClick +=
delegate (object sender, EventArgs args)
{
//this.Show();
//this.WindowState = WindowState.Normal;
ni.Visible = false;
ni.Dispose();
System.Windows.Application.Current.Shutdown();
};
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
CreateTextIcon("0");
DispatcherTimer timer = new DispatcherTimer()
{
Interval = TimeSpan.FromMilliseconds(1024)
};
timer.Tick += Timer_Tick;
timer.Start();
this.Hide();
}
private void Timer_Tick(object sender, EventArgs e)
{
Diskpercent();
string iii = diskpercentvalue.ToString();
CreateTextIcon(iii);
}
public PerformanceCounter myCounter =
new PerformanceCounter("PhysicalDisk", "% Disk Time", "_Total");
public int diskpercentvalue = 0;
public void Diskpercent()
{
var d = Convert.ToInt32(myCounter.NextValue());
if (d > 99) d = 99; // can go over 100%
diskpercentvalue = d;
}
public System.Drawing.Font fontToUse =
new System.Drawing.Font("Microsoft Sans Serif", 16, System.Drawing.FontStyle.Regular, GraphicsUnit.Pixel);
public System.Drawing.Brush brushToUse = new SolidBrush(System.Drawing.Color.White);
public Bitmap bitmapText = new Bitmap(16, 16);
public IntPtr hIcon;
public void CreateTextIcon(string str)
{
//System.Drawing.Font fontToUse = new System.Drawing.Font("Microsoft Sans Serif", 16, System.Drawing.FontStyle.Regular, GraphicsUnit.Pixel);
//System.Drawing.Brush brushToUse = new SolidBrush(System.Drawing.Color.White);
//Bitmap bitmapText = new Bitmap(16, 16);
Graphics g = System.Drawing.Graphics.FromImage(bitmapText);
//IntPtr hIcon;
g.Clear(System.Drawing.Color.Transparent);
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
g.DrawString(str, fontToUse, brushToUse, -4, -2);
hIcon = (bitmapText.GetHicon());
ni.Icon = System.Drawing.Icon.FromHandle(hIcon);
}
}
转到 App.xaml.cs 并像下面那样实现它。诀窍是永远不要关闭 MainWindow,因为关闭的 Window 无法再次显示。而是取消关闭并隐藏它。
using System.ComponentModel;
using System.Windows;
namespace BackgroundApplication
{
public partial class App : Application
{
private System.Windows.Forms.NotifyIcon _notifyIcon;
private bool _isExit;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainWindow = new MainWindow();
MainWindow.Closing += MainWindow_Closing;
_notifyIcon = new System.Windows.Forms.NotifyIcon();
_notifyIcon.DoubleClick += (s, args) => ShowMainWindow();
_notifyIcon.Icon = BackgroundApplication.Properties.Resources.MyIcon;
_notifyIcon.Visible = true;
CreateContextMenu();
}
private void CreateContextMenu()
{
_notifyIcon.ContextMenuStrip =
new System.Windows.Forms.ContextMenuStrip();
_notifyIcon.ContextMenuStrip.Items.Add("MainWindow...").Click += (s, e) => ShowMainWindow();
_notifyIcon.ContextMenuStrip.Items.Add("Exit").Click += (s, e) => ExitApplication();
}
private void ExitApplication()
{
_isExit = true;
MainWindow.Close();
_notifyIcon.Dispose();
_notifyIcon = null;
}
private void ShowMainWindow()
{
if (MainWindow.IsVisible)
{
if (MainWindow.WindowState == WindowState.Minimized)
{
MainWindow.WindowState = WindowState.Normal;
}
MainWindow.Activate();
}
else
{
MainWindow.Show();
}
}
private void MainWindow_Closing(object sender, CancelEventArgs e)
{
if (!_isExit)
{
e.Cancel = true;
MainWindow.Hide(); // A hidden window can be shown again, a closed one not
}
}
}
}
去App.xaml除掉Startup-Uri,这样当你启动应用程序时,只有NotifyIcon被添加到通知区域
<Application x:Class="BackgroundApplication.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BackgroundApplication">
<Application.Resources>
</Application.Resources>
</Application>
取自:
https://www.thomasclaudiushuber.com/2015/08/22/creating-a-background-application-with-wpf/
注意:如果你想访问变量,你在App.xaml.cs中创建一个public只读属性:
public System.Windows.Forms.NotifyIcon NotifyIcon { get { return _notifyIcon; } }
然后你可以像这样在 MainWindow 中使用它:
((App)App.Current).NotifyIcon
此行导致内存泄漏:
hIcon = (bitmapText.GetHicon());
hIcon需要销毁:
hIcon = (bitmapText.GetHicon());
ni.Icon = System.Drawing.Icon.FromHandle(hIcon);
DestroyIcon(hIcon);
将此代码添加到 class 以定义 DestroyIcon:
[DllImport("user32.dll", SetLastError = true)]
static extern bool DestroyIcon(IntPtr hIcon);
参见:
https://msdn.microsoft.com/en-us/library/system.drawing.icon.fromhandle(v=vs.110).aspx