Windows Develop Bookmark and Share   
 index > Windows Forms General > SplitContainer - DoubleBuffering does not prevent child panels from flickering
 

SplitContainer - DoubleBuffering does not prevent child panels from flickering

On and off MSDN forums, there have been questions and comments raised about flickering due to SplitContainer.

The repeated official answer from MSDN is the same - setStyle for DoubleBuffer, UserPaint and AllPaintingInWmPaint to true.

All the while the official answer does not andress this one obvious phenomenon:

  1. The child SplitterPanels, panel1 and panel2, do not expose their setStyle methods.
  2. SetStyle methods are protected. Therefore in order to apply setStyle to child SplitterPanels, the programmer needs to create asubclass of SplitterPanel.
  3. But SplitContainer does not allow you to replace the child SplitterPanels referenced by the variables panel1 and panel2 with our own SplitterPanel instances.

Therefore, there is no way to enable doublebuffering on the individual SplitterPanels. There is no point in enabling doublebuffering for SplitContainer.

In fact, having doublebuffering feature available to SplitContainer is nearly a waste of namespace real-estate, because what really matters is doublebuffering the child SplitterPanels not the SplitContainer itself.

Another answer given to solve this problem is - have the contents of the SplitterPanels absorb theSplitterPanel'sirresistableurge toflicker.Which would require the programmer to create contents that have complex manual painting strategies that may or may not work. Which the programmer may not able to implement due to class protection of the content being use.

Therefore, the only effective answer I have found on the internet is - create your own SplitContainer class.

I urge MSDN to carefully inspect this issue and admit that there is a bug (aka non-deliberate feature)here:

  1. Please do not tell us to use doublebuffering unless
  2. You can tell us a way to propagate the double buffering to the child SplitterPanels.

Perhaps, the issue would be solved in .NET 3.x?

Blessed Geek  Sunday, September 28, 2008 9:11 AM
The SetStyle() method of the panels are not accessible. You can hack around that with Reflection:

using System;
using System.Windows.Forms;
using System.Reflection;

public class MySplitContainer : SplitContainer {
public MySplitContainer() {
MethodInfo mi = typeof(Control).GetMethod("SetStyle",
BindingFlags.NonPublic | BindingFlags.Instance);
object[] args = new object[] { ControlStyles.OptimizedDoubleBuffer, true };
mi.Invoke(this.Panel1, args);
mi.Invoke(this.Panel2, args);
}
}

Hans Passant.
nobugz  Friday, January 02, 2009 6:33 PM

OK, I encountered someone suggesting that we should have a panel subclassed to use its protected setStyle method to enable double buffering.

Then attach and dock-fill the subclassed panel to the intendedSplitterPanel as a child control.

Then proceed todeposit stuffs intothe subclassed panel rather than to the SplitterPanel.

I will experiment with that and feedback my findings.

I don't quite like the idea of piling up layers of control unnecessarily. Wouldn't that slow the application down? Would the compiler optimiserbe smart enough to remove unnecessary layers (I guess not)?

But then, I am still curious:

  • Why must the setStyle methods be protected?
  • Whydothe SplitPanels panel1 and panel2 need to be sealed and readonly? Why can't you let us replace them with our own subclassed ones?

Microsoft needs to reconsiderthe SplitContainer to make it more functional, usable and customisable. Microsoft should remove these paternalistic/fascistic restrictions and trust that a programmer knows what to do with thefreedom.

I might be deviating but I need to rub it in. Definition of a fascistic programming language/system - One that implements excessive or annoyingrestrictions and protectionsagainst the freedom of programming in hope of preventing programmers from getting interesting orultra-curricularwork done and to compel potential hackers from deviating from the intended architected use of the system.

Let's say we are all keen supporters of fascistic systems - I would like to know how having or not havingthose tworestrictions would prevent or allowa programmer from deviating from the intended architecture of .NET. And, how would a programmer be able to write write ultra-curricular applications beyond what is already available in .NET?

Blessed Geek  Sunday, September 28, 2008 10:33 AM

Wow! Like somepeople would say -Works like a charm.

But I also overrode OnPaint.

I have a boolean flag PanelContainer.SuspendPainting which I set to true at start of a series of component updates and set it back to false at end of those updates. Which, basically, is similar to beginUpdate and endUpdate found in some controls. I tested it with the most nastyflicker-tendencycontrol ever - the webbrowser control.

Code Snippet

public class ContainerPanel : Panel

{

public ContainerPanel(Container tabContainer)

{

this._TabContainer = tabContainer;

this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);

this.SetStyle(ControlStyles.CacheText, true);

this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

this.SetStyle(ControlStyles.ResizeRedraw, true);

this.SetStyle(ControlStyles.UserPaint, true);

}

private PanelContainer _PanelContainer;

public PanelContainer PanelContainer

{

get{return this._PanelContainer;}

}

protected override void OnPaint(PaintEventArgs e)

{

if (this.PanelContainer == null || this.PanelContainer.SuspendPainting)

return;

base.OnPaint(e);

}

}

At the SplitContainer

Code Snippet

this._ContentPanel2 = new ContainerPanel(this);

this._ContentPanel2.SuspendLayout();

this.Panel1.SuspendLayout();

this.Panel2.SuspendLayout();

this.SuspendLayout();

this._ContentPanel2.Dock = DockStyle.Fill;

this.Panel2.Controls.Add(this._ContentPanel2);

As usual for voluntary semaphores, the SuspendPainting flag may need to be treated for concurrent update.

I avoided that complexity by having only one thread update the flag and designing my code to perform anymultiplecomponent updatessynchronised toone single sequence of updatesand hence having definitebegin and end.

Blessed Geek  Sunday, September 28, 2008 6:33 PM
I'm facing the same problem as you. I have not tested your solution so far, but I have a question.

How to you make it, that SplitContainer uses your new ContainerPanel?
wannabe_2  Thursday, January 01, 2009 9:03 PM
So, now I have tested it. Here's my code:

publicrefclassmyPanel:publicPanel{
public:
myPanel(){
SetStyle(ControlStyles::DoubleBuffer,true);
SetStyle(ControlStyles::UserPaint,true);
SetStyle(ControlStyles::AllPaintingInWmPaint,true);
};
};
publicrefclassmySplitContainer:publicSplitContainer{
public:
mySplitContainer(){
Panel1 =gcnewmyPanel; // this does not work?
Panel2=gcnewmyPanel; // this does not work?
};
};

But two questions arise:
1. How can I use my new panel-class inside the Form-Designer?
2. Is there a way to define 2 new myPanels for the derived mySplitContainer class?

And one more question: How Do you handle a TreeView-control? It's content is flickering as the content of the original Panel-control.
wannabe_2  Thursday, January 01, 2009 10:37 PM
The SetStyle() method of the panels are not accessible. You can hack around that with Reflection:

using System;
using System.Windows.Forms;
using System.Reflection;

public class MySplitContainer : SplitContainer {
public MySplitContainer() {
MethodInfo mi = typeof(Control).GetMethod("SetStyle",
BindingFlags.NonPublic | BindingFlags.Instance);
object[] args = new object[] { ControlStyles.OptimizedDoubleBuffer, true };
mi.Invoke(this.Panel1, args);
mi.Invoke(this.Panel2, args);
}
}

Hans Passant.
nobugz  Friday, January 02, 2009 6:33 PM

This code is what I need, butwhat is the VB.NET equivalent? Thanks!

- Jon

Agent Z5q  Wednesday, January 28, 2009 3:51 PM
Thank you to nobugz. That code worked *however* I had to add two extra control styles before it worked, as follows:

//mustusereflectiontosetdoublebufferingonthechildpanelcontrols
MethodInfomi=typeof(Control).GetMethod("SetStyle",BindingFlags.NonPublic|BindingFlags.Instance);
object[]args=newobject[]{ControlStyles.UserPaint|ControlStyles.AllPaintingInWmPaint|ControlStyles.OptimizedDoubleBuffer,true};
mi.Invoke(this.Panel1,args);
mi.Invoke(this.Panel2,args);

I'm not sure if that will work for everyone's situation, but I hope it is helpful to someone else out there.
  • Proposed As Answer byNate Cook Tuesday, March 10, 2009 4:33 PM
  •  
Nate Cook  Tuesday, March 10, 2009 4:32 PM

You can use google to search for other answers

Custom Search

More Threads

• How can I add an uninstaller in the user's desktop shortcut
• DataGridView - Column/Cell Not Selectable
• FixedToolWindow resizes when titlebar is double clicked
• .net remoting problem?
• ColorPicker ComboBox
• Tab Control Style?
• 32bit Icons not being displayed in ListView control
• Creating helper apps
• How do i know a file is opened (either for read or write)???
• WebBrowser Control