I'm working on a winforms application using MetroFramework. I want to programmatically resize the form so a larger object can fit on it. For this I'm using a toggle from the framework in a tabControl object. Making the form bigger works fine, but when I disable the toggle it doesn't want to shrink the form.
private void tSynced_CheckedChanged(object sender, EventArgs e)
{
if (tSynced.Checked)
{
//Sync enabled
Console.WriteLine("Sync enabled");
this.Size = new Size(this.Width + 300, this.Height);
this.MinimumSize = new Size(this.Width, this.Height);
this.MaximumSize = new Size(this.Width + 200, this.Height);
} else
{
//Sync disabled
Console.WriteLine("Sync disabled");
this.Size = new Size(this.Width - 300, this.Height);
this.Width = 534;
Console.WriteLine(this.Size);
this.MinimumSize = new Size(this.Width, this.Height);
this.MaximumSize = new Size(this.Width, this.Height);
}
}
As you can see I've been experimenting with some techniques that I know, just to give it a try and work my way back from there, but it doesn't seem to work. This seems odd to me, since the first method (the this.Size line) does work when making the form bigger. The this keyword is referring to the Form according to Visual Studio. It doesn't seem to try to resize the tabControl, because I bound that to the right side, and properly moves along with the right border.
The log for the this.Size will return the large value, which is {Width=834, Height=354} in my case.
I've tried saving the initial values in a Size variable, and restoring it from there (since it would account for resizing by the user), but that doesn't seem to work correctly.
Size oldSize; //Global variable
private void initialize()
{
oldSize = new Size(this.Width, this.Height);
Console.WriteLine(oldSize);
}
this.Size = oldSize; //In the eventhandler
The log will return the correct value, which is {Width=534, Height=354} in my case. But it refuses to use the value when setting the this.Size property again...
What am I overlooking?
When enlarging the form, you set the MinimumSize to the current size - but when you make it smaller you try to reset the Size while the MinimumSize is still set - so the form doesn't resize.
All you need to do is to reset the MinimumSize before changing the Size.
Related
I have a WinForms project on which I would like all of the controls to grow proportionally along with the form as the form is resized. This is what the form looks like in normal state: Normal State Form
I have tried setting the Anchor properties to their appropriate values given the location of each control on the form, and while it does move the controls, they remain the same size. I tried using the AutoSize property, but also to no avail. Here is what the form looks like after being maximized with the Anchor properties set: Maximized Form
I also tried using a formula from Shaun Halverson to dynamically resize everything but it does not relocate the control properly, and I can't seem to figure out why. Here is the code I used to try and resize dynamically:
private void Main_Load(object sender, EventArgs e)
{
originalFormSize = new Rectangle(this.Location.X, this.Location.Y, this.Size.Width, this.Size.Height);
submitBtnOriginal = new Rectangle(submitButton.Location.X, submitButton.Location.Y, submitButton.Width, submitButton.Height);
}
private void Main_Resize(object sender, EventArgs e)
{
resizeControl(submitBtnOriginal, submitButton);
}
private void resizeControl(Rectangle r, Control c)
{
float xRatio = (float)(this.Width) / (float)(originalFormSize.Width);
float yRatio = (float)(this.Height) / (float)(originalFormSize.Height);
int newWidth = (int)(r.Width * xRatio);
int newHeight = (int)(r.Height * yRatio);
int newX = (int)(r.Width * xRatio);
int newY = (int)(r.Height * yRatio);
c.Location = new Point(newX, newY);
c.Size = new Size(newWidth, newHeight);
}
When I run this code, it moves the button to the opposite corner of the form, but it resizes it properly.
This would obviously be quite redundant given that I have to get an original size for every control I want to resize, but I would be fine with that if I could get dynamic resizing to work. I am surprised that this is not a more common problem, and I couldn't find hardly anything on this specific topic other than to use the Anchor and Dock properties. Is there an easy way to do this that I am missing? Is this a more difficult problem than it seems?
Put TextBox anchor property values as Top, Bottom, Left, Right and resize the form. That should work.
I have custom control inherited from UserControl. I need to ensure that it is squared.
So, I need smth like that:
int side = Math.Max(this.Width, this.Height);
this.Size = new Size(side, side);
But where should I implement this logic? I cannot do it in OnResize because it causes recursive calls and crashes Visual Studio in design mode, or app in runtime.
To keep a squared aspect, I suggest to override OnLayout instead of OnResize, the latter can be called more than once when the UserControl is resized in the Form designer or at run-time.
OnLayout is called multiple times when the UC is first created (it has to, the size is set multiple time in the initialization).
You also need to check whether the UserControl's Size is scaled down or up:
If the UC is scaled up, you set the squared size to Math.Max(Width, Height)
If the UC is scaled down, you set the squared size to Math.Min(Width, Height)
You have perform this check otherwise, when - for example - the US is scaled up, you won't be able to resize it to a value that is lower that Max(Width) or Max(Height) (i.e., when scaled up, it won't ever scale down).
public partial class MyUserControl : UserControl
{
int m_Squared = 0;
public MyUserControl()
{
InitializeComponent();
// Test with and without setting these
this.MaximumSize = new Size(100, 100);
this.MinimumSize = new Size(300, 300);
}
protected override void OnLayout(LayoutEventArgs e)
{
base.OnLayout(e);
m_Squared = (this.Width > m_Squared || this.Height > m_Squared)
? Math.Max(this.Width, this.Height)
: Math.Min(this.Width, this.Height);
this.Bounds = new Rectangle(this.Location, new Size(m_Squared, m_Squared));
}
}
I have created a custom ListView control to suit my needs and I'm having an issue that causes the ListView not to show any contents (not drawing anything, just white) when the form first loads.
If I resize the form or click on my control (anything that forces a repaint on the ListView) then it shows up as expected.
As a side note, it used to work just fine until I made a small change today and rebuilt the control. I removed all the changes I made and rebuilt again but the issue still happens. Any ideas as to why it will not show up (paint) when the form is first loaded?
This is what I use to do the custom drawing on my custom ListView control...
protected override void OnDrawItem(DrawListViewItemEventArgs e)
{
Image image = e.Item.ImageList.Images[e.Item.ImageIndex];
Size textSize = new Size((int)e.Graphics.MeasureString(e.Item.Text, e.Item.Font).Width, (int)e.Graphics.MeasureString(e.Item.Text, e.Item.Font).Height);
//Get the area of the item to be painted
Rectangle bounds = e.Bounds;
bounds.X = 0;
bounds.Width = this.Width;
//Set the spacing on the list view items
int hPadding = 0;
int vPadding = 0;
IntPtr padding = (IntPtr)(int)(((ushort)(hPadding + bounds.Width)) | (uint)((vPadding + bounds.Height) << 16));
SendMessage(this.Handle, (uint)ListViewMessage.LVM_SETICONSPACING, IntPtr.Zero, padding);
//Set the positions of the image and text
int imageLeft = (bounds.Width / 2) - (image.Width / 2);
int imageTop = bounds.Top + 3;
int textLeft = (bounds.Width / 2) - (textSize.Width / 2);
int textTop = imageTop + image.Height;
Point imagePosition = new Point(imageLeft, imageTop);
Point textPosition = new Point(textLeft, textTop);
//Draw background
using (Brush brush = new SolidBrush(e.Item.BackColor))
e.Graphics.FillRectangle(brush, bounds);
//Draw selected
if (e.Item.Selected)
{
using (Brush brush = new SolidBrush(m_SelectedColor))
e.Graphics.FillRectangle(brush, bounds);
}
//Draw image
e.Graphics.DrawImage(image, imagePosition);
//Draw text
e.Graphics.DrawString(e.Item.Text, e.Item.Font, new SolidBrush(e.Item.ForeColor), textPosition);
}
I also set the following things in the Constructor of my custom control...
public MyListView()
{
this.DoubleBuffered = true;
this.OwnerDraw = true;
this.View = View.LargeIcon;
this.Cursor = Cursors.Hand;
this.Scrollable = false;
}
I also inherit the ListView class...
public class MyListView : ListView
{
//All my source
}
You need to set the set the control to redraw itself when resized. So add this code in constructor of your control:
this.ResizeRedraw = true;
My apologies:
Doing the below reset my event handlers and the problem went away. However, once I hooked them up, I found the Resize event handler that I used to set the ColumnWidth was causing the issue. Why setting the ColumnWidth is causing this, I do not know.
Arvo Bowen's comment on this answer fixed it for me also (.NET 4.8 Framework, VS2022). To be clear, not requiring this.ResizeRedraw = true; from the answer.
So after much headache and time I found that I had absolutely nothing wrong with my control. It was your answer that made me create another control just like my existing one and test it. To my surprise it worked great. I simply copied my existing non-working control and pasted it on the form and then new one worked! Sometimes VS just does weird things... Somehow I managed to muck up the control's creation object or something..
I'm writing a game using c#'s winforms,
When creating a Scene (holding graphics, objects, etc...) I'm transfering the form so the c'tor looks something like that:
public Scene(Form form)
{
_g = form.CreateGraphics();
RegisterFormEvents(form);
_gameObjects = new List<GameObject>();
Width = form.Width;
Height = form.Height;
}
Now I'm trying to add an option to show the game on full screen,
but when i'm trying to maximize the window it only prints graphics to the original Width x Height,
how can I strecth those?
You just have to listen to the SizeChanged event of the form. Whenever the size has changed you set the Width and Height properties of the scene to match the new dimensions.
So, somewhere in your code you should have the following:
// I assume that this code is in the code-behind of the form, so "this" is the form
this.SizeChanged += new EventHandler(FormSizeChanged);
and
private void FormSizeChanged(object sender, EventArgs e)
{
yourScene.Width = this.Width;
yourScene.Height = this.Height;
}
I couldnt find anything like that at all (basicly every problem from so else is always a syntax problem) and well..., the situation is a bit more complicated. to avoid using 500 lines of code im going to describe it for the most part:
Ive got a Form wich is acting as a parent Form (MdiParent) and another Form wich is a Child but basicly a fully functional Form at its own. Im using several OnPaint methods in the childform, witch work perfectly fine, and 3 custom buttons on the parent Form witch also have their own OnPaint methods. These 3 buttons (actualy panels) and every other control on the parent Form are contained in a PictureBox witch fills the parent Form completely and is used to make the background of the parent transparent / clickthrough via TransparencyKey (havnt found any other ways of doing that).
the Problem is that every OnPaint Method on the parent wont work at all (they're beeing executed but dont paint anything).
here is some code but that isnt the problem i'd say:
this.myButtonObject1.BackColor = System.Drawing.Color.Red;
this.myButtonObject1.Location = new System.Drawing.Point(840, 0);
this.myButtonObject1.Name = "myButtonObject1";
this.myButtonObject1.Size = new System.Drawing.Size(50, 50);
this.myButtonObject1.TabIndex = 0;
this.myButtonObject1.Click += new System.EventHandler(this.myButton1_Click);
this.myButtonObject1.Paint += new System.Windows.Forms.PaintEventHandler(this.myButtonObject1_Paint);
private void myButtonObject1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
LinearGradientBrush lgb = new LinearGradientBrush(new PointF(0, 0), new PointF(myButtonObject1.Width, myButtonObject1.Height), Color.Green, Color.Lime);
Pen p = new Pen(lgb, 5);
g.DrawRectangle(p, myButtonObject1.Bounds);
lgb.Dispose();
p.Dispose();
}
if anyone can tell me; what am i doing wrong?
PS: i m using .net 4.5, VS 2015, and havnt changed any of the default settings besides TopMost FormBorderStyle ShowInTaskbar StartPosition and ofc the color and trancparencyKey, but i dont think it has anything todo with that.
Update
The small error in your code is to use the Panel's Bounds property, which at runtime will refer to the Panel's Location within its Parent! But the drawing code must be relative to the object, not its parent!
So do not use Bounds but ClientRectangle and make sure to set the right PenAlignment:
using (LinearGradientBrush lgb =
new LinearGradientBrush(ClientRectangle, Color.Green, Color.Lime, 0f) ) //or some angle!
using (Pen p = new Pen(lgb, 5))
{
p.Alignment = PenAlignment.Inset;
g.DrawRectangle(p, ClientRectangle);
}
Set myButtonObject1.FlatStyle to FlatStyle.Standard.