I have a zoomable form-interface like MS Word. The form contains +70 controls (Richtextbox, checkbox, etc) that are positioned all over the form.
The problem is that generating the form takes 2.5 seconds. Adding the 70 controls with panel.Controls.Add( ctrl) alone takes 1 second. (16 ms per call).
Is there a way to cache the whole blank form ?
Perhaps someone smart knows another method to generate the form ?
Are these controls being added through the designer, or are you adding them manually in code? If it's the latter, I would recommend calling SuspendLayout on the Form before you load the controls, then ResumeLayout(true) after you're finished loading.
Additionally, if these controls are being added while the form is visible, then suspending and resuming drawing can be a great help. See the accepted answer to this question for more info on how to do that.
EDIT
Why do you need 70 RichTextBox controls? Have you considered redesigning the form so that so many aren't required (reusing some for multiple purposes, for instance)? Have you investigated your custom control to see if any speed can be gained in your own constructor?
After lots of tracing we discovered that the constructor for a Custom Inherited RichTextbox takes 7-8 ms per call.
70 controls means 70 * 8 = 560 ms.
Cant we just copy or clone an already constructed CustomRichTextBox ? Would that make a difference ?
Related
Working with DevExpress 2012 vol 2.10
C# on top of VS 2010
First question seems to have been unclear...
So lets clear it a bit (or try to at least)!
We are building a MainForm with a Ribbon containing many buttons. Every button in the Ribbon is disabled until their respective state is "ready to enable".
"ready to enable" depends on one thing : The WinForm_Popup associated with the button has been completely built, including data retrieval and DevExpress.ExpressApp.ListView construction.
Retrieving data from database takes less than 0.1 second
Calling the WinForm_Popup.Show() takles over 15 seconds
We tried to put this in a Thread or a Task, with no success: It crashes on WinForm_Popup.Show() with an exception related to the DragDrop Event.
What I know by now, is Show() method takes long, but I don't have a clue what happens in this method, but constructing the DevExpress.ExpressApp.ListView, which should be taken away from Show (or do it in a Task or Thred maybe).
Or, in other words, having the WinForm_Popup UI completely built as when it's shown but doing this asynchronously (like in a separate Task, for example).
Any idea, advice, help, link, suggestion, tip... Any "thing" ?
Make a new form and make it empty. In the program.cs file change your main form to the new form. Then make the new form constructor be like this:
public newForm()
{
this.Hide();
Thread backTh = new Thread(() =>
{
MainForm mf = new MainForm();
mf.Show();
});
backTh.Start();
}
I would go for the opposite approach, one that is usually used in slow loading systems like a web browser. Why don't you load the form fast, then use a thread to populate your slow loading grid view?
That way, you can have like a spinning hourglass (or something less 1995) that will tell your users that the data is loading.
I have written a C# 4.0 Windows Forms Application that creates two panels which are both populated exclusively with text labels. I would like to add functionality to my application to print these panels exactly as they appear on the form, but I only want to print these panels and their contents, with no background or other parts of the form.
This link was especially helpful as an overview, but so far I'm only able to print what amounts to a screen capture of the form. The entire form is included, buttons, trim, background, and all. It looks like I need to "rebuild" the form by creating a graphics object (I use the term generically, as I'm not sure what specific graphics-related class I need to employ) and somehow transfer the contents of the panel into this object.
My question is: what classes and/or methods should I research in order to build this graphical object? Also helpful to know: are there any handy tricks within the .NET framework or any libraries out there to automatically fit the result to a single page when building the PrintDocument object?
OK, I found one way to do it (love to my Perl bros out there):
Wrap both panels in another parent Panel. Let's call this Panel "parentPanel." Create a bitmap (memoryBitmap)that is the size of parentPanel (parentPanel.Size).
Next: parentPanel.DrawToBitmap(memoryBitmap, new Rectangle(parentPanel.Location, parentPanel.Size)
Then, in the print page event handler: e.Graphics.DrawImage(memoryBitmap, 0, 0)
I'll leave this open in the likely event that someone else has a better idea.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I suspend painting for a control and its children?
Winforms Double Buffering
I have a form that draws a bunch of user defined controls (81 of them) each of which contains another ten controls (total 8,100 ish). It all seems to be drawn sequentially (takes ~1 second or so).
I've looked at these two questions, and followed the ier reccomendations (setting this.DoubleBuffered = true on both the form and the custom control, and SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); on the form, but that did not appear to do anything.
Is there a way to save the paint function of the form, save it in a delegate, swap in a dummy function so that the form does not get redrawn AT ALL, and then putting the real function back and triggering it.
I assume there is a more standard way of doing this, but I was unable to find it (it is not SuspendLayout/ResumeLayout those just deal with layout logic).
How can I do this?
This is the answer: (a link).
But think of it. If you prevent Paint from being happened, how your UI controls should be updated when user interacts with them? There will be no button glowing, no textbox cursor flickerinig and so on.
If you are okay with that then why you just not RenderToBitmap the container of your user controls as its background image?..
This is really simple.
I have a TableLayoutPanel that is populated with controls (just Labels, Buttons, and some Panels with buttons) based on a database query. When the data needs to be refreshed, I use TableLayoutPanel.Controls.Clear(). Unfortunately, this is a very slow operation. I would expect it to be faster than the code populating the table, but it is at least 3 or 4 times slower.
I definitively proved that the slowness is when executing Controls.Clear() by executing this as the single thing done to the TableLayoutPanel after a message box is displayed (then the procedure returns). The controls visibly disappear from the bottom up. When the recordset is used to repopulate the TableLayoutPanel, the speed of the controls appearing from top to bottom is almost faster than I can see.
I'm already doing TableLayoutPanel.SuspendLayout() and ResumeLayout().
Using this.DoubleBuffered = true on the form doesn't appear to do anything.
I could just Dispose the entire control and recreate it through code, but this is a big pain and makes having a nice form designer GUI pointless. I would have to dig into every property I've set on the control and create a line of code for it (though I guess I could get this out of the designer code itself, it still feels wrong).
Any ideas on how to do the job faster? I'm even open to using other methods besides a TableLayoutPanel... I just need the freedom to put multiple buttons per cell or barring that to be able to span columns in the table header.
Can C# at least freeze the whole form while it redraws and then paint all at once?
I've run into issues with slowness using TableLayoutPanels as well. Rather than setting the DoubleBuffered property on the form, the best solution I have found is to create a new class that inherits from TableLayoutPanel, and in that class' constructor, enable double-buffering:
public class DoubleBufferedTableLayoutPanel : TableLayoutPanel
{
public DoubleBufferedTableLayoutPanel()
{
DoubleBuffered = true;
}
}
Then, use the DoubleBufferedTableLayoutPanel wherever you would normally use a TableLayoutPanel.
This seems to work for my uses:
tableLayoutPanel.Visible = false;
tableLayoutPanel.Clear();
/* Add components to it */
tableLayoutPanel.Visible = true;
There is no need to subclass TableLayoutPanel as in Chris Ryan's answer. I had the same problem and solved it by setting the property through reflection:
typeof(TableLayoutPanel)
.GetProperty("DoubleBuffered",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
.SetValue(myTableLayoutPanel, true, null);
If i'm going to built up some dynamic gui i'm always going to do so in code. But at a starting point i just start with the designer on a dummy form and style each control the way i (or better the customer) like(s). Afterwards i take a look into the Designer.cs file and copy the necessary property settings out of it into some factory function like
private TextBox CreateTextBox(string name, /* maybe other parameters */)
{
var textBox = new TextBox();
textBox.Name = name;
//Other settings from given parameters...
//Further settings which are all the same for these kind of control
textBox.KeyDown += (sender, e) => {};
return textBox;
}
So i make sure that every control feels and looks the same on my GUI. This will be done on each level within my surface (starting with the small controls like TextBox and goes up to the containers like GroupBox or TableLayoutPanel.
In some cases this leads to a point where a factory function calls several other factory functions. If this is becoming true it's time to think about encapsulating these controls into a single UserControl, but as always it depends if this is needed or not.
From my side i can only encourage you to move your code out of the designer into a self-written function. At the beginning it is (as always) more work, but afterwards it is easier to make even bigger changes to the layout.
How can I create a Delphi TSpeedButton or SpeedButton in C# 2.0?
Using a Button and setting the TabStop property to false only works when tapping through the form...
If you need (as I did) a button that does not get selected when clicking on it, there is only one way I have found to do it.
The way I did it, was to subclass the Button class and in the constructor calling the SetStyles and thereby setting Selectable to false, like so:
public class ButtonNoFocus : Button
{
public ButtonNoFocus()
: base()
{
base.SetStyle(ControlStyles.Selectable, false);
}
}
This worked out for me, and is perfect if you e.g. have a control-panel with buttons that perform actions to a selected object...
I'm wondering if you want to create a control like a TSpeedButton, or you just need same kind of end result ...
Programming one from scratch is certainly possible, but I'd only tackle that as a learning exercise.
Assuming you want to achieve a similar end result ...
Delphi's TSpeedButton had a differences from the standard TButton that developers found useful - it was flat, didn't take focus, and it consumed fewer resources than a regular button (because it didn't have an underlying Windows Handle).
Which of these are important to you?
If you just want a flat button that doesn't accept focus, use a regular Button with FlatStyle=Flat (or PopUp) and TabStop=false. You can configure a glyph by setting either the Image property, or a combination of ImageList and ImageIndex/ImageKey.
An alternative to this would be to look for an existing button component that comes close to your needs - one place to look might be the Krypton Toolkit (free to use, see http://www.componentfactory.com/toolkit_buttoncontrols.php).
If you're wanting to reduce the number of resources consumed by your application, it's likely you'll get a better return looking elsewhere.
Back in the days of Windows 3.1 (Delphi 1) and Windows 95 (Delphi 2), the number of available handles was strictly limited, with a maximum number available system wide. Today, with Windows XP and Vista, the number of available handles is far far higher, and the number is per process, not system wide. Unless you're creating thousands upon thousands of buttons, you're very unlikely to come anywhere close to running out.
Does this help? Looks like you would have to handle the OnPaint event, and not take focus...
The regular .net 2.0 button supports part of what a TSpeedbutton Does:
The Glyph: Image
Flat : FlatStyle
It does not handle:
Down
Group
These two are related, you could inherit from the button, and ownerdraw it, adding Down and Group features.
Codeproject has an example of ownerdraw buttons.