The FlowLayoutPanel shares many of an ordinary panel control. They ultimately serve the same purpose, which is to organize children controls. In other words, is a container control that provides dynamically layout for the child controls. However, the stock version of the toolbox has some major limitations in terms of performance. For that reason the following minor modifications can improve your flowlayout panel’s performance, especially if you want to add a large amount of child controls.
public delegate void VoidObject(object obj);
...
...
public partial class FlowLayoutPanel : System.Windows.Forms.FlowLayoutPanel
{
private Control _focusedControl = null;
public VoidObject onChildFocus = null;
public Control focusedControl
{
get
{
return _focusedControl;
}
set
{
onChildFocus?.Invoke(value);
_focusedControl = value;
}
}
public FlowLayoutPanel() : base()
{
DoubleBuffered = true;
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.ControlAdded += FlowLayoutPanel_ControlAdded;
this.ControlRemoved += FlowLayoutPanel_ControlRemoved;
}
protected override void OnScroll(ScrollEventArgs se)
{
//Invalidate();
base.OnScroll(se);
}
protected override void OnResize(EventArgs se)
{
this.SuspendLayout();
foreach (Control c in this.Controls)
{
if (c.HasMethod("InheritedResize"))
{
c.GetType().GetMethod("InheritedResize").Invoke(c, new object[] { this.Width, this.Height });
}
}
this.ResumeLayout();
this.Invalidate();
}
void Control_Entered(object sender, EventArgs e)
{
focusedControl = (Control)sender;
}
private void FlowLayoutPanel_ControlRemoved(object sender, ControlEventArgs e)
{
e.Control.Enter -= new EventHandler(Control_Entered);
}
public void ForcedInvalidation()
{
this.SuspendLayout();
foreach (Control c in this.Controls)
{
if (c.HasMethod("InheritedResize"))
{
c.GetType().GetMethod("InheritedResize").Invoke(c, new object[] { this.Width, this.Height });
}
}
this.ResumeLayout();
this.Invalidate();
}
private void FlowLayoutPanel_ControlAdded(object sender, ControlEventArgs e)
{
this.SuspendLayout();
if (e.HasMethod("InheritedResize"))
{
e.GetType().GetMethod("InheritedResize").Invoke(e, new object[] { this.Width, this.Height });
}
e.Control.Enter += new EventHandler(Control_Entered);
this.ResumeLayout();
}
public virtual void Add(Control value)
{
Application.DoEvents();
this.InvokeIfRequired(() => this.Controls.Add(value));
Application.DoEvents();
}
public void ClearAndDispose()
{
List<Control> ctrls = new List<Control>(this.Controls.Cast<Control>());
Application.DoEvents();
this.InvokeIfRequired(() => this.Controls.Clear());
Application.DoEvents();
foreach (Control c in ctrls)
{
c.InvokeIfRequired(() => c.Dispose());
Application.DoEvents();
}
Application.DoEvents();
ctrls.Clear();
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000; // WS_CLIPCHILDREN
return cp;
}
}
}
Below is an extensions class which is required for the previous example.
public static class Extensions
{
public static bool HasMethod(this object obj, string methodName)
{
var type = obj.GetType();
return type.GetMethod(methodName) != null;
}
public static void InvokeIfRequired(this ISynchronizeInvoke obj, System.Windows.Forms.MethodInvoker action)
{
if (obj.InvokeRequired)
{
var args = new object[0];
obj.Invoke(action, args);
}
else
{
action();
}
}
}
Hi,
Nice one but what is “Common.VoidObject”?
Hi,
Please use this as VoidObject:
public delegate void VoidObject(object obj);
Hi there! Such a nice short article, thanks!
I get errors to HasMethod. “Control does not have mothod HasMethod … ” And missing InvokeIfRequired, also…
Hi! You can use the Extensions class found in this post (updated).