stuengelman
asked on
Need Help Choosing Events To Place Commands to Speed Up Paint Operations on .NET TabControl
Hello,
I am building a Windows PC application in Visual Studio 2008 using VB and the .NET 3.5 Framework.
Most of my main application form is covered by a TabControl. The clickable tabs themselves are hidden, but they are programmatically clicked via Main Menu commands and Main Toolbar buttons. This programmatic clicking causes different content (controls, tables, charts, etc.) to appear within the the main application form just under the Main Toolbar.
Most of my tabs populate slowly, especially those populated with UserControls associated with records on database tables. I think paint speed would be accelerated significantly if I could invoke the SuspendLayout/ResumeLayout commands whenever a programmatic click of a TabControl tab occurs.
My question is: which events of the TabControl object should I place the commands in? Ideally, the SuspendLayout would be invoked before tab content painting begins, and ResumeLayout would be invoked just after tab content painting ends.
Thank you, Stu Engelman
I am building a Windows PC application in Visual Studio 2008 using VB and the .NET 3.5 Framework.
Most of my main application form is covered by a TabControl. The clickable tabs themselves are hidden, but they are programmatically clicked via Main Menu commands and Main Toolbar buttons. This programmatic clicking causes different content (controls, tables, charts, etc.) to appear within the the main application form just under the Main Toolbar.
Most of my tabs populate slowly, especially those populated with UserControls associated with records on database tables. I think paint speed would be accelerated significantly if I could invoke the SuspendLayout/ResumeLayout
My question is: which events of the TabControl object should I place the commands in? Ideally, the SuspendLayout would be invoked before tab content painting begins, and ResumeLayout would be invoked just after tab content painting ends.
Thank you, Stu Engelman
ASKER
Hi CC,
I follow what you are saying. The issue is that there are alot of tabs. I need events at the TabControl level so the Suspend/Resume logic is "generalized".
Thanks, Stu
I follow what you are saying. The issue is that there are alot of tabs. I need events at the TabControl level so the Suspend/Resume logic is "generalized".
Thanks, Stu
Do you load controls programmatically?
ASKER
Hi CC,
Yes, that is part of the issue. The slowest tabs to paint are the ones that instantiate UserControls related to records on a DB table in a programmatic manner. But other tabs with relatively more static content paint slowly too.
Essentially, what I'm looking for are events at the TabControl level to place the Suspend/Resume Layout logic (i.e., whenever a tab click occurs). This saves me the effort of having to place the logic at the tab level (there are alot of tabs).
Stu
Yes, that is part of the issue. The slowest tabs to paint are the ones that instantiate UserControls related to records on a DB table in a programmatic manner. But other tabs with relatively more static content paint slowly too.
Essentially, what I'm looking for are events at the TabControl level to place the Suspend/Resume Layout logic (i.e., whenever a tab click occurs). This saves me the effort of having to place the logic at the tab level (there are alot of tabs).
Stu
Does the slowness occur when clicking a tab first time or does it occur everytime?
ASKER
Hi CC,
It occurs every time.
Stu
It occurs every time.
Stu
I dont think you can do much then. If you stop the layout logic, the tabs wont paint and you obviously dont want that.
ASKER
Hi CC,
I think the solution depends on the sequence of events that fire when a tab is clicked. I need a custom handler for an event that fires before the Paint Event to place the SuspendLayout command, and another custom handler for an event that fires after the Paint Event to place the ResumeLayout command. The question is: which TabControl events do I use?
Stu
I think the solution depends on the sequence of events that fire when a tab is clicked. I need a custom handler for an event that fires before the Paint Event to place the SuspendLayout command, and another custom handler for an event that fires after the Paint Event to place the ResumeLayout command. The question is: which TabControl events do I use?
Stu
If you suspend the layout just before paint, you tab wont be painted and you wont see any controls. Is that what you want? Check the invalidating event.
ASKER
Hi CC,
That's the whole idea. I want to place the SuspendLayout command in an event at the TabControl level before tab painting begins, and place the ResumeLayout command in an an event at the TabControl level after painting ends.
I need to use TabControl level events so the commands apply to all tabs.
Stu
That's the whole idea. I want to place the SuspendLayout command in an event at the TabControl level before tab painting begins, and place the ResumeLayout command in an an event at the TabControl level after painting ends.
I need to use TabControl level events so the commands apply to all tabs.
Stu
You will either need to write custom events propagated from tab level controls or the other solution that can solve your problem is to hide the tab control while performing this operation and show something like "Please wait" (Which looks professional) and then unhide the control once ready.
-Rahul
-Rahul
ASKER
Hi Rahul,
I prefer to avoid the tab invisibility approach, as the whole system is tab driven, and getting a "Please Wait" every time someone switches tabs will be annoying to users.
I could, in theory, place SuspendLayout/ResumeLayout in each Sub that populates each tab, but I'm hoping to avoid this due to the numbr of tabs.
My "ideal solution" would be to understand what the sequence of events is when a tab is clicked. The idea is to choose a suitable event before Paint to place SuspendLayout, and a suitable event after Paint to place ResumeLayout. The question is: what are the two best events to use? I'd like these two events to be at the TabControl level, not the tab level, as I don't wish to have to code the event handlers separately for each tab.
Thanks, Stu
I prefer to avoid the tab invisibility approach, as the whole system is tab driven, and getting a "Please Wait" every time someone switches tabs will be annoying to users.
I could, in theory, place SuspendLayout/ResumeLayout
My "ideal solution" would be to understand what the sequence of events is when a tab is clicked. The idea is to choose a suitable event before Paint to place SuspendLayout, and a suitable event after Paint to place ResumeLayout. The question is: what are the two best events to use? I'd like these two events to be at the TabControl level, not the tab level, as I don't wish to have to code the event handlers separately for each tab.
Thanks, Stu
ASKER
Hello All,
I haven't received any input yet on TabControl events to target, so I tried putting logic directly into the handler for one of my tabs when invoked via the Click event.
My basic logic is:
object.Visible = False
object.SuspendLayout()
[main logic of Sub]
object.ResumeLayout(True)
object.Visible = True
In the above, "object" was tested using both the TabControl, and the applicable tab, as "object". In neither case did any speeding up occur.
Any suggestions? This approach follows the second option given in Rahul's 10/31/11 04:43 AM post. The tab does not hide while it slowly repaints. It seems my extra logic is not actually doing anything.
Thanks, Stu
I haven't received any input yet on TabControl events to target, so I tried putting logic directly into the handler for one of my tabs when invoked via the Click event.
My basic logic is:
object.Visible = False
object.SuspendLayout()
[main logic of Sub]
object.ResumeLayout(True)
object.Visible = True
In the above, "object" was tested using both the TabControl, and the applicable tab, as "object". In neither case did any speeding up occur.
Any suggestions? This approach follows the second option given in Rahul's 10/31/11 04:43 AM post. The tab does not hide while it slowly repaints. It seems my extra logic is not actually doing anything.
Thanks, Stu
Look at the Selecting event.
TabControl.Selecting Event
http://msdn.microsoft.com/en-us/library/system.windows.forms.tabcontrol.selecting.aspx
TabControl.Selecting Event
http://msdn.microsoft.com/en-us/library/system.windows.forms.tabcontrol.selecting.aspx
ASKER
Hi LearnedOne,
Thanks for your input. The TabControl.Selecting Event only addresses where to place the SuspendLayout command; I still have the issue of where to place the ResumeLayout command.
At this stage I'm less concerned about the efficiency of finding TabControl events to place the commands than I am about simply finding commands that will solve my problem. It's not that big a deal to place the commands in the individual tab click handlers themselves, as long as I knew what to put there. Per my earlier post, I'm currently using:
object.Visible = False
object.SuspendLayout()
[main logic of Sub]
object.ResumeLayout(True)
object.Visible = True
In the above, "object" was tested using both the TabControl, and the applicable tab, as "object". In neither case did any speeding up occur. Object visibility was not affected at all, and the same slow painting occured. In other words, the above logic does absolutely nothing to improve performance.
The big issue is occuring in the step "[main logic of Sub]". This logic for most tabs reads a DB table, and renders a UserControl for each record in a DB table (typically input controls for the table fields, and Alter/Delete buttons). Even with very few table records (say, 4 or 5), the process is very slow and annoying. Neither the Visibility nor Layout commands impact performance in any manner; it's as if VB is completely ignoring the extra commands.
I need some way to drastically speed up painting of the UserControls, and possibly speed up their disposal as well (e.g., when the Refresh button on the tab is pressed).
Thanks, Stu
Thanks for your input. The TabControl.Selecting Event only addresses where to place the SuspendLayout command; I still have the issue of where to place the ResumeLayout command.
At this stage I'm less concerned about the efficiency of finding TabControl events to place the commands than I am about simply finding commands that will solve my problem. It's not that big a deal to place the commands in the individual tab click handlers themselves, as long as I knew what to put there. Per my earlier post, I'm currently using:
object.Visible = False
object.SuspendLayout()
[main logic of Sub]
object.ResumeLayout(True)
object.Visible = True
In the above, "object" was tested using both the TabControl, and the applicable tab, as "object". In neither case did any speeding up occur. Object visibility was not affected at all, and the same slow painting occured. In other words, the above logic does absolutely nothing to improve performance.
The big issue is occuring in the step "[main logic of Sub]". This logic for most tabs reads a DB table, and renders a UserControl for each record in a DB table (typically input controls for the table fields, and Alter/Delete buttons). Even with very few table records (say, 4 or 5), the process is very slow and annoying. Neither the Visibility nor Layout commands impact performance in any manner; it's as if VB is completely ignoring the extra commands.
I need some way to drastically speed up painting of the UserControls, and possibly speed up their disposal as well (e.g., when the Refresh button on the tab is pressed).
Thanks, Stu
SelectedIndexChanged Event
http://msdn.microsoft.com/en-us/library/system.windows.forms.tabcontrol.selectedindexchanged.aspx
This event occurs when SelectedIndex is changed, after the tab is visible.
SuspendLayout/ResumeLayout only disables layout events temporarily, and does nothing for slow painting performance. If you need to address that, you might look into SetRedraw (sending WM_SETREDRAW to a control).
Here is a proof-of-concept reference:
http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/d5444fa4-26e0-4ecc-9a33-a590c55531af
http://msdn.microsoft.com/en-us/library/system.windows.forms.tabcontrol.selectedindexchanged.aspx
This event occurs when SelectedIndex is changed, after the tab is visible.
SuspendLayout/ResumeLayout
Here is a proof-of-concept reference:
http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/d5444fa4-26e0-4ecc-9a33-a590c55531af
private const int WM_SETREDRAW = 0x000B;
private const int WM_USER = 0x400;
private const int EM_GETEVENTMASK = (WM_USER + 59);
private const int EM_SETEVENTMASK = (WM_USER + 69);
[DllImport("user32", CharSet = CharSet.Auto)]
private extern static IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam);
public static void SetRedraw(bool shouldDraw, Control control,
ref IntPtr eventPtr)
{
if (shouldDraw)
{
SendMessage(control.Handle, EM_SETEVENTMASK, 0, eventPtr);
SendMessage(control.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
control.Invalidate();
control.Refresh();
}
else
{
SendMessage(control.Handle, WM_SETREDRAW, 0, IntPtr.Zero);
eventPtr = SendMessage(control.Handle, EM_GETEVENTMASK, 0, IntPtr.Zero);
}
}
ASKER
LearnedOne,
Thank you. Will test your approach.
Stu
Thank you. Will test your approach.
Stu
ASKER
LearnedOne,
Would it be much trouble to provide a VB version of your code?
Thanks, Stu
Would it be much trouble to provide a VB version of your code?
Thanks, Stu
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
LearnedOne,
Thanks so much. Will test it out.
Stu
Thanks so much. Will test it out.
Stu
If you want to use these, you would use these in code that is adding the controls to the tabs. So suspectlayout before adding controls and resume layout after adding controls.