C# WinForms - Real (including non-client) FixedToolWindow height and width - c#

I'm trying to place a fixed tool window in the bottom right portion of my primary screen just above the start menu bar.
I'm using the following code
this.Top = Screen.PrimaryScreen.WorkingArea.Bottom - this.Height;
this.Left = Screen.PrimaryScreen.WorkingArea.Right - this.Width;
The form aligns the edge of the screen to the client rectangle so I see the non client bottom edge bleed into the start menu bar and the right non client edge bleed into the second monitor.
I need to get the full form width and height including all the non client borders
I notice it works when the form is SizableToolWindow but not with FixedToolWindow
Thanks everyone!

The Bounds property will give you a Rectangle from which you can get the full size.
The bounds of the control include the nonclient elements such as scroll bars, borders, title bars, and menus.
Documentation

Hans got this answer right but posted it as comment instead of an answer.
The answer is here:
https://social.msdn.microsoft.com/Forums/windows/en-US/af2608c1-1159-444f-bb21-b2cf0228f1c1/strange-issues-with-formborderstyle-on-vista-between-fixed-and-sizable-modes?forum=winforms
– Hans Passant May 19 at 21:07
Copied from site:
Strange issues with FormBorderStyle on Vista between fixed and sizable modes
Question:
The problem lies on all types of fixed border styles like FixedDialog, Fixed3D, FixedSingle and FixedToolWindow. It does not happen on the sizable ones. This problem, like I said, also happens only on Vista.
Let's say you have a form with any of the fixed border styles and set the starting location to 0,0. What you want here is for the form to be snapped to the top left corner of the screen. This works just fine if the form border style is one of the sizable options, if it's fixed, well, the form will be a little bit outside of the screen working area both to the left and top.
What's more strange about this is that the form location does not change, it sill is 0,0, but a few pixels of the form are drawn outside of the working screen area.
I tested this on XP and it didn't happen, the problem is Vista specific. On XP, the only difference was the border size that change a bit between any of the styles. But the form was always perfectly snapped to position 0,0.
If possible, without finding how many pixels are being drawn outside of the working area and then add that to the form location, is there a possible way to fix or workaround this?
Answer:
The problem is specific to Aero, it doesn't happen when you turn it off. It is one of those famous app-compat fixes. Windows actually lies to you when you P/Invoke GetWindowRect(). It gives window position and size, relative from the client area, that the window would have if it were running on an earlier version of Windows, like XP.
That makes sure that older programs still behave somewhat predictably, they'll have their all-important client area in the same location, even though they have much fatter borders. But gets in the way at times, like your case.
To fix that, you have to convince Vista that you are really aware how Vista works. That requires patching the .exe header. Start the Visual Studio Command Prompt, navigate to your build directory and type this command:
editbin /subsystem:windows,6.0 yourprogram.exe

Yes, the comment from Hans correctly told us why the form's .Height and .Width are not correct. I think the following should work to give you the real height and width, whether or not Aero is enabled.
(in the code for a Form)
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern bool DwmIsCompositionEnabled();
// When Aero is enabled, and our FormBorderStyle is FixedToolWindow,
// Windows will lie to us about our size and position.
public bool AeroIsMessingWithUs()
{
bool ret = false;
// check for other Fixed styles here if needed
if (FormBorderStyle == System.Windows.Forms.FormBorderStyle.FixedToolWindow)
{
if (Environment.OSVersion.Version.Major >= 6 && DwmIsCompositionEnabled())
{
// Aero is enabled
ret = true;
}
}
return ret;
}
public int MyWindowHeight()
{
int height = Height;
if (AeroIsMessingWithUs())
{
// there are actually 5 more pixels on the top and bottom
height += 10;
}
return height;
}
public int MyWindowWidth()
{
int width = Width;
if (AeroIsMessingWithUs())
{
// there are 5 more pixels on the left and right
width += 10;
}
return width;
}

Related

Set MinimumSize according the controls residing inside form

Title of my question could be make it look like a duplicate but please read ahead as my problem is a bit different.
I am trying to replicate the minimum size functionality of some popular media players like MPC-HC or VLC where when you try to make it small the minimum size it achieves is when only MenuStrip and Player Controls are visible.
The code I've written to attain this is:
public NewMain()
{
InitializeComponent();
int ClientTop = RectangleToScreen(ClientRectangle).Top;
int height = menuStrip1.Height + panel1.Height + ClientTop - Top;
label4.Text = height.ToString();
MinimumSize = new Size(373, height);
}
The problem is that when it runs, its not working perfectly and the menuStrip1 is still getting blocked a little at bottom from the panel1 (Docked at bottom) where the player controls will be placed.
Below is the Image of what I was able to attain with above code.
Next Image is what I expected:
Note that label on left updates when resize the form and the label on the right is the determined height via code.
My Idea was to add the difference of Form's Top and the Top of total rectangle visible on the screen i.e. the height of the title bar otherwise the resulting height will be even smaller and hide the menuStrip1 completely. I don't want to hardcode any values because it'll make the interface less adaptable to the changes that I might be doing later on.
To correctly determine the minimum height in this case is to keep the calculations relative which can be attained by:
int height = Height - (panel1.Top - menuStrip1.Bottom);
All credit goes to Hans Passant who provided this code. I'm just posting it as an answer to mark my question solved. Thank you.

Textbox Positioning Issues On Form Bigger Than Resolution

I have this form that works perfectly fine on resolution 1920 x 1080 (mainly cause I made it using that resolution). I read information about controls from a database (labels and textboxs). This information tells me where to place the controls. Like I said, on 1920 x 1080 everything is placed correctly. When I go down resolutions the form is now bigger than the resolution so I added scroll bars. Issue is that the controls are being placed as if the form that is visable on the screen is all that there is. So if I were to place a textbox at location (4, 90) on the form on lower resolution it might place it at (100,90). Y coord is fine, X coord is not.
Although TableLayoutPanels looks very nice in this case it would be a complete hassle and a waste of time to basically completely redo what I have done already. If I were to have started fresh I probably would have used TableLayoutPanels. Instead what I did was, since the Form was bigger than the resolution, I turned my forms AutoScroll to true (which I said in the question). I then set the AutoScrollPosition to (0,0) on form_shown which makes the horizontal one go to the left and the vertical one to the top using...
this.AutoScrollPosition = new Point(0,0);
Since the controls information is based off of where they are on the screen I just force the form's top left to be located in the top left of the screen and not off. I also had to have an override for the ScrollToControl. Every time a control was placed it would reset back to the center and would mess the placement up. So I added this...
protected override Point ScrollToControl(Control activeControl)
{
return this.AutoScrollPosition;
}

How to align windows when they are very near

I have an application with some small windows on the screen. I would like to align them to each other, so when I move one close enough, it will automatically be align with the other. Helping me positioning and size them all.
How can I know the position of other windows when there isn't a parent window? Is it possible to know it even if they are different process (applications)?
I am not fully sure what you mean but the following trick is what I use for dynamic layout and it gives me full control over anything, you just need to play around with it and you can easily get the distance between two windows.
This code is copied from a windows phone app but it is easily understood.
width = Convert.ToInt32(Window.Current.Bounds.Width);//gets window width
height = Convert.ToInt32(Window.Current.Bounds.Height);// gets window height
double dist Math.Abs(Btn1.GetValue(Canvas.LeftProperty) - Btn2.GetValue(Canvas.LeftProperty) + Btn2.Width);
note first two lines are only in order to have the proportions right in every single movement and resize you do, you can keep it all proportional to the window size.

Is there a way to get the margins previously set by `DwmExtendFrameIntoClientArea`?

Is there a way to retrieve the margins that were set by DwmExtendFrameIntoClientArea?
I've scanned the documentation. I would have expected DwmGetWindowAttribute to be the most logical place to look it up.
(What I would like to do is discern what portion of an inserted child should be painted black to allow Aero glass effects through and what portion should be painted the parent's background colour.)
There is no way to do this. The developer is expected to know the size of the frame they extended into the client area.
MARGINS g_Margins;
g_Margins.cxLeftWidth = 0;
g_Margins.cxRightWidth = 0;
g_Margins.cyTopHeight = 15*fontHeight;
g_margins.cyBottomHeight = 7*fontHeight;
DwmExtendFrameIntoClientArea(g_hwnd, g_margins);
Note: Any code released into public domain. No attribution required.

.net Resizing control won't work?

I have a couple of pictureboxes that need to be resized by aspect ratio when the window size changes. I assumed I can anchor the width, but set the height manually (i.e. anchor the left, right, and top edges; but not the bottom.) However, my control won't resize if I try changing the Size property. Why wouldn't that work? How can I resize my control?
private void Form1_Resize(object sender, System.EventArgs e)
{
int oldWidth = 1280;
int oldHeight = 1024;
int newWidth = webcamPictureBox.Size.Width; // this is auto-resized w/ window; becomes 591
int newHeight = (oldHeight * newWidth) / oldWidth; // this is calculated manually; becomes 472
// Control won't resize if I change the Size property
// Size property stays the same
this.webcamPictureBox.Size = new Size(newWidth, newHeight);
this.thumbnailPictureBox.Size = new Size(newWidth, newHeight);
}
You could be running into one of a few problems, I suppose:
What's the SizeMode of the PictureBox? Is it AutoSize, StretchImage, or something like that? It should probably be Normal for what you want to do.
Are you sure you have your anchoring set up correctly?
Did you debug and check the final size of the picture boxes you're trying to resize? You should verify that it's what you expect and that the form has been repainted.
These are just some ideas; your code along is not enough to provide a great response.
It's difficult to answer this question definitively with the information you've posted.
Windows forms controls problems are difficult to debug by nature because of all the controls that might be affecting what you're doing. First off, you'll want to try debugging this on your own on a form with as few controls as possible. Are there any circumstances under which the resizing behaves properly?
That said, is the Dock property set on these controls? They definitely won't resize if they're set to DockStyle.Fill.
Thanks for the ideas -- they pointed me on the right track! Everything was set up as they should be, except the TableLayoutPanel they were in was constraining their sizes. I determined this by noticing the pictureboxes' size values were simply uneditable, both in runtime and in the designer.
So I set TableLayoutPanel's AutoSize to true, and it works great!

Categories