How to draw a control, without drawing the control - c#

I've got a list of UserControl objects; when a menu option is clicked to go to another section of the application it does the following:
Set the currently displayed usercontrol to visible
Clear the main panel's Controls list
New up the requested control (if not already created in the list)
Add the new control to the main panels' Controls list
Dock the new control to fill
Set the new control to visible
I did this because, previously all of the areas of the application were not user controls and they were just collections of controls in a TabControl. The underlying code was monstrous (the code in frmMain was 13000+ lines).
It works well. All controls (what each tab page would have been before) manage their own behaviour, each control has a small code footprint. I can have a sexy menu. All good things.
However, obviously there's a problem. Before, the tabcontrol would load on startup, and all tabs would render (but weren't seen). One tab page in particular has a scheduling control on it and it takes a good 3-4 seconds to draw and adjust its layout. Now that controls are loaded and shown as they're needed, the first time you view this particular control, you see it load and adjust its size/formatting/etc. Which is hardly esthetically pleasing.
My question is, how can I load and render this control so that it'll render and figure out its layout, but without it actually showing the user?
I've tried simple things like:
ScheduleWindow scheduler = new ScheduleWindow() { Visible = false; }
mainPanel.Controls.Add(scheduler);
scheduler.Visible = true;
I've tried creating and loading the control on its own thread (with numerous difficulties) and it still didn't do anything...
Is there any way to achieve what I'm looking for?

Try using the SuspendLayout() and ResumeLayout() methods on the main form? When you call SuspendLayout(), you can do whatever you need to do with the controls you are adding, such as docking, resizing, etc. When you call ResumeLayout(), all changes will be applied at once, and should happen instantaneously.
Alternatively, some controls have a BeginUpdate() and EndUpdate() method, which suspend redraws for that control, allowing you to do heavy work (such as adding thousands of items to a ListView) without seeing the updates happen live. This also improves performance, as rather than redrawing every time the control is changed, you batch changes, then redraw once.

Try calling scheduler.Handle.ToString() and/or scheduler.Refresh().

Related

Is it worth to show/hide existing form over creating new form every time?

Imagine we have:
1) some parent MainForm;
2) some child NewItemForm (called often).
What I think is: why would I use new NewItemForm() every time I need the form if I could create it once and set it's Visible property to true/false after on need (clearing the previous input ofc).
What I would want to know: personally I did not notice any difference however my sketchy knowledges tell me there should be some (memory allocation, controls initialization); support me please with your skill in
my doubts.
If the child controls are more or some third party controls pasted on the Winforms then it will take some seconds to load/initialize the form. If there is no control pasted or only .net controls then it is okay. Otherwise it will have performance issue while painting hide and show.

Create controls dynamically or create controls in a side form? C# winforms

I have a form full of controls, and there is no room for other controls. On the bottom of the form I have a panel with some controls on it.
My goal is that when a certain button is clicked, the original panel on the bottom will be replaced with another panel that contains controls which could be created before the program starts, meaning these controls in the panel do not need to be created dynamically. The replace action would be executed by setting each panel's visible field to it's matched value.
I have thought of two ways of doing this - either creating the new panel (and it's controls) dynamically and adding it to the form instead of the original, or creating the new panel in another form and when the relevant button is clicked the panel being taken from that form and added to the required form (by creating an instance of the new form and making it's panel's modifier public). The "side form"'s purpose is only to create that panel, it has no functionality of it's own.
The advantages of creating the new panel dynamically:
There is no need to create a zero-functionality form.
The advantages of creating the new panel in a side form:
It's very clear which controls are added to the new panel and their positions.
It's very easy to set the location and other fields of the controls in the new panel.
Which way is better?
Thanks!
Have you considered TabControl? That seems a good fit for your needs. Other controls I can think of are StackPanel (Can be fairly easily done for Windows Forms) or OutlookBar like control (again a user control).
Simplest and quickest way seems to be TabControl.
Edit:
SideForm is a different windows form I suppose. So if you are thinking to make controls public and then change their visibility etc, please don't. Use delegates to handle SideForm's events in MainForm.
As you mentioned, there is no room for more controls, I would suggest more screens rather than just one. Having said that I do not know much about your current UI design and functionality so it's up to you.
I would say having the controls hidden and just playing with the Visibility is fine. This means that you do not have to worry about positioning of controls, anchoring and docking at runtime. The problem could well be loading of form. Having huge number of controls having a lot of data associated with them may slow things down.
IMO the best way would be to utilise user controls for this purpose. Simply create one user control per panel you wish to show/hide and place your controls inside. This way you will have both: the designer and the "extra form" you wanted.

How to fix nested winform control flicker issues

I am currently working on a program that uses a fairly complex structure of nested winform controls which changes dynamically as a user makes certain selections. To go into more detail about the specific layout of the controls would be to extensive for this question.
When ever a selection is made, a lot of updates are made to the underlying model which is controlled by the user controls. This then results in series of corresponding changes in the size/position/visibility of the displayed controls. All of these changes results in a painfully intense flickering of controls on the screen. I need to somehow fix this so that everytime the user makes a selection the screen is basically frozen until all of the control updates have completed.
I have attempted to use the Control.SuspendLayout/Control.ResumeLayout methods in many different places and ways and I can not eliminate the crazy flickering. I thought that suspending layout on the root control during the changes would fix the problem but it appears that this SuspendLayout doesn't help when child controls are changed.
Do I need to use some other approach rather than SuspendLayout? Is there a way I can debug SuspendLayout to see why it doesn't appear to be cascading to all of the child controls?
Suspend/ResumeLayout isn't your problem here. That only suspends automatic layout, the kind that is triggered by the Anchor and Dock properties. Double-buffering can't fix your problem either, that only suppresses flicker in each individual control. Your real problem is that you are updating too many controls at the same time, each will take its turn to paint itself and that takes time.
What you need is a different kind of double-buffering, compositing. Check out if the solution in this thread solves your problem.
In addition to #tommieb75's suggestion for double buffering, you can try and see if your root level controls have BeginUpdate/EndUpdate method pairs. These should help repress the repaints in between the calls.
If you are using WinForms 2+ then you can just set the 'Control.DoubleBuffer' property on the control to true (in the designer even).
With framework 2, setting DoubleBuffered sets the 3 flags : OptimizedDoubleBuffer, AllPaintingInWmPaint, and and another that I forgot, 'UserPaint' perhaps.
Also, do look at the BeginUpdate/EndUpdate as mentioned by #yetapb.
Use the SetControlStyles in the user Control, the flag is OptimizedDoubleBuffer which will prevent the flickering.

To Show a Control in two Windows Forms

I have inherited a control from Panel-Class.
I have added some events to this control. I gave move - ability to this control
and so on ..
I have two display screens. I have a main program where the inherited
panel is displaying an image on a small area. I want to show this panel
fullscreen on a second.
I created a new form and use the same control... But i can not move both screens
together. What should I do ?
If you want to be able to manipulate both forms at the same time, show the second form with Show() instead of ShowDialog(). You can certainly pass the original panel to the second form and add it to the form's Controls collection. I am not sure if this is the best way to do it (sharing one control across two forms), but I don't know your requirements either.
I wouldn't use a second form, but a second 'mode' (fullscreen vs. not) on your existing form.
You can have 2 panel controls, or just one and resize.
I think this kind of behaviour calls for a model-view pattern. If that's implemented, the rest should fall into place.
The problem is that you only have one instance of your inherited panel. You actually have to make another "copy" of it, a new instance, before you can add it to the other form.
Mypanel mypanel1 = new Mypanel();
Mypanel mypanel1copy = new Mypanel();
You can either edit these instances to contain the same data all the time through the run, or use something like "Deep Copy":
How do you do a deep copy of an object in .NET (C# specifically)?
Keep in mind, that any changes to mypanel1 should be done to mypanel1copy, too.

Flickering during updates to Controls in WinForms (e.g. DataGridView)

In my application I have a DataGridView control that displays data for the selected object. When I select a different object (in a combobox above), I need to update the grid. Unfortunately different objects have completely different data, even different columns, so I need to clear all the existing data and columns, create new columns and add all the rows. When this is done, the whole control flickers horribly and it takes ages. Is there a generic way to get the control in an update state so it doesn't repaint itself, and then repaint it after I finish all the updates?
It is certainly possible with TreeViews:
myTreeView.BeginUpdate();
try
{
//do the updates
}
finally
{
myTreeView.EndUpdate();
}
Is there a generic way to do this with other controls, DataGridView in particular?
UPDATE: Sorry, I am not sure I was clear enough. I see the "flickering", because after single edit the control gets repainted on the screen, so you can see the scroll bar shrinking, etc.
People seem to forget a simple fix for this:
Object.Visible = false;
//do update work
Object.Visible = true;
I know it seems weird, but that works. When the object is not visible, it won't redraw itself. You still, however, need to do the begin and end update.
The .NET control supports the SuspendLayout and ResumeLayout methods. Pick the appropriate parent control (i.e. the control that hosts the controls you want to populate) and do something like the following:
this.SuspendLayout();
// Do something interesting.
this.ResumeLayout();
Double buffering won't help here since that only double buffers paint operations, the flickering the OP is seeing is the result of multiple paint operations:
Clear control contents -> repaint
Clear columns -> repaint
Populate new columns -> repaint
Add rows -> repaint
so that's four repaints to update the control, hence the flicker. Unfortunately, not all the standard controls have the BeginUpdate/EndUpdate which would remove all the repaint calls until the EndUpdate is called. Here's what you can do:
Have a different control for each data set and Show/Hide the controls,
Remove the control from its parent, update and then add the control again,
Write your own control.
Options 1 and 2 would still flicker a bit.
On the .Net GUI program I'm working on, I created a set of custom controls that eliminated all flicker.
Rather than adding the rows of the data grid one at a time, use the DataGridView.Rows.AddRange method to add all the rows at once. That should only update the display once. There's also a DataGridView.Columns.AddRange to do the same for the columns.
This worked for me.
http://www.syncfusion.com/faq/windowsforms/search/558.aspx
Basically it involves deriving from the desired control and setting the following styles.
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.DoubleBuffer, true);
Sounds like you want double-buffering:
http://www.codeproject.com/KB/graphics/DoubleBuffering.aspx
Although this is mainly used for individual controls, you can implement this in your Windows Forms control or Form.
Unfortunatly, I think that thins might just be a by-product of the .net framework. I am experiencing similar flickering albeit with custom controls. Many of the reference material I have read indicates this, alongside the fact the the double buffering method failed to remove any flickering for me.
You may also try this, its work.
public static void DoubleBuffered(Control formControl, bool setting)
{
Type conType = formControl.GetType();
PropertyInfo pi = conType.GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
pi.SetValue(formControl, setting, null);
}

Categories