2

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.

myelxx
  • 314
  • 3
  • 11
  • 2
    I think [this](https://stackoverflow.com/questions/21171764/how-to-position-the-opening-form-at-specific-location-in-c-sharp-windows-forms) will answer your question – Andrei Solero Jan 16 '21 at 07:11
  • Using [How do I get the taskbar's position and size](https://stackoverflow.com/questions/1264406/how-do-i-get-the-taskbars-position-and-size) and [Taskbar location](https://stackoverflow.com/questions/3677182/taskbar-location) and [Get location and size of TaskBar](https://stackoverflow.com/questions/29330440/get-precise-location-and-size-of-taskbar), you can calculate the desired form location within the [WorkingArea](https://docs.microsoft.com/dotnet/api/system.windows.forms.screen.workingarea). Also take into consideration that the taskbar can be left/right/top/bottom as well as auto-hided. –  Jan 16 '21 at 08:22
  • 2
    Simplified: [How to obtain task bar Notification Area width in a C# program?](https://stackoverflow.com/a/52572859/7444103). See the notes about DpiAwareness. – Jimi Jan 16 '21 at 12:04
  • 1
    *I am planning to create a custom form instead of a context menu since I need to enhance the UI* → Well, if a notify icon and a showing a complex Form/UserControl inside a `ContextMenuStrip` does the trick for you, you can do that. Look at [this example](https://stackoverflow.com/a/33160838/3110834). – Reza Aghaei Jan 16 '21 at 12:32
  • Also if the bottom-right of the screen working area is what you are looking for: then you having `f` as the form you want to show, you can set its location to `new Point(Screen.PrimaryScreen.WorkingArea.Right - f.Width, Screen.PrimaryScreen.WorkingArea.Bottom - f.Height);` and set its start position to manual and show it. But keep in mind, it is the bottom-right of the working area while you may have the taskbar at left/right/top side of the screen! If the exactly tray location is your concern, then Jimi's post handles your concern. – Reza Aghaei Jan 16 '21 at 12:36

2 Answers2

2

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.

0

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;
myelxx
  • 314
  • 3
  • 11