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));
}
}
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'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.
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;
}
C#3.0,.net framework 3.5
I am drawing ( using the draw method in the graphics class) a lot of solid rectangles on a windows form vertically. The form starts at 500 x 500 px and the rectangles are only drawn at runtime after data is downloaded from the net -and the number of rectangles depends on the download so I do not know it upfront.
So only a few rectangles are drawn as the size of the form is fixed.
So I googled/Binged ( lest someone suggest I do that) and found a few tips but they don't work in this case -like setting the forms AutoScroll property to true or trying double buffering.I also tried to draw on a listbox control and set it's scroll property etc...but no dice.
I'm guessing there is no way to display , say 200 rectangles vertically on a windows form using draw. I need some other solution... any ideas please.
Maybe a list of pictureboxes and then populate each picturebox with the solid color ?
Thanks
You are drawing GDI+ rectangles on a form during the paint event? The form would have no idea that you are creating objects outside of the clipping space and would therefore have no idea that you need to scroll.
You would need to add a scrollbar to the form and then calculate the value\position of the scrollbar and use that to determine what portion of your rectangles to draw upon the paint event. This would involve a bit of manual effort. You could draw them all to an in-memory bitmap of the appropriate size and then just copy the portions of that to the form upon draw.
Or:
If you wanted the form to do this for you, create a custom rectangle control and place 200 of those on the form. Since they are components and have a concrete height & width, the form would then know it needed to scroll, and would do so accordingly provided that autoscroll was set.
it can be as simple as this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.DoubleBuffered = true;
this.AutoScroll = true;
for (int i = 0; i < 100; i++)
this.Controls.Add(new Rectangle() { Top = i * 120, Left = 10 });
}
}
public class Rectangle : Control
{
public Rectangle()
{
this.Width = 100;
this.Height = 100;
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.DrawRectangle(new Pen(Color.Black, 5), 0, 0, 100, 100);
}
}