如何根据任务栏系统托盘图标的位置设置通知自定义表单的位置在正上方或下方?

How to set the location of a notification custom form just above or below depending on the position of the system Tray Icon of the Taskbar?

有没有办法在c# winforms中识别系统托盘的位置?

我想创建一个表格,将放置在系统托盘上方或下方,具体取决于系统托盘的位置。

我打算创建一个自定义表单而不是上下文菜单,因为我需要增强 UI 但我对如何将我的表单 above/below 放置在系统托盘中感到困惑。

我附上了我想象的表格位置的图片。

我试图查看您的参考资料,并基于此有了一个想法,这是解决方法:

  1. 创建了 notifyicon 控件,然后在点击方法上设置方法来调用我的表单
  2. 表单将显示在鼠标位置上方,因为无论工具箱的位置如何,notifyicon 控件始终位于系统托盘上。

通过鼠标定位表单的代码片段

 var form = new Form1();
                    form.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
                    form.SetDesktopLocation(MousePosition.X - form.Width / 2, MousePosition.Y - form.Height - 20);
                    form.Show();
                    form.Activate();
                    form.TopMost = true;

使用此 post 获取任务栏的坐标:

Taskbar location

static public Rectangle GetTaskbarCoordonates()
{
  var data = new NativeMethods.APPBARDATA();
  data.cbSize = Marshal.SizeOf(data);
  IntPtr retval = NativeMethods.SHAppBarMessage(NativeMethods.ABM_GETTASKBARPOS, ref data);
  if ( retval == IntPtr.Zero ) 
    throw new Win32Exception("Windows Taskbar Error in " + nameof(GetTaskbarCoordonates));
  return new Rectangle(data.rc.left, data.rc.top,
                       data.rc.right - data.rc.left, data.rc.bottom - data.rc.top);
}

此方法returns任务栏到屏幕边缘的锚点样式:

public const int TaskbarWidthCheckTrigger = 250;

static public AnchorStyles GetTaskbarAnchorStyle()
{
  var coordonates = GetTaskbarCoordonates();
  if ( coordonates.Left == 0 && coordonates.Top == 0 )
    if ( coordonates.Width > TaskbarWidthCheckTrigger )
      return AnchorStyles.Top;
    else
      return AnchorStyles.Left;
  else
  if ( coordonates.Width > TaskbarWidthCheckTrigger )
    return AnchorStyles.Bottom;
  else
    return AnchorStyles.Right;
}

这个值 250 是任意的,可以在特殊条件下校准或更改为更好的东西。

然后我们可以使用上面的post来精确计算自定义工具提示通知表单的所需位置,同时考虑任务栏的边缘位置以及托盘图标的位置和大小。

或者我们可以简单地确定窗体的角:

  • 顶部 => 右上角
  • 左 => 左下角
  • 底部 => 右下角
  • 右 => 右下角

例如:

var form = new Form();
form.StartPosition = FormStartPosition.Manual;
var anchor = DisplayManager.GetTaskbarAnchorStyle();
switch ( anchor )
{
  case AnchorStyles.Top:
    form.SetLocation(ControlLocation.TopRight);
    break;
  case AnchorStyles.Left:
    form.SetLocation(ControlLocation.BottomLeft);
    break;
  case AnchorStyles.Bottom:
  case AnchorStyles.Right:
    form.SetLocation(ControlLocation.BottomRight);
    break;
}
form.Show();

拥有:

static public void SetLocation(this Form form, ControlLocation location)
{
  if ( form == null ) return;
  var area = SystemInformation.WorkingArea;
  switch ( location )
  {
    case ControlLocation.TopLeft:
      form.Location = new Point(area.Left, area.Top);
      break;
    case ControlLocation.TopRight:
      form.Location = new Point(area.Left + area.Width - form.Width, area.Top);
      break;
    case ControlLocation.BottomLeft:
      form.Location = new Point(area.Left, area.Top + area.Height - form.Height);
      break;
    case ControlLocation.BottomRight:
      form.Location = new Point(area.Left + area.Width - form.Width,
                                area.Top + area.Height - form.Height);
      break;
    case ControlLocation.Center:
      form.Center(area);
      break;
    case ControlLocation.Fixed:
      form.CenterToMainFormElseScreen();
      break;
    case ControlLocation.Loose:
      break;
    default:
      throw new NotImplementedExceptionEx(location);
  }
}

还有那个:

[Serializable]
public enum ControlLocation
{
  Loose,
  TopLeft,
  TopRight,
  BottomLeft,
  BottomRight,
  Center,
  Fixed
}

备注:此方法仅适用于主屏幕,应适配其他屏幕。