You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
using System; using System.ComponentModel; using System.Diagnostics; using System.Drawing; using System.IO; using System.Security; using System.Security.Permissions; using System.ServiceProcess; using System.Threading; using System.Windows.Forms;
namespace Apewer.WinForm {
/// <summary>通用托盘。</summary>
public sealed class Tray : IDisposable {
#region icon
NotifyIcon _origin = null;
/// <summary>通知图标。</summary>
NotifyIcon Icon { get => _origin; }
/// <summary>鼠标点击通知图标时执行的程序。</summary>
public Action OnClick { get; set; }
/// <summary>鼠标点击通知图标时执行的程序。</summary>
public Action OnDoubleClick { get; set; }
/// <summary>设置图标。</summary>
public void SetIcon(Icon icon) { if (_disposed) throw new ObjectDisposedException(ToString());
ClearIcon(); SyncInvoke(() => { if (icon == null) { _origin.Visible = false; } else { _origin.Icon = icon; _origin.Visible = true; } }); }
/// <summary>设置标题。</summary>
public void SetTitle(string title) { if (_disposed) throw new ObjectDisposedException(ToString()); if (_origin != null) { SyncInvoke(() => { _origin.Text = title; }); } }
void ClearIcon() { SyncInvoke(() => { if (_origin != null) { var old = _origin.Icon; _origin.Icon = null; RuntimeUtility.Dispose(old); } }); }
/// <summary>获取 EXE 文件的图标。</summary>
public static Icon GetExeIcon() { var exePath = RuntimeUtility.ExecutablePath; var exeIcon = System.Drawing.Icon.ExtractAssociatedIcon(exePath); return exeIcon; }
/// <summary>获取 EXE 文件的图标。</summary>
/// <exception cref="ArgumentNullException" />
/// <exception cref="FileNotFoundException" />
public static Icon GetExeIcon(string filePath) { if (filePath.IsEmpty()) throw new ArgumentNullException(nameof(filePath)); if (!File.Exists(filePath)) throw new FileNotFoundException($"文件【{filePath}】不存在。"); var icon = System.Drawing.Icon.ExtractAssociatedIcon(filePath); return icon; }
#endregion
#region tip
/// <summary>鼠标点击弹出提示时执行的程序。</summary>
public Action OnTipClick { get; set; }
/// <summary>显示悬浮通知。</summary>
/// <exception cref="ObjectDisposedException"></exception>
public void ShowTip(string text, string title = null, ToolTipIcon icon = ToolTipIcon.None) { if (_disposed) throw new ObjectDisposedException(ToString()); if (text.IsEmpty()) return; _origin?.ShowBalloonTip(5000, title, text, icon); }
#endregion
#region menu
/// <summary>清除右键菜单。</summary>
public void ClearMenu() { if (_disposed) throw new ObjectDisposedException(ToString());
SyncInvoke(() => { #if NETFRAMEWORK
if (_origin.ContextMenu != null) { var old = _origin.ContextMenu; _origin.ContextMenu = null; RuntimeUtility.Dispose(old); } #endif
if (_origin.ContextMenuStrip != null) { var old = _origin.ContextMenuStrip; _origin.ContextMenuStrip = null; RuntimeUtility.Dispose(old); } }); }
/// <summary>设置右键菜单。</summary>
public void SetMenu(MenuItem[] menu) { ClearMenu(); if (menu == null) return; #if NETFRAMEWORK
SetMenu(menu.ContextMenu()); #else
SetMenu(menu.ContextMenuStrip()); #endif
}
#if NETFRAMEWORK
/// <summary>设置右键菜单。</summary>
public void SetMenu(ContextMenu menu) { if (_disposed) throw new ObjectDisposedException(ToString());
ClearMenu(); SyncInvoke(() => { if (menu != null) _origin.ContextMenu = menu; }); }
#endif
/// <summary>设置右键菜单。</summary>
public void SetMenu(ContextMenuStrip menu) { if (_disposed) throw new ObjectDisposedException(ToString());
ClearMenu(); SyncInvoke(() => { if (menu != null) _origin.ContextMenuStrip = menu; }); }
#endregion
#region instance
bool _disposed = false; SynchronizationContext _sync = null; Form _form = null; Action<Tray> _action = null;
/// <summary></summary>
/// <exception cref="InvalidOperationException"></exception>
public Tray(Action<Tray> action) { _sync = SynchronizationContext.Current; if (_sync == null) throw new InvalidOperationException($"当前线程无法启动 {nameof(Tray)} 实例。");
_origin = new NotifyIcon(); _origin.Click += (s, e) => OnClick?.Invoke(); _origin.DoubleClick += (s, e) => OnDoubleClick?.Invoke(); _origin.BalloonTipClicked += (s, e) => OnTipClick?.Invoke();
_form = new Form(); _form.FormBorderStyle = FormBorderStyle.None; _form.Opacity = 0; _form.ShowInTaskbar = false; _form.Size = new Size(0, 0); _form.StartPosition = FormStartPosition.CenterScreen; _form.TopMost = true;
_action = action; _form.Load += Load; _form.Show(); _form.Visible = false; }
/// <summary></summary>
public void Dispose() { if (_disposed) throw new ObjectDisposedException(ToString());
ClearMenu(); ClearIcon();
_origin.Dispose(); _origin = null;
_form.Dispose(); _form = null;
_disposed = true; }
void Load(object sender, EventArgs e) { RuntimeUtility.InBackground(() => { _action?.Invoke(this); }); }
/// <summary></summary>
public void SyncInvoke(Action action) { if (action == null) return;
if (_sync == null) action.Invoke(); else _sync.Send(state => action.Invoke(), null); }
/// <summary></summary>
public void FormInvoke(Action action) { if (action == null) return; if (_form == null) return; if (_form.InvokeRequired) { _form.Invoke(action); return; }
action.Invoke(); }
/// <summary></summary>
public void FormBeginInvoke(Action action) { if (action == null) return; if (_form == null) return; _form.BeginInvoke(action); }
/// <summary>显示对话框,并获取结果。</summary>
/// <exception cref="ArgumentNullException" />
public DialogResult ShowDialog(CommonDialog dialog) { if (_disposed) throw new ObjectDisposedException(ToString()); if (dialog == null) throw new ArgumentNullException(nameof(dialog));
if (_form.InvokeRequired) { var result = default(DialogResult); _form.Invoke(() => { _form.Visible = true; result = dialog.ShowDialog(); _form.Visible = false; }); return result; }
return dialog.ShowDialog(); }
/// <summary></summary>
public void Exit() { if (!_disposed) Dispose(); Application.Exit(); }
/// <summary></summary>
public void Exit(Action customExit) { if (!_disposed) Dispose(); customExit.Invoke(); }
#endregion
#region run
/// <summary>已启动的服务名称。</summary>
public static string ServiceName { get; private set; }
/// <summary>在当前线程运行托盘程序,并启动消息循环。</summary>
/// <param name="action">启动托盘后执行的程序。</param>
/// <exception cref="ArgumentNullException" />
[STAThread] public static void Run(Action<Tray> action) { if (action == null) throw new ArgumentNullException(nameof(action));
Control.CheckForIllegalCrossThreadCalls = false; Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false);
if (SynchronizationContext.Current == null) { var sc = AsyncOperationManager.SynchronizationContext; if (sc == null || sc.GetType() == typeof(SynchronizationContext)) { new PermissionSet(PermissionState.Unrestricted).Assert(); try { AsyncOperationManager.SynchronizationContext = new WindowsFormsSynchronizationContext(); } finally { CodeAccessPermission.RevertAssert(); } } }
var instance = new Tray(action); // action.Invoke(instance);
Application.Run(); }
/// <summary>启动服务。</summary>
/// <param name="onStart">服务启动后执行的程序。</param>
/// <param name="onStop">停止服务时执行的程序。</param>
public static void Service(Action onStart, Action onStop = null) { var processName = Process.GetCurrentProcess().ProcessName; var service = new TrayService(processName, onStart, onStop); ServiceBase.Run(service); }
class TrayService : ServiceBase {
Action on_start; Action on_stop;
public TrayService(string serviceName, Action onStart, Action onStop) { if (serviceName.IsEmpty()) throw new ArgumentNullException(nameof(serviceName)); if (onStart == null) throw new ArgumentNullException(nameof(onStart)); ServiceName = serviceName; on_start = onStart; on_stop = onStop; }
protected override void OnStart(string[] args) => RuntimeUtility.InBackground(on_start);
protected override void OnStop() => on_stop?.Invoke();
}
#endregion
}
}
|