C# Screen Class member methods cannot open form on secondary display - c#

There are some methods from the Screen class to retrieve the respective screen, which contains the most area of a control.
They are the:
Screen.FromRectangle(Rectangle rect)
Screen.FromControl(Control control)
Screen.FromHandle(IntPtr hwnd)
Screen.FromPoint(Point point)
The issue here is that I have a problem getting my second Form to be opened in the second monitor. It kept on displaying only on the primary screen. According to the answer from here, the suspect is that the DpiAware was not enabled. However, the problem was still not fixed even after I have enabled the DpiAware.
To help me to check what was going on, I've added code for debugging. Then, I called/ opened the popup menu on \\\\.\\DISPLAY2. Inside of the debug console, the chosen Screen for FromPoint() was written \\\\.\\DISPLAY2. However, the popup menu was still opened on \\\\.\\DISPLAY1. Can anyone help me with this issue, please?
Below are the codes example:
Under main form class:
//mouseup event handler
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
//if RMB clicked
if(e.Button == MouseButtons.Right)
{
//----set PopupMenu form location----
popupMenuObj.Location = popupMenuObj.popupMenuLocation((sender as Control).PointToScreen(e.Location));
//----set PopupMenu form location----
//process the form location
popupMenuObj.Location = popupMenuObj.processFormLocation(popupMenuObj.Location);
//----set PopupMenu cursor location----
Cursor.Position = popupMenuObj.middleOfPopupMenu(popupMenuObj.Location);
//----set PopupMenu cursor location----
//----display the popup menu----
popupMenuObj.displayPopupMenu(1);
//----display the popup menu----
}
}
Under popup menu class:
//to set cursor to middle of popup menu
public Point middleOfPopupMenu(Point mousePoint)
{
int theCenterWidth = this.Width / 2;
int theCenterHeight = this.Height / 2;
//set the mouse pointer location at middle of PopupMenu
mousePoint.X += theCenterWidth;
mousePoint.Y += theCenterHeight;
return Cursor.Position = mousePoint;
}
//to set popupmenu location
public Point popupMenuLocation(Point thePoint)
{
return this.Location = thePoint;
}
//set popup menu display status
public bool displayPopupMenu(int displayFlag)
{
switch(displayFlag)
{
case 1: //if argument 1 -> display the PopupMenu
this.Visible = true;
return true;
case 0: //if argument 0 -> close the PopupMenu
this.Visible = false;
return false;
default: //by default, no need to display
return false;
}
}
//to process if popupmenu opens exceeding the screen working area
public Point processFormLocation(Point currentPoint)
{
Point newPoint = new Point();
int selectedScrWidth, selectedScrHeight; //screen dimension of the selected screen
Screen selectedScreen;
int totalXPos, totalYPos; //where the form is located before exceed screen is handled
//---get screen where point is at---
selectedScreen = Screen.FromPoint(currentPoint);
Console.WriteLine("\nSelected screen info: {0}\n", selectedScreen); //for debugging purposes
//---get screen where point is at---
//---get selected screen dimension---
selectedScrWidth = selectedScreen.WorkingArea.Width;
selectedScrHeight = selectedScreen.WorkingArea.Height;
//---get selected screen dimension---
totalXPos = currentPoint.X + this.Width; //mouseXCoor + popupMenu width
totalYPos = currentPoint.Y + this.Height; //mouseXCoor + popupMenu height
//if exceed selected screen width and height
if ((totalXPos >= selectedScrWidth) && (totalYPos >= selectedScrHeight))
{
newPoint.X = selectedScrWidth - this.Width;
newPoint.Y = selectedScrHeight - this.Height;
}
//if exceed selected screen width
else if ((totalXPos >= selectedScrWidth))
{
newPoint.X = selectedScrWidth - this.Width;
newPoint.Y = currentPoint.Y;
}
//if exceed selected screen height
else if ((totalYPos >= selectedScrHeight))
{
newPoint.X = newPoint.X;
newPoint.Y = selectedScrHeight - this.Height;
}
else //if x exceed screen, just set the location as is
{
return this.Location = Cursor.Position;
}
return this.Location = newPoint;
}
Update 1:
As per Jimi's request under the comment section, after creating a simple test project based on given answer here, here's what I got:
Please note the reason why the code in the question from the previous thread has no Width, Height, and StartPosition = FormStartPosition.Manual defined was because the popup menu is from a class on another .cs file where, those specific properties have already been declared in the PopupMenu.Designer.cs file. Therefore, I don't feel like redefining was necessary.
Update 2:
Now that it works, a newer problem arises is that, only when popup menu exceeds right boundary of secondary display, the popup menu was displayed on primary screen. However this didn't occur when I try to open the popup menu when exceeding the height of secondary screen. Example is shown below:
Above is the case when I try to open the popup menu when exceeding the width of secondary screen. The popup menu opens at the right boundary of primary screen.
It however worked just fine when I tried the case for exceeding the height of secondary display.

Related

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?

Is there a way to recognize the position of system tray in c# winforms?
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.
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:
Created notifyicon control then set is method on click method to call my form
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;

Prevent new window from going offscreen

If the MainWindow is too close to the edge of the screen, opening a New Window with relative positioning can go off screen.
I'd like to have it detect that it's off screen and reposition itself close to the edge, even overlapping the MainWindow. For Top, Bottom, Left and Right.
Example Project Source
https://www.dropbox.com/s/3r2guvssiakcz6f/WindowReposition.zip?dl=0
private Boolean IsWindowOpened = false;
// Info Button
//
private void buttonInfo_Click(object sender, RoutedEventArgs e)
{
MainWindow mainwindow = this;
// Start Info Window
InfoWindow info = new InfoWindow(mainwindow);
// Only Allow 1 Window Instance
if (IsWindowOpened) return;
info.ContentRendered += delegate { IsWindowOpened = true; };
info.Closed += delegate { IsWindowOpened = false; };
// Position Relative to MainWindow
info.Left = mainwindow.Left - 270;
info.Top = mainwindow.Top + 0;
// Open Info Window
info.Show();
}
Example of 1280x720 screen
MainWindow Center Screen
InfoWindow -270px Left, 0px Top
Off Screen
MainWindow Top Left of Screen
InfoWindow -270px Left, 0px Top
Reposition In Screen
MainWindow Top Left of Screen
InfoWindow -160px Left, 0px Top
To Place Dialog to Left
The quick-n-dirty way of doing this is to simply use Math.Max (i.e. the right-most value) to use the offset or 0, whichever is larger. Using System.Windows.Forms.Screen allows us to accommodate for multiple monitors.
private void btnInfoToLeft_Click(object sender, RoutedEventArgs e)
{
// Figure out which screen we're on
var allScreens = Screen.AllScreens.ToList();
var thisScreen = allScreens.SingleOrDefault(s => this.Left >= s.WorkingArea.Left && this.Left < s.WorkingArea.Right);
// Place dialog to left of window, but not past screen border
InfoWindow info= new InfoWindow();
info.Left = Math.Max(this.Left - info.Width - 10, thisScreen.WorkingArea.Left);
info.Top = Math.Max(this.Top - info.Height - 10, thisScreen.WorkingArea.Top);
info.Show();
}
Note that we use the Width of the dialog - it's ActualWidth will be 0 before it is shown on the screen.
To Place Dialog to Right
Similarly, we need to figure out the right-most boundaries of the screen, and account for the width of the main window and dialog, and take the Math.Min value (i.e. the left-most value).
private void btnInfoToRight_Click(object sender, RoutedEventArgs e)
{
// Figure out which screen we're on
var allScreens = Screen.AllScreens.ToList();
var thisScreen = allScreens.SingleOrDefault(s => this.Left >= s.WorkingArea.Left && this.Left < s.WorkingArea.Right);
// Place dialog to right of window, but not past screen border
InfoWindow info = new InfoWindow();
info.Left = Math.Min(this.Left + this.ActualWidth + 10, thisScreen.WorkingArea.Right - info.Width);
info.Top = Math.Min(this.Top + this.ActualHeight + 10, thisScreen.WorkingArea.Bottom - info.Height);
info.Show();
}
This time, we still use the Width of the dialog, but the ActualWidth of the main window, which will be the width after it has been drawn (and possibly resized).
In these examples, I've also placed the dialog above/below the main window. You can set the top of the dialog to be equal to the top of the main window, or play around to get it to line up with the bottom, etc., using this example as a guide.
There are no shortcuts for this kind of problem. You'll have to figure out the dimensions of the screen you're using, then adjust the position of the info window manually.
Take a look at this StackOverflow post: How to get the size of the current screen in WPF?

Center UISegmentedControl within a UISearchBar

I am using the built-in search scope with a UISearchDisplayController, and I only have 2 segments.
The problem is that our design needs the buttons to be smaller and centered (it especially looks bad on iPad because the buttons are stretched really wide).
Is there a way to center the UISegmentedControl and make it smaller? I already have the UISegmentedControl pulled out by looping over subViews. And I can set the width of each segment with setWidth:forSegmentAtIndex, but the control is docked to the left. How can I center it?
PS - my app is MonoTouch (Xamarin.iOS), but Obj-C answers are welcome.
Are you adding this via IB or programmatically? In IB, I had to turn off "Autoresize Subviews" and do the resizing of the control dynamically via code. I put the controls I needed to resize into a view that I could bind to then center my control within that view. Here's a sample. I had 2 buttons that I put side-by-side in landscape mode, but it should give you an idea.
// get the current sizes of the things we are moving
CGRect saveRect = self.viewButtons.frame; // the enclosing view
CGRect addLocRect = self.buttonAddLocation.frame; // button 1
CGRect connectRect = self.buttonConnect.frame; // button 2
// This will be set below in one of the if-else branches
CGFloat buttonWidth = 0;
// determine the offset from the left/right based on device and orientation
int offsetLeft = 0;
int offsetRight = 0;
if ([self isIphone]) {
offsetLeft = (UIDeviceOrientationIsPortrait(toInterfaceOrientation)) ? OFFSET_LEFT_PORTRAIT_IPHONE : OFFSET_LEFT_LANDSCAPE_IPHONE;
offsetRight = (UIDeviceOrientationIsPortrait(toInterfaceOrientation)) ? OFFSET_RIGHT_PORTRAIT_IPHONE : OFFSET_RIGHT_LANDSCAPE_IPHONE;
} else {
offsetLeft = (UIDeviceOrientationIsPortrait(toInterfaceOrientation)) ? OFFSET_LEFT_PORTRAIT_IPAD : OFFSET_LEFT_LANDSCAPE_IPAD;
offsetRight = offsetLeft;
}
// change the size & location of the buttons to maximize the area for the location list
// no matter what orientation, the button frame will fill the bottom of the screen
saveRect.size.width = _windowWidth -offsetLeft - offsetRight;
// for Landscape, move the buttons to side-by-side at the bottom of the window
if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) {
// size & move the buttons to fit side-by-side
buttonWidth = (saveRect.size.width)*.4;
// addLocRect.origin.x += offset;
addLocRect.origin.y = saveRect.size.height - addLocRect.size.height ;
connectRect.origin.x = saveRect.size.width - buttonWidth - offsetRight;
connectRect.origin.y = saveRect.size.height - connectRect.size.height;
} else { // Portrait
// move the buttons down to the bottom of the frame, stacked
// size the buttons to be fully across the screen
buttonWidth = saveRect.size.width-2*offsetLeft;
addLocRect.origin.y = 0 ; // at the top of the button view
addLocRect.origin.x = offsetLeft;
connectRect.origin.y = saveRect.size.height - connectRect.size.height;
connectRect.origin.x = offsetLeft;
}
connectRect.size.width = buttonWidth;
addLocRect.size.width = buttonWidth;
self.buttonAddLocation.frame = addLocRect;
self.buttonConnect.frame = connectRect;

Scrolling in a flowlayoutpanel while dragging?

I have a Windows Forms application which is using a FlowLayoutPanel control to display a Picture boxes that are built dynamically. I have enabled the drag drop effect as they may want to reorder them, this works fine with only a few picture boxes (right now the screen shows about 6) but if there are more you try to drag an item below the control it will not scroll, so you cannot put an image that is currently on the screen (say image 4) to an image that is below what is visible (say image 13).
I have seen several posts where the ScrollControllIntoViewMethod should be used, I have tried in a few spots unsuccessfully.
Thanks!
Here is what I ended up doing.
Create the event on the DragLeave event
Getting the position of the control
Calculating the height of the control to get the lower boundary.
check the mouse position and if above the bounds, change the vertical scroll (or horizontal scroll) by a value in a Constant..
private void thumbFlow_DragLeave(object sender, EventArgs e)
{
int BegY_ThumbFlow = this.thumbFlow.FindForm().PointToClient(this.thumbFlow.Parent.PointToScreen(this.thumbFlow.Location)).Y;
int thumbFlowBound_Y = this.thumbFlow.Height + BegY_ThumbFlow;
int mouseY = this.thumbFlow.FindForm().PointToClient(MousePosition).Y;
while (mouseY >= thumbFlowBound_Y)
{
thumbFlow.VerticalScroll.Value = thumbFlow.VerticalScroll.Value + DRAG_DROP_SCROLL_AMT;
mouseY = thumbFlow.FindForm().PointToClient(MousePosition).Y;
thumbFlow.Refresh();
}
while (mouseY <= BegY_ThumbFlow)
{
thumbFlow.VerticalScroll.Value = thumbFlow.VerticalScroll.Value - DRAG_DROP_SCROLL_AMT;
mouseY = thumbFlow.FindForm().PointToClient(MousePosition).Y;
thumbFlow.Refresh();
}
}
Hope this helps others.

C#, WinForms - Change FormBorderStyle without the client area moving

I have a small tool window that normally has the FormBorderStyle to FixedDialog with no caption text and no control box so it looks like a border-less form with a raised 3d effect.
When the user moves the mouse over the tool window it changes from this border-less FixedDialog mode to a SizableToolWindow w/ caption text and a control box.
The result is the client area moving.
The following code works but i do not want to hard code the top/left delta and I assume it is different depending on what theme/os the user has
void Reposition()
{
var topDelta = 12; // this number is wrong, i have not found the right number for aero yet
var leftDelta = 3;
if (this.Bounds.Contains(MousePosition))
{
if (this.FormBorderStyle != System.Windows.Forms.FormBorderStyle.SizableToolWindow)
{
this.Location = new Point(this.Location.X - leftDelta, this.Location.Y - topDelta);
this.ControlBox = true;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow;
}
}
else
{
if (this.FormBorderStyle == System.Windows.Forms.FormBorderStyle.SizableToolWindow)
{
this.Location = new Point(this.Location.X + leftDelta, this.Location.Y + topDelta);
this.ControlBox = false;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
}
}
}
Look into SystemParameters class. You will find the values you are hard-coding in your code there.

Categories