I have three monitors/screens of different sizes/resolutions setup as an extended view, all wired to the same NVIDIA graphic card. And from left to right:
Screen#0: 2400*1080
Screen#1: 1920x1080
Screen#2: 1920*1080
My application has three separate Windows, where I respectively position each Window to the corresponding monitor/screen with the following code
window00.Left = System.Windows.Forms.Screen.AllScreens[0].WorkingArea.Left;
window01.Left = System.Windows.Forms.Screen.AllScreens[1].WorkingArea.Left;
window02.Left = System.Windows.Forms.Screen.AllScreens[2].WorkingArea.Left;
window00.WindowState = System.Windows.WindowState.Maximized;
window01.WindowState = System.Windows.WindowState.Maximized;
window02.WindowState = System.Windows.WindowState.Maximized;
I only get the 3rd windows (window02) position to the right most screen properly (Screen#02), but both the 1st and 2nd windows (window00 & window01) stack and maximized to the first screen (Screen#00), leaving the middle Screen#01 empty displaying the background desktop environment, regardless if I set WindowsState.Maximized or Normal.
Even if I workaround the problem through offsetting window01 position by the width of Screen#00 to get all three windows position properly to their corresponding screens, if I maximize Windows.State, window01 still jumps back to Screen#00.
Why is this happening and why does the window not position or maximized to its WorkingArea it assigned to? Could it be due to WPF application using Forms properties?
Related
I currently have a way to do exactly what im asking, but the results are very in-efficient for some users.
Some users reported it making it as if it minimized (no window showing ever but still in taskbar), some reported for example in an ultrawide 21:9 it would only maximize from the left of a 1080p 16:9 width, yet I have a 32:9 super-ultrawise and have had no issues.
My current flow:
Get the Screen Dimensions excluding the taskbar on-load:
MaximizedBounds = Screen.FromHandle(mForm.Handle).WorkingArea; (mForm = Application.OpenForms[0], for support from any thread and such)
From another thread/function/class run:
Form1.mForm.Invoke(new MethodInvoker(() => Form1.mForm.WindowState = FormWindowState.Maximized));
This should result in a maximized window with the proper resolution, but it doesn't :/
What I would prefer:
NOT require to get the screen dimensions on-load, so use something from official Microsoft Code, either DllImport's, .NET Framework Code, or msapi to get the PROPER MaximizedBounds for Borderless Forms. (formborderstyle.none)
I set MaximizedBounds because if I don't, the application will fullscreen the entire screen, not "maximize" like traditional apps but would end up doing more of a Video Player style fullscreen.
Using my 32:9 screen and my 4k 16:9 laptop's screen on Extend Display mode, I managed to re-create the issue
Re-production Steps:
Open the application, leave it on the screen it first started in
Maximize the application (will work fine)
Unmaximize and move it to the other screen
Click maximize, your result should be like above.
This means, the on-load Maximize Bounds only gets the active bounds once which is expected, but due to me executing the Form Style change on a different class and different thread, I cant actually edit the MaximizedBounds property on it everytime I want to maximize, due to property not being public.
Thanks to HansPassant!
Found out exactly whats needed.
Problem:
When moving application to other monitor, it would use the same bounds. Causing it to not properly Maximize
When updating bounds via WndProc(), it would still try and maximize on Monitor 1 but outside its actual bounds, making it look like the application was hidden >:(
Updating the Bounds (put this in Form1):
protected override void WndProc(ref Message m) {
if(m.Msg == 0x02E0) {
Rectangle b = Screen.FromControl(mForm).WorkingArea; //where mForm is Application.OpenForms[0], this is specific to my applications use case.
b.X = 0; //The bounds will try to base it on Monitor 1 for example, 1920x1080, to another 1920x1080 monitor on right, will set X to 1080, making it show up on the monitor on right, outside its bounds.
b.Y = 0; //same as b.X
MaximizedBounds = b; //Apply it to MaximizedBounds
m.Result = (IntPtr)0; //Tell WndProc it did stuff
}
base.WndProc(ref m); //If any other messages were called, do the defaults this method does. Required even if you edited a msg.
}
Updating DPI Awareness for the WndProc message to fire (put this in app.manifest, make it if it doesnt exist):
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitor</dpiAwareness> //Windows 10
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware> //Old-Compatibility
</windowsSettings>
</application>
Now it no longer shows up out of bounds, and is finally updating the MaximizeBounds when changing monitors!
Thanks #HansPassant for the tips!
My primary user-target are user with multiple screens.
My application should overlay all those screens. This is easy for users with screens standing next to each other, primary screen left. Then i can just set my program's this.Left = 0 (same with Top) and set the width to the screens combined width.
Unfortunately not ever user has the same setup, so I have to make some dynamic code, that will place the window correctly on every setup.
What if the user has the primary screen to the right? What if he has the screens vertically? What if he has different resolutions and/or different scaling factors (DPI, 100%, 125%, ...) on each screen?
Can someone help me out write a C# Method that will place my window correctly to overlay every monitor? Thanks!
This function will calculate the total number of screens connected and will give you the Dimensions.
public System.Drawing.Size GetTotalArea()
{
System.Drawing.Size SizeYouNeed = new Size(0,0);
foreach (var screen in Screen.AllScreens)
{
SizeYouNeed.Height+=screen.WorkingArea.Height;
SizeYouNeed.Width +=screen.WorkingArea.Width;
}
return SizeYouNeed;
}
I have a winform (c#, let's say 250px by 250px) that needs to stay in one location on the screen regardless of screen resolution i.e 800x600, 1920x1080 etc. The Winform itself contains only one element - a picturebox so what's inside really doesn't matter (no need to worry about fonts, etc.). I just need it to stick in one place on the screen from one monitor to another.
Any ideas? Thanks in advance.
Could you use one of these?
1) WindowsState = Maximized (then you dont worry, it always takes whole screen)
2) StartPosition = CenterScreen (then it always shows as centered), or CenterParent to center within parent form
3) Location = in this case you would have to do some math to get screen size, your form size than based on that center it but I dont see point of using this considering that StartPosition does it already for you.
Hope that helps
Ok, so in order to get the window at a fixed location given in % of the screen size, you need the screen size (e.g. using this answer), compute the desired position, and set it as the window-location.
Since you need to do it at startup, you could do it before you show the window, or maybe best inside a Frame.Loaded event handler.
I currently have my XNA PC game running in a borderless windowed mode which has worked well until recently on my new laptop. It seems to start drawing a few hundred pixels off the screen to the top left. This leaves a gap at the bottom of the screen and on the right where you can see the desktop below the game. All the mouse coords are accurate to where you should have to mouse over and click on things even though it's just not drawing in the right place.
My older laptop it drew correctly but this new one I just got it seems to be off somehow. I am using David Amador's Resolution class to set up a virtual resolution via:
graphics = new GraphicsDeviceManager(this);
Resolution.Init(ref graphics);
control = Control.FromHandle(this.Window.Handle);
Resolution.SetVirtualResolution(GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width, GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height);
Resolution.SetResolution(GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width, GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height, false);
I set fullscreen to false and then once I create the game screen I do the following to set it to borderless:
Form gameForm = (Form)Form.FromHandle(curGame.Window.Handle);
gameForm.FormBorderStyle = FormBorderStyle.None;
I tried doing "gameForm.Location = new System.Drawing.Point(0, 0);" to try and force set it to start drawing at (0,0) but with my current set up that doesn't seem to do anything because I can set it to (150, 150) and it won't start drawing there. Here is a screenshot from my laptop that shows how it's moved the window and cut off the left and top side exposing the desktop:
Does anyone have any idea why it could be happening now on my new laptop when it hasn't happened on my desktop or old laptop ever before?
Is there a way to make make a windows form application full screen and black out your secondary monitors? So the main display is on your primary display and all your other monitors are just completely black?
You can use the Screen class which give you informations about the current active screens.
// Form myFrm
Rectangle r = new Rectangle();
foreach (Screen s in Screen.AllScreens)
{
if ( s != Screen.CurrentScreen ) // Blackout only the secondary screens
r = Rectangle.Union(r, s.Bounds);
}
myFrm.Top = r.Top;
myFrm.Left = r.Left;
myFrm.Width = r.Width;
myFrm.Height = r.Height;
myFrm.TopMost = true; // This will bring your window in front of all other windows including the taskbar
I can think of one way, and that would be to find out how many monitors there are on the computer, and their layout relative to each other, then create your primary window at 0,0, maximize it and set it to be TopMost, then do the same for the other displays, placing them at the screen locations corresponding to the top left of each monitor of the computer.
The only thing I can think of that would benefit from this in a WinForms environment is an app designed to give a test; the app would cover the entire desktop (except the taskbar; you'd have to disable the Start menu) and pretty much ensure that the user couldn't look at anything except the testing program. It will give you a minimal performance advantage.
Most of the apps that black out all the monitors except the main display are basically using DirectX to control the screen directly (through the lower-level interface to the graphics card). If you're using WinForms to make your program, you're about 50 levels of abstraction above using DirectX.
One way would be to create a second form in your application. One that, when given a set of dimensions, will open without border or menu and with the background set to black.
When your application runs, enumerate your monitors (count them to see how many) and find their dimensions. Your primary one will start at 0,0.
Then spawn a copy of that second form for each of your monitors (except your primary one) and give that form the dimensions of the monitor. They will then turn each screen black.
You will need to remember to keep a handle to each of the forms and terminate them when you terminate your main form.