You all know what throbber is. This is small rotated circle used to indicate that program is working. Used usually for progress bar replacement when current progress state is unknown (i.e. infinity progress bar). For example throbber is used in Firefox browser.
Several months ago I found a nice control named LoadingCircle on CodeProject. The idea was good and control looks beautiful, but is has strange design-time behavior and its toolstrip control are almost useless. So I decided take best from this control (painting logic) and write another much more design-time friendly component. And I rename LoadingCircle to Throbber (a name used by Firefox).
First of all I moved all painting logic to independent class called ThrobberRenderer is has only two public methods and several public properties for customization. This class is needed because I want to create several controls with throbber logic (custom control and ToolStripItem ancestor). I do some optimizations and code cleanup, but the most of code and all ideas are from original control.
Second part is to create control which uses this ThrobberRenderer class to paint itself, add animation logic, autosize logic. There was a problem with implementing autosize logic, because just override AutoSize property and GetPrefferedSize is not enough, but this problem is solved by overriding SetBoundsCore method and some design-time class are needed too (for prevent resize autosized control).
Third part is to create ToolStripThrobberButton class, a ToolStripButton ancestor with clickable button behavior. The main idea here is hide all image behavior and replace them with throbber. This component can have text and looks like as standard toolstrip button with image replaced with throbber.
And as end part I create ToolStripThrobberItem a simplified version of ToolStripThrobberButton that inherited from ToolStripItem (instead of ToolStripButton) and can only draw itself, without text or clickable behavior support.
Using is pretty simple. Just drop the control on form (or create toolstripitem on toolstrip), set up several properties and that's all.
All these components have several basic properties:
First four properties used to customize throbber, and the last one used to set all these properties at once.
The control has animated behavior when enabled and static when disabled. Animation speed can be controlled through AnimationSpeed property. I have also added BorderStyle property to mimic any other control from standard library.
ToolStripThrobberButton has also ThrobberColor property to distinguish text color (ForeColor) from throbber color.
Firsts of all we need to hide all properties that exist in Control class but don't need in this control. This is done by overriding these properties and hide them from world by using special attributes.
Then I need to rewrite serialization logic. For example when Style property is set, there is no need to store InnerCircleRadius, OuterCircleRadius, etc. This is done by using special private method. Such method starts with ShouldSerialize prefix followed with the property name and is used by design serialization logic to decide write property or no.
private bool ShouldSerializeInnerCircleRadius()
When control is autosized I expect non-resizable behavior in designer. But I was wrong. After some investigation I found that custom designer is needed to achieve needed behavior.
public class AnimatedThrobberDesigner : ControlDesigner
Toolstrip items was created with some cut'n'paste work. Logic is almost the same, and this is a place where multiple inheritance (unsupported by C#) can reduce amount of code to write.
Work is done. And I hope that you find these components useful. And I wish to thank Martin Gagne, without your work this cannot be done.
And again I must say that my English is far from perfect. So if you find some mistakes fell free to email me.