Bug or am I doing something wrong? Usercontrol Painting - c#

private void UserControl1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawEllipse(Pens.Black, new Rectangle(-200, -500, this.Width + 400, this.Height + 420));
}
Paste the above code into a usercontrol. Drop the usercontrol onto a form and anchor it to all 4 points.
In the designer (Under Visual Studio 2010) it renders perfectly (even as you resize). Run it and try and resize the form and the ellipse becomes skewed.
Here are two examples both after resizes the first while running, the second in the designer.
Obviously the behavior in the designer can't always be assumed to be the same (Although it would be nice) but my understanding is that the code above is completely legal. Am I wrong?

Stecya has posted the "fix", but omitted an explanation detailing why that works or why you're seeing a discrepancy between the behavior in the designer and in the running application. In my mind, that makes the answer only minimally useful, so I thought I'd weigh in with an attempt at an explanation.
You already know that calling the Invalidate method is the solution. What this does is tell Windows that the entire surface area of the control needs to be redrawn the next time the window gets painted. Simple enough, but why don't you have to do this in the designer?
The answer lies in the fact that you're running the program with the Windows Aero theme enabled. Aero uses an entirely new window manager called the Desktop Window Manager (or DWM for short) based on composition. Each window is double-buffered, meaning that its graphics are rendered off-screen into a temporary bitmap, and only then blitted to the screen. This allows all sorts of cool effects and fancy transitions that users seem to like nowadays.
But, of course, it means that the sections that have already been drawn aren't erased and redrawn unless you explicitly instruct Windows that it needs to do so. That's not a problem for the form inside the designer, because there, Aero's DWM composition is not enabled. When the window gets resized, it is automatically redrawn, and your swoosh looks smooth and correct.
Outside of the designer, with Aero composition enabled, only the newly-exposed portions of your control are redrawn (the rest are still there in the buffer), so the shape is wrong. Part of the old shape is still there, and part of the new shape was just drawn in. Calling Invalidate tells Windows "the graphic surface of this control has changed; forget everything you thought you knew about it and redraw it from scratch next time". So Windows dutifully obeys, discarding that portion from its off-screen buffer and redraws it in from scratch, producing a correctly-rendered, nicely-smoothed path.
You can effect the same change in another somewhat more elegant way: Tell the control that it needs to redraw itself every time that it is resized. Insert the following code into the control's constructor method:
public MyUserControl()
{
// Force the control to redraw itself each time it is resized
this.SetStyle(ControlStyles.ResizeRedraw);
}

You can manually Invalidate control while resizing
private void Form1_Resize(object sender, EventArgs e)
{
userControl11.Invalidate();
}

Related

Windows Form Awkwardly "Resizes" when Started

I'm using Windows 10, Visual Studio 2017 and writing a C# Windows Form Application.
I have a windows form application that I am writing (partly in an attempt to get better at writing such things). I have designed my form nicely, with everything spaced and sized properly, but when I press F5 to start the form to debug it, I find that it loads at about 75% the size of the one I see in the designer.
This resizing seems a bit hit and miss, with buttons that were previously aligned no longer being so, and text no longer fitting in its spaces (see pic - the top part shows the designer and the bottom shows the actual form being run).
I would like to have the designer accurately reflect the final look of the form - does anyone know what is going on or how to avoid the problem? Everything I have looked at on the web talks about choosing to resize the form, not this enforced resize!
Have you changed the whole form font size? By default WinForms designer set
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
try changing the AutoScaleMode and see what happens.
I've experienced similar WinForms designer issues when the default Font (in the form property) size is not 8,25pt. I dont't know why but seems related to desktop and/or screen configuration. Not sure but some weird behaviours could be bugs (WinForms is now quite old...).
AutoScaleMode.Font means that form scaling is based on font size. So trying changing different font settings can solve the problem.
hope this help
When designing the form, the form automatically sets the anchor points to Top Left. You will have to set the anchor points to your form.
The anchor style works like this. On a control if you set anchor points to:
Top/Right then the control stays in the Top Right.
Top/Left then the control stays in the Top Left. Bottom/Right then the control stays in bottom right. Bottom/Left then the control stays in bottom left.
Top then it stays at the top.
Bottom then it stays in the bottom.
Left then it stays in the Left.
Right then it stays in the right.
Top/bottom stretches top to bottom.
Left/Right stretches left to right.
Now when you anchor a control to any of those combinations they will stay in that location when form is maximized. Controls can anchor to each other as well.
I hope this helps.
Also here is a tutorial I did on this.:
https://youtu.be/wlZ6pt79v1E
accurately reflect the final look of the form
Your form's appearance is mostly decided by the end user. Font, size, colour, scale, contrast... all these things are under the users control, not yours.
Consider using split panels, and maybe some flow panels. Get used to 'randomly sizing' the form when you think you've finished designing, to see how it reacts to being the 'wrong size'. Someone will find a way to shrink or grow your form, and handling that gracefully is easier than enforcing a view.

