On Tue, 18 Jul 2006 15:57:37 +0100, in
microsoft.public.dotnet.framework.windowsforms you wrote:
>Hi,
>
>Has anybody experienced severe slow-down with the drawing speed of
>WinForms? It's not fast at the best of time, but the particular
>scenario I am having problems with is via COM interop and Excel.
>
>The structure is:
>
>
> Excel VBA macro
> |
> V
> instantiate and call a COM wrapper class exposed
> by my assembly using ComVisible(true)
> |
> V
> Wrapper class instantiates the WinForm
> and displays it
>
>
>The forms don't do anything special, they contain maybe 10-20
>controls, including one or two grids, but you can sit there and watch
>them paint themselves control-by-control.
>
> Phil
I finally got chance to take an indepth look at this problem this
morning, and much to my surprise, I have actually solved it without
too much trouble. The problem was not related to Debug vs Release
mode, order of form painting events, in process vs out of process COM
servers, BeginUpdate()/EndUpdate, SuspendLayout()/ResumeLayout(),
SuspendBinding()/ResumeBinding() or any other "usual suspect".
It was purely a problem within the WinForms engine when it comes to
painting forms. I proved this by creating a simple form and dragging
about 20 controls onto it. Display this form via a COM interface and
the painting speed is terrible (checked list boxes are particularly
bad), run it by double clicking the EXE from within Windows Explorer
and the painting speed was great.
So what's the difference?
It turns out that the problem is related to these 2 magic lines that
VS2005 puts at the beginning of the Main method in every Windows Forms
application:
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
You know, the 2 lines that you mentally tune out because they are
always there and you never need to edit them and they run first before
anything happens because Main is the entry point for your
application...
However, if you are allowing callers to display forms via a COM
interface then you have multiple potential entry points to your
assembly, and Main is actually unlikely to be the first method to run.
For example, here is a COM interface in a test app I wrote:
[ComVisible(true)]
[Guid("33F6DDA9-0D4D-4276-AC8D-C66E315649F2")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IShowForms {
void ShowForm();
}
[Guid("3649EC0C-8F49-4844-B2F0-EF154E2D10AF")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("COM.ShowForms")]
[ComVisible(true)]
public class ShowForms : IShowForms {
public void ShowForm() {
using (Forms.frm1 f = new Forms.frm1()) {
f.ShowDialog();
}
}
}
You can instantiate and run this from VBA using the following:
Dim f As COM.IShowForms
Set f = New COM.ShowForms
f.ShowForm
If you do this, then those magic 2 lines don't get called and the
painting performance is pathetic. So to solve the slow painting
problem we need to ensure those 2 lines are run (the WinForms engine
also requires that the 2 lines are run before any forms are displayed
and that they are only called once).
My quick and dirty solution is to add a static variable and method to
the Program class:
private static bool m_VisualStylesHaveBeenSet;
public static void SetVisualStyles() {
if (!m_VisualStylesHaveBeenSet) {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
m_VisualStylesHaveBeenSet = true;
}
}
Then adjust Main to call this method, and ensure that the constructor
of every class which is exposed via COM also calls it:
static void Main() {
SetReferenceToConfigFile();
SetVisualStyles();
Application.Run(new frmMain());
}
public ShowForms() {
Program.SetVisualStyles();
}
This is a tolerable solution at the moment because I only have about 5
COM-exposed classes, but a better solution might be to try and call it
when the assembly is loaded.
By the way, it's actually the call to EnableVisualStyles() which is
the one which gives the performance boost, the other line doesn't seem
to make any difference. I have had a look at the code for the
EnableVisualStyles() method in Reflector, and it doesn't seem to do
much so the reason for the poor performance is still unknown to me. I
suspect it is hidden deep in the WinForms engine, and may be operating
system related (I am on XP Pro SP2).
Happy interopping!
--
Phil