Form.Width incorrect on Form.FormClosing() - c#

I am trying to get an accurate Form.Width on FormClosing().
I have a zoom() method I use to scale a picture in the Form. The form's width is then manually re-sized by me to fit. I then, set the MaximumSize's Width limit to the new width of the form. For our purpose, let's say the width and maxwidth are now 1386.
If I re-size the form in the Windows interface by dragging its edge to the left, the width is being reduced just fine. FormClosing reports the re-sized width accurately. Let's say 1107.
However, if go through the zoom() method I wrote, even though I drag to the left to the same position, FormClosing is reporting the ORIGINAL 1386 width. The only things I do to form size in the zoom() method are set width and maxwidth.
I am at a loss to handle this behavior. I need FormClosing to report the correct size. I think FormClosing is setting the Width to MaximumWidth when it fires. I think I read something about how the Form is set to Hidden by the time the FormClosing event is fired. Maybe being Hidden reverts its size to MaxWidth.
Any help would be much appreciated. I have been struggling with this for a few hours and can't find anything.
Thanks.
Here is the relevant code:
private void zoom()
{
// Re-size form width to slightly more than page width.
// This is percentage-based, meaning 100 = default size.
Size picSize = new Size
{
Width = (int)(originalRenderingSize.Width * integerUpDownZoom.Value / 100),
Height = (int)(originalRenderingSize.Height * integerUpDownZoom.Value / 100),
};
// some code here which I commented-out, and still, the problem exists.
// Set maximum to prevent ugly sizing.
this.MaximumSize = new Size(picSize.Width + 40, Screen.FromControl(this).WorkingArea.Height);
// The problem is this: When this method processes, as shown, a page is rendered and sized according to
// a user-provided zoom level represented by an integerUpDown control. Once rendered, the form should
// re-size its width to match the newly-scaled page's width. This works, too. So far, so good.
//
// But!!! If the user grabs the right side of the form and drags it to the left to reduce the width
// of the form (mind you, this is Windows OS doing this), upon Form.Form_Closing(), you can see a
// quick flash of the form fully-open and unscrolled. Then, in the FIRST line of Form_Closing(),
// the debugger reports the form's width as the fully-open and UNSCROLLED width.
//
// The goal is to set the width upon the conclusion of this zoom, but then, on closing
// get the width of the Form in order to persist it for use the next time the app is run.
//
// 2 options have been tried. Both cause Form_Closing to erroneously report the fully-open width.
// But if BOTH are commented-out, the re-sizing occurs and Form_Closing() reports properly the
// form's scrolled width.
// Bear in mind that Form_Closing is one of those things that can happen anytime or never. This means
// the bug is triggered by EITHER and ONLY the two options below.
// Option 1: Tried first. It sets the width fine.
//
// this.Width = picSize.Width + 40;
// Option 2: It also sets the width fine.
// I think this option causes width to change (it invokes width change, and somewhere in the
// OS's width change, the error occurs.
//this.MinimumSize = new Size(MaximumSize.Width - 1, this.Height);
//this.MinimumSize = new Size(0, 0);
}
Edit: I have new information which should help. The culprit is FormClosing(). Here's what I did: I re-sized the form in Windows until it occupied maybe 500 pixels in width. The horizontal scrollbar on my panel was showing. Then, in the FormClosing event, I added the line: Form.Show(). After that, I put a MessageBox.Show("Hi."). Sure enough, the Show() caused the form to repaint in its full, unscrolled width. It did not maintain its scroll state.
I think I have the solution and will post back after trying. Namely, I need to check Scroll values and operate on those values as well.
Edit 2: FormClosing() also re-sets HorizontalScroll.Value and VerticalScroll.Value to 0. This is a bummer! I wonder how to work around this. I also looked at e.Cancel, but there seems to be no way to take advantage of it, either. It seems e.Cancel just re-shows() the form in its unhidden state.
Sorry I cannot post the code. It would be pointless anyway. Think about it. The Windows OS handles the resizing. Not me. When the user re-sizes the form, it's all on Windows. If user re-sizes the form to 500 pixels wide, but FormClosing() reports it is 1386 pixels wide, no amount of my coding will show us anything new. This is a behavior issue. There is no code to show you how the Windows OS handles form re-sizing.

On FormClosing Event Use:
MessageBox.Show(this.Width.ToString());
You're using another Instance of your form's class, Form.Show() should not work in this event cause Dispose function is called and if you have referenced the same instance it will be disposed as well.

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.

Positioning a control to another control on a form

I have a form where user is supposed to put few 'ticks' here and there and when he finishes, I'd like to store locations of those ticks so I can restore them in exact alignment when the user opens the form again. No rocket science. I have a hard times with it, though. The form is a window of 788px x 574px and there's A4-size picturebox (pBox) on it (1035px x 1456px) - so the picturebox is a lot bigger and it scrolls when user is scrolling the form. The tick is other picturebox control (pb). I thought this code should store the locations:
calcX = pb.Left - pBox.Left;
calcY = pb.Top - pBox.Top;
And to restore the 'ticks' (check is object I keep tick data in):
pb.Left = pBox.Left + check.XPoint;
pb.Top = pBox.Top + check.YPoint;
It kind of work, but if user reopens the form in another window size, the tick is placed off the target. The same happens e.g. when user puts tick when pBox is scrolled all the way to the bottom. The problem is that pBox.Left/pBox.Top is 0/0 doesn't matter if the form is scrolled or not. I should take into account pBox alignment to the form, but I'm failing at it. Any help is appreciated. Take a look at attached pictures, the first is when pBox left/top is equeal to Form's beginning, the second is when pBox is scrolled to the right in the form, so it's Left/Top are probably negative to the form.

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

Setting the height of two controls to be the same

How can I make two controls share the same height. I have set the Size to be the same for both controls but when I run it, I am seeing a difference.
this.txtUserName.Size = new System.Drawing.Size(382, 45);
this.btnLogin.Size = new System.Drawing.Size(75, 45);
Actually both have the same Height as you set them. However in order to accomodate various BorderStyles (or FlatStyles as it is called in the case of Buttons) the full size is not always visible.
So, the Button will look to be one pixel smaller on each side than the Height is has with these (current) appearances:
button1.FlatStyle = FlatStyle.Standard
button1.FlatStyle = FlatStyle.System
The full Size will be visible with
button1.FlatStyle = FlatStyle.Popup
button1.FlatStyle = FlatStyle.Flat
If you are sure about your choice of FlatStyle you may want to adapt their Height (and Location!) accordingly..
To further complicate thing the TextBox's visible Height will change if you set its BorderStyle from FixedSingle or Fixed3D to None: It will shrink by 7 (!) pixels..
Note that as far as I remember, all those details of the borderstyles depend on the Windows version & Visual Styles on the target machine.. I am running W8.1 here
Open the Form.Designer.cs and go to InitializeComponent() method for the form, you'll see initialization code for all components on the form.
If you are setting these values prior to InitializeComponent() call from the constructor, it'll be lost. Otherwise you may need to check Margin and Padding of the components.
http://msdn.microsoft.com/en-us/library/vstudio/ms229627(v=vs.100).aspx

Redraw panel contents after ClientSizeChanged

So my application runs in fixed size window and in full screen. The problem I'm facing is how to properly scale the current contents of the panel (which depend on the application use) when the window is resized. This is my current code:
private void Form1_ClientSizeChanged(object sender, EventArgs e)
{
System.Drawing.Drawing2D.Matrix transformMatrix = new System.Drawing.Drawing2D.Matrix();
float px = panel2.Width;
float py = panel2.Height;
panel2.Width = this.Width / 2;
panel2.Height = panel2.Width;
panel2.Location = new Point(this.Width - panel2.Width - 30, 30);
transformMatrix.Scale(panel2.Width / px, panel2.Height / py);
panel2.Region.Transform(transformMatrix);
//Rest of the code
}
But the drawn content doesn't scale, and if I use Invalidate() or Refresh() the drawn content gets cleared (the panel is redrawn empty). What am I missing?
.NET doesn't remember what's drawn on the panel, as simple as that. As soon as anything invalidates the windows bitmap buffer (causing a WM_PAINT), it's going to be repainted again. So, you have to draw what you want to draw using the Paint event (or overriding OnPaint).
However, there is another way that might be easier to implement - don't paint into a Panel. Instead, paint into a PictureBox (or rather, a Bitmap assigned to the Image property of the PictureBox). The Bitmap will be reused when invalidating (and redrawing) the picture box, so nothing will be lost. By using PictureBox.ScaleMode, you can define how you want the picture box to scale the bitmap, and it will do so as well as it can.
In any case, transforming the Region property doesn't do anything useful - you're simply changing the region, not doing anything to the drawing itself. To use 2D transformation matrices, you want to apply them on a Graphics object during the drawing (in Paint handler or OnPaint override) - drawing anything on the Graphics object will then transform everything you're trying to draw, which in your case means scaling the painting.
So you have to decide: do you want to just scale a stored bitmap with the painted image, or do you want to redraw it all from scratch (which also means you can pick any level of detail you can provide)?
I think that you're mistaking what the Region property is meant for. According to the MSDN docs (empasis mine, replace 'window' with 'control' when reading):
The window region is a collection of pixels within the window where the operating system permits drawing. The operating system does not display any portion of a window that lies outside of the window region. The coordinates of a control's region are relative to the upper-left corner of the control, not the client area of the control.
All that you're doing is changing the region that the OS will allow painting, which explains why you're not seeing anything. I think that you should be resizing the control when the form is resized, either through Anchor, or through my preference of Dock with several controls, or a panel like TableLayoutPanel where it will handle scaling and relative sizing for you.
Thank you for your answers, but I wrote my own function and logic that serves the purpose for this application. Basically the function checks for the state of the application variables, and calls the appropriate function that originally drew the content, and since those functions use the panel width and height as arguments they properly scale the drawn content and retain the drawing composition.
P.S. I'll accept Luaan's answers since it offers a valid alternative and is complete.

Categories