How do I fit/re-size Windows Form to any screen resolution?

I know this is duplicated question but I checked all other related question and their answers did not help ( the result still the same as shown in screenshot 2)
I am new to c# windows forms. As shown in screenshot1, I have Form1 with some controls and each group of controls were put in a panel. I designed the application in PC1 as shown in Screenshot1 which is fit the screen resolution and worked well.
My application was developed in 1366 x 768 screen resolution (as shown in Screenshot1) but when I run this application in different computer (PC2) with different monitor size and different screen resolution the form appeared too big and part of the application is missing or is out of the screen.
However I solved this issue using Anchors but another issues came up which is: the user control does not re-size itself ( as shown in screenshot2) and part of it is cut or went under panel1 . I do not know if the problem is related to user control or related to all controls in Form1 (they should resize themselves)
I even tried the following code but the result still the same:
this.WindowState = FormWindowState.Maximized;
this.Location = new Point(0, 0);
this.Size = Screen.PrimaryScreen.WorkingArea.Size;
Screen.PrimaryScreen.WorkingArea
I have been searching to solve this issue the whole day yesterday but I failed, Please help me with any idea/suggestion it might work. Thank you
If you are working with Windows Forms and you cannot switch to WPF then you will prefer to do all the design in the lowest resolution at which you must run.
In WinForms you are setting the Size of every element so they will not re size according to the app size. What they will do is to be distributed along the empty space (if you program them to do so) increasing the free space between them, that's all.
Another option are LayoutPanels as Sinatr said as they try to offer the WPF panel functionality.
By default in WinForms, all controls that you place on the form while designing it have a fixed size. If you don't do anything special, whatever size the controls are when you place them are the size that they are always going to have, no matter what machine you're running on.
As you've noticed, that isn't always going to give good results. The way you work around it is to use a fluid layout, with liberal use of the TableLayoutPanel and/or FlowLayoutPanel container controls, as well as the Anchor and Dock properties for individual child controls. If you take special care to lay out the controls on your form correctly, they can be dynamically resized and rearranged to fit the available screen space.
This code
this.WindowState = FormWindowState.Maximized;
this.Location = new Point(0, 0);
this.Size = Screen.PrimaryScreen.WorkingArea.Size;
Screen.PrimaryScreen.WorkingArea
doesn't do anything. The only thing you need there is the very first line. Once you make the form maximized, it will fill the entire screen. You don't need to force it by setting its Size or Location properties. In fact, those have no effect on a maximized form.
The problem is presumably that the controls placed on your form do not resize themselves automatically (as discussed above). If you had a big enough screen, you'd see empty space where the form was filling the screen but had no controls on it. You have the opposite problem: on a smaller screen, controls don't fit and therefore overlap each other.
It isn't a perfect situation. Even if you code up a perfect dynamic layout, if you try to run the application on a system with a screen that is significantly smaller than your design intended, you're going to end up with buttons that are too small to poke. That's why applications are not, in general, designed this way. A screenful of buttons is terrible UI. The only time this kind of design is acceptable is when you're designing for a touch screen UI, like a restaurant POS. And in that case, you already have a pretty good idea what size screens your clients are going to be using, since it's all specialty hardware.

Line gets drawn only after Control moves over it

I have a set of custom controls and a list of geometric objects that I need to draw on the same handle.
I override the OnPaint procedure, put the base.OnPaint(e) in the first line and commence with the drawing of the geometric objects (via e.Graphics.DrawLine etc.).
Those are in a locked list and decay after a while.
Also the customized controls can move around the window.
Now this is almost working as intended except for this fun fact:
The geometric shapes appear only after a control is moved along/above their layouts.
I was able to reproduce this in a small environment: PASTEBIN
I tried flushing the graphics object; save/restore; changing Clip.
Nothing seemed to work.
I am guessing that regions only get invalidated and repainted once a control is present. But how can I force them to be drawn anyways?
Control.Invalidate will tell the framework that the control needs to be redrawn. It does this automatically to redraw controls after, for example, the mouse has obscured part of it, but it will only redraw a the small section that the mouse covered (hence why you end up with a "(re)painting with the mouse" effect. Also moving a window will force it to redraw, as does covering it with another window and then moving that window away again.
But if you are doing a bunch of custom painting, you need to let it know that the control needs to be redrawn by calling Invalidate yourself.

Custom control under modaldialog not repainting when moving dialog

What causes this ? Other controls are shown fine ...
public CustomControl()
{
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.UserPaint, true);
}
The customcontrol is placed in a TableLayoutPanel.
...................
Edit: For clarification:
Suppose you have a window-sized control with a small modal dialog form on top. When you move the dialog window, it's like your painting with the window on the control (the borders are painted on the control). The control doesn't repaint itself like other controls do on the same form, ie montcalendar or other custom controls. I can't seem to find the cause of this ?
Small detail of drawing artifact:
Hard to tell from the snippet. The standard mistake is to draw through Control.CreateGraphics() instead of the OnPaint() method. Won't work, Windows lets the OnPaint method run when parts of the control get uncovered. Which wipes out whatever you drew. Another failure mode is deriving from a control that's a wrapper for a native Window control. UserPaint is not supported for these type of controls, the native Windows code has to do the drawing.
It is clear from the screen shot, note how the text is staggered. That's because the OnPaint() override is using the e.ClipRectangle property to figure out where to draw. That value always changes when you slowly drag a window across your control, it only tells you what part of the control needs to be redrawn. It does not tell you where to draw. That has to be based on the control bounds, routinely the rectangle from (0,0) to (ClientSize.Width, ClientSize.Height).
Only ever use e.ClipRectangle to optimize the drawing. Like skipping an expensive drawing detail when it is outside of the clipping rectangle. It is otherwise a small one, Windows is already quite good at clipping automatically.

Using Visual Studio 2010 Express to create a surface I can draw to

I'm coming from a Java background and trying to port a simple version of Conway's Game of Life that I wrote to C# in order to learn the language.
In Java, I drew my output by inheriting from JComponent and overriding paint(). My new canvas class then had an instance of the simulation's backend which it could read/manipulate. I was then able to get the WYSIWYG GUI editor (Matisse, from NetBeans) to allow me to visually place the canvas.
In C#, I've gathered that I need to override OnPaint() to draw things, which (as far as I know) requires me to inherit from something (I chose Panel). I can't figure out how to get the Windows forms editor to let me place my custom class. I'm also uncertain about where in the generated code I need to place my class.
How can I do this, and is putting all my drawing code into a subclass really how I should be going about this? The lack of easy answers on Google suggests I'm missing something important here. If anyone wants to suggest a method for doing this in WPF as well, I'm curious to hear it.
Thanks
In Windows Forms, you can simply draw on any control by calling its CreateGraphics method. If you have a panel, for example, you can draw like this:
using (var g = panel1.CreateGraphics()) {
g.DrawString("Hello World", 0, 0);
}
Controls also have a Paint event. Add an event handler by double-clicking the event in the properties window, and you can draw like this:
private void panel1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
e.Graphics.DrawString("Hello World", 0, 0);
}
If you want to derive from a control, you can either just do it in code, or create a new user control and change the base class in the code and in the .Designer.cs file (though UserControl or just Control will be fine). If you already have a form in the designer, it's already derived from Form, and you can just override OnPaint.
My advice is: You typically won't need to create a new class if you just want to draw something. Just use the Paint event. If you need to immediately redraw, call Refresh to make the control redraw itself. This should get you going. Note that there is also a protected DoubleBuffered property, which can help you avoid flickering (set it for the form or in your derived control).
I'm not sure what you would do in WPF. I never needed to actually draw something manually in WPF, since the layout and rendering engine is very powerful, and you can just get away with data templates, control templates etc. The point in WPF is that you typically don't draw anything, the engine draws for you.

Categories

Resources