Almost a year ago I've published first two articles titled "Drawing Custom Borders in Windows Forms" and they turned out to be the most successful part of my blog with almost 13 000 web views (however barely 2 000 people made through to the second part), 86 comments and almost 3 000 downloads till date. If so many people seem to be interested I guess it's about time to give you something new.
I've been using this code in my own project for a while and was always told how cool it looks compared to other applications. However, there were also some people asking why wouldn't we do a full skinning engine and let people choose the skins themselves. Until now, I was excusing myself that there is no more time for such nonsense. What changed my mind? If you are using Infragistics NetAdvantage you already know what's coming from them in next release. In short I've got inspired by what they've done and in order not to fell behind I've decided to add my own skin support.
My latest release (which you can already download here) introduces new component called FormStyleMager. It's a central place that defines styles available for all forms in your application. The idea is that when you have multiple forms using the same styling you can define this style in only one place and reuse on every form. For this reason FormStyleManager maintains a library of available FormStyles. Whats more this library can be load and saved to file. This allows the application to have multiple skins that can be changed at runtime.
In order to load a style library you use the static Load method of the FormStyleManager. For example to load default style library for your application you can put following line in it's Main method:
After that you can apply styles from this library to any form that inherits from the CustomBorderForm class. To do this you only need to set the UseFormStyleManger property to true. Optionally, you can specify which style to apply to this particular form using the FormStyleName property or leave it empty so that form uses the default style.
However, if you don't want to use FormStyleLibraries you can still create a single FormStyle (earlier called CustomBorderAppearance) in your code as before. In previous versions it was done by overriding the CreateBorderAppearance property. Now this can be done at any time by assigning your style to FormStyle property. In this case don't forget to leave UseFormStyleManager property set to false.
But what's the point of having a style manager when you couldn't edit the styles. So my other task was creating the FormStyleEditor. And here it is:
The editor is designed not as separate application as one might expect, but as a component that you use inside of your own application. This has such advantage that when you design your style you can immediately see how it applies to your application. The editor comes packaged as a component that you drop on your form. Later you can lunch the editor (from some button, magic key combination or simply form's Load event) by calling the ShowFormEditor method.
The window shows contents of currently loaded style library so if you loaded one already you would see something like on the screen above, but if not you need first to add a new FormStyle which the Add Style button. Starting from left: New button clears the contents of current style library, Open loads style library from file, and Save of course does the opposite (I've choose the .fsl extension and it simply stands for Form Style Library).
As said before the library can contain more then one FormStyle. For example you can design different skins for the main window and for the dialogs or tool windows. Each style is identified by its Name that you can reference using FormStyleName property on any class inheriting from CustomBorderForm. To select which style to edit you use the drop down list next to Active Style label. Add Style button will create additional styles, and Delete Style button of course removes currently selected style from the library.
Below you have two panels: the tree on the left show hierarchy of elements of the active style and the property grid on the right lets you edit the properties of currently selected element. The hierarchy of elements starts on the FormStyle. It has following properties:
||Name used to identify this style in the library|
||Padding of the client rectangle relative to window bounds|
||Padding of icon rectangle relative to top-left corner of title bar|
||Padding of the title rectangle relative to rectangle of title bar|
||Font used to paint window title|
||Color used to paint window title|
||Color used to draw drop shadow behind window title|
||Offset from window border where window can be sized using a mouse horizontally or vertically|
||Offset from window corner where form can be sized in both directions|
||Image used to paint background on forms non client area|
||Style for window close button|
||Style for window minimize button|
||Style for window maximize button|
||Style for window restore button|
||Style for window help button|
The FormButtonStyle class defines appearance for the Close, Minimize, Maximize, Restore and Help buttons of the form and has following properties:
||Size of the button rectangle|
||Margin around the button rectangle relative to title bar|
||Image used to paint button in normal state|
||Image used to paint button in active state|
||Image used to paint button in hover state|
||Image used to paint button in disabled state|
Last thing that changes with this release is the way the images that are drawn on the border are assembled. Earlier the image drawn in background needed to be cut into 9 pieces and specified one by one. Now you can use single image and instead you specify the stretch margins for the images. These margins specify how this image should be cut into pieces theater would be then used to fill the given screen area. Perhaps this image will better explain how it works:
The red lines represent the StretchMagins for this image. The idea here is that the four pieces cut from the corners are painted exactly the same size as in source image whereas the pieces between the corners running on the horizontal and vertical borders are stretched to fill the remaining space. Also worth noting is that the StretchMargins don't have to be the same as the ClientAreaPadding (like in this example it is slightly bigger to accommodate for the round corners on top).
The same technique is used for painting the form background and all form buttons and it is configured by the SerializableImage class that has following properties:
||The actual image used to paint the corresponding element.|
||Sizing technique used to draw the image. Available values are Centered, Stretched and Tiled. |
||Specifies the rules of dividing image into pieces for the Stretched SizeMode.|
* * *
As already mentioned the code is ready for download here so go ahead and experiment with it. It includes a new skin that I've made based on the new WMP 11 (which I love by the way). If you find any bugs or have suggestions for improvements please let me know. Also if you decide to use my library in your project consider sending me a screenshot so I can see how cool it looks. Until then, have fun!