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?

Viewed 575

Is there a way to recognize the position of system tray in c# winforms?

enter image description here

I want to create a form that will place above or below the system tray depends on where the system tray is the position.

I am planning to create a custom form instead of a context menu since I need to enhance the UI but I am confused about how will position my form above/below the system tray.

I attached the image of how I imagine my form will be position.

2 Answers

Using this post to get the Taskbar's coordonates:

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);
}

This method returns the anchor style of the taskbar to the edge of the screen:

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;
}

This value 250 is arbitrary and can be calibrated under special conditions or changed for a better thing.

Then we can use the above post to precisely calculate the desired position of the custom tooltip notification form, considering the edge location of the taskbar as well as the location and size of the Tray Icon.

Or we can simply determine the form's corner:

  • Top => top-right
  • Left => bottom-left
  • Bottom => bottom-right
  • Rigth => bottom-right

For example:

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();

Having:

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);
  }
}

And that:

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

Remark: This works only for the primary screen and it should be adapted to use another.

I tried to look at your references and I had an idea based on that and here is the fix:

  1. Created notifyicon control then set is method on click method to call my form
  2. The form will be displayed above the position of the mouse since the notifyicon control is always placed on the system tray whatever the position of the toolbox might be.

Code snippet for position your form via mouse position

 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;
Related