patterncsharpMinor
Context manager for SuspendLayout
Viewed 0 times
contextsuspendlayoutformanager
Problem
I've found a few places where control updates take longer than the redraw cycle.
I started off surrounding them with
After doing that a few times, I realized it could be refactored into a context:
Then, the above code would look like
I then decided I didn't like having to call the constructor every time, so I created an extension method (
The example then looks like
Questions
-
Is there any reason not to use an
I started off surrounding them with
Suspend and ResumeLayout: container.SuspendLayout();
updateControls();
container.ResumeLayout(true);After doing that a few times, I realized it could be refactored into a context:
///
/// Context manager to suspend and resume layout engine while performing
/// updates that take longer than a refresh cycle
///
/// using (new SuspendLayoutContext(container)
/// DoSlowUpdate(container.Controls);
class SuspendLayoutContext : IDisposable
{
private readonly Control _control;
private readonly bool _performLayoutAfter;
///
/// Constructs the context manager to suspend and resume layout.
///
///
///
public SuspendLayoutContext(Control container, bool performLayoutAfter=true)
{
_control = container;
_performLayoutAfter = performLayoutAfter;
_control.SuspendLayout();
}
/// Calls ResumeLayout on the container.
/// If you call this manually, you are probably using this class wrong.
public void Dispose()
{
_control.ResumeLayout(_performLayoutAfter);
}
}Then, the above code would look like
using (new SuspendLayoutContext(container))
{
updateControls();
}I then decided I didn't like having to call the constructor every time, so I created an extension method (
/// comments elided for brevity):static class ControlExtensions
{
public static SuspendLayoutContext SuspendLayoutContext(this Control container, bool performLayoutAfter=true)
{
return new SuspendLayoutContext(container, performLayoutAfter);
}
}The example then looks like
using (container.SuspendLayoutContext())
{
updateControls();
}Questions
-
Is there any reason not to use an
IDisposable context here? I'm more familiar with python, where I wouldn't hesitate to create new context managers - but the method nameSolution
I think there is nothing wrong with using
I also would prefer extension method over other options. It looks cleaner IMHO. What I don't like is the
The thing you should be careful about is using this class with nested methods. For example, this:
won't work as you want it to. So eventually you might want to implement some sort of reference counting.
IDisposable whenever a class requires some sort of clean-up. It might have been originally designed to release unmanaged resources, but it is definitely no longer the case. Nowadays people use IDisposable to do all sort of things: unsubscribe from events, release pooled objects, flush buffers... this list goes on and on.I also would prefer extension method over other options. It looks cleaner IMHO. What I don't like is the
Context word. Not only because the method name should be a verb, but also because its somewhat misleading. I think a lot of people will assume that ...Context class is the class that implements context object (anti-)pattern. But your class doesn't. For example, class LayoutSuspender both sounds funny and describes what the class does. Win-win.The thing you should be careful about is using this class with nested methods. For example, this:
public void UpdateAllControls()
{
using (container.SuspendLayoutContext())
{
UpdateControlA();
UpdateControlB();
}
}
public void UpdateControlA()
{
using (container.SuspendLayoutContext())
{
UpdateControlA();
}
}won't work as you want it to. So eventually you might want to implement some sort of reference counting.
Code Snippets
public void UpdateAllControls()
{
using (container.SuspendLayoutContext())
{
UpdateControlA();
UpdateControlB();
}
}
public void UpdateControlA()
{
using (container.SuspendLayoutContext())
{
UpdateControlA();
}
}Context
StackExchange Code Review Q#128222, answer score: 2
Revisions (0)
No revisions yet.