65.9K
CodeProject is changing. Read more.
Home

Border Container

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (23 votes)

Jul 30, 2008

CPOL

12 min read

viewsIcon

71694

downloadIcon

3169

A collapsable container control with complete header, border, and color customization. Also has the ability to utilize an 'Activation' button (like the 'Active Files' button you'll find at the top of every form in the Visual Studio IDE).

Border Container - A Panel on Steroids

With the changes to the BorderControl I wrote two years ago, the once slim and trim replacement for the WinForms.Panel control has grown large, fat, and heavy! It was a small price to pay to improve the UI for the applications I've been working on, and while the control has grown in size and complexity, the machines using my controls have also grown in power and ability... so it was a wash as far as I was concerned.

That having been said, you could easily take this new control and remove from it everything you didn't require and wind up with a fairly small DLL.

While you can dynamically adjust the height of the Header within the BorderContainer (BC), the three buttons: Close, Collapse, and Activation, are all fixed in height and width, so if you planned on a Header with a height of 12 pixels and you wanted to use one or more of the management buttons, you'll definitely want to change the images within the ImageList as well as the CONSTs that are used for ButtonHeight and ButtonWidth as well.

BorderContainer

Along with the BorderContainer (a replacement for the Panel control), you also get in the DLL, a BorderForm which is a replacement for Windows.Forms.Form. It has all of the same properties as BorderContainer minus the Collapse capabilities. There is also a property that sets the opacity of the form while being dragged.

The image on the left shows a sample BorderForm.

The image on the right shows that same BorderForm being dragged with a DragOpacity of 0.5.

BorderContainer

BorderForm - Being dragged
 

Author's note: The Color Selector control used as a replacement for .NET's color property editor is included in BorderContainer.dll. It's a dialog box, but as you can see from the demo BorderContainer shown here, you can also use the individual parts: ColorBox and VerticalColorSlider.

What's New?

A graphical 'collapse' button has replaced the old-style push-pins. The image for this button changes based on where the BorderContainer is docked. There is an ImageList that holds normal, mouse-over, and mouse-down images for Top, Left, Right, and Bottom collapsing as well as the Activation and Close buttons. They are 17x19 32 bit PNGs, but changing them would be as easy as replacing the corresponding images within that ImageList, making sure you change the sizes appropriately - then changing the two constants: BUTTON_HEIGHT and BUTTON_WIDTH to match your new image size.

  • ButtonOffset - This is a property that allows you to adjust how close to the right-edge of the BC you want your buttons to line up with.
  • ButtonGap - a property that allows you to adjust the number of pixels in between each button.

A 3-color gradient header is now available along with the ability to adjust where the center color fades in:

  • BackgroundColorBegin - The starting color of your gradient.
  • BackgroundColorCenter - The middle color of the gradient.
  • BackgroundColorEnd - The final color of the gradient. This is also the solid color used to fill-in the Header if you select no gradient, as well as the color used to fill-in the side panels if you enter an InnerBorderWidth > 0.

Here are some of the properties that have been added:

  • AutoCollapse: If True, the BorderContainer (BC) will automatically collapse when the user double-clicks the header.
  • AutoRefresh: If True, the BC will refresh itself automatically whenever UI properties are changed. You can turn this to False if you're going to set a large number of properties at run-time, then refresh the entire control when your property changes have been completed.
  • AllowResize: If True, the user can resize the control at run-time without having to place a Splitter control next to the BC.
  • InnerBorderWidth: A property that will display a border along the inside of the BC - the ClientRectangle is automatically adjusted to prevent controls added to the BC from drawing over the top of this inner border.
  • RoundedCorners: When set to True will draw the header with rounded edges, the size of which is adjusted by setting the RoundSize property.

Using the Code

Drop the DLL into your Libraries folder (or wherever you put your own custom-controls), then add it to the VS IDE toolbar. Once added to the Toolbar, you can use the BC just like a Panel.

Property Details

BorderContainer has the following properties:

BorderDetails This is an expandable property that contains the bulk of the UI settings.
BorderColor The color of your border
BorderLines   Expandable property holding all of the border settings
   
InnerBorder   If True, will draw a single-pixel border around the inside of the client area
InnerPanelShowAll   If True, will set all InnerPanel properties to True
InnerPanelShowBottom   Displays the Bottom Inner Panel
InnerPanelShowLeft   Displays the Left Inner Panel
InnerPanelShowRight   Displays the Right Inner Panel
InnerPanelShowTop   Displays the Top Inner Panel but only if DisplayHeader has been set to False.
ShowAllOutLines   If True, will set all OutLine properties to True
ShowBottomOutLine   Shows the Bottom Outline
ShowLeftOutLine   Shows the Left Outline
ShowRightOutLine   Shows the Right Outline
ShowTopOutLine   Shows the Top Outline
     
DisplayHeader If True, a header will be displayed at the top of the BorderContainer
HeaderDetails Expandable property - all of the details are listed below in this document
InnerBorderWidth   Establishes the width in pixels of the Inner Border panels; valid settings range from 0 (no border) to 10 (very wide)
     
AllowResize   If True, this will allow the user to resize the non-docked edge(s) of the BC; if the BC is docked, only the movable size of the BC can be dragged for resizing
     
AutoCollapse   If True, the BC will collapse when the user double-clicks the Header
     
AutoRefresh   If True, the BC will repaint whenever any UI properties are adjusted during run time; if you have a large number of UI properties to change, you might want to set this to False - make your changes, then reset this value to True so the painting only occurs once
     
CollapsePanel   This is a built-in Panel control that appears if ShowCollapsePanel = True and the BC has been collapsed; you can set all standard panel properties at design-time, but you'll have to add any additional controls to this panel at run-time
     
CurrentState This identifies how the Container will be displayed when the form is opened; 'open' is the default, but you can have the control collapsed at start-up
   
HeaderImage An icon you can place inside the Header
HeaderImageAlignment Horizontal placement of the icon

BorderDetails.HeaderDetails is an expandable property that handles all Header-specific UI elements, and has the following sub-properties:

ActivationMenu This built-in ContextMenuStrip can be edited from within the BorderContainer properties window or at run-time. To add menu items to the strip, expand the ActivationMenu property, scroll down to 'Items', and click on the collection editor. All ToolStripItem types are supported and are added as controls to your form, just as if you had created them by adding your own MenuStrip... so, if you want to trap the SelectedIndexChanged event of a MenuStripComboItem - just look for the control in the 'Class Name' drop down in the VS IDE.
AntiAliasText If True, the text displayed in the Header will be anti-aliased.
BackgroundColorBegin The starting color for the gradient used to fill the Header.
BackgroundColorCenter   The middle color for the gradient.
BackgroundColorEnd   Has several purposes: first, its the final color in the gradient. It is also the color used to fill the inner panels if InnerPanelWidth > 0, and it is the solid color used to fill the entire Header if no gradient is selected.
ButtonGap The gap (in pixels) between each of the buttons drawn in the Header.
ButtonOffset   The gap (in pixels) between the right-edge of the last button drawn and the right-edge of the BC.
ForegroundColor   The foreground color of the BC. Use this to adjust your HeaderText foreground color.
GradientMode   Valid settings are: None, Horizontal, Vertical, ForwardDiagonal, and BackwardDiagonal.
GradientPercentage   There is a smooth transition from Begin to Center to End colors in the gradient. This is the percentage at which the middle color will be at 100%. Example: GradientMode=Horizontal and your BC is 100 pixels wide. Setting this to 0.20 will mean that at 20% of the width of the BC, the color will be BackgroundColorCenter... So, the closer to 0 you set this, the faster the change from Begin to Center will occur, and the closer to 1 you set it, the further that transition will take.
Height The height (in pixels) of the header. All graphics displayed in the header will resize, but keep in mind that if you make the height too small, your users will not see the images properly.
RoundedCorners If True, the BC will display rounded corners in the header.
RoundSize   The radius (in pixels) of the 'round' corners.
ShowActivationMenu If True, the Activation button will be displayed.
ShowClose If True, the Close button will be displayed.
ShowCollapse   If 'True, the Collapse button will be displayed.
ShowCollapsePanel   If True, the Collapse Panel will be displayed whenever the BC is collapsed.
Text This is the text-string that is displayed in the Header. If the text is truncated, ellipses (...) will be drawn at the truncation point.
TextAlignment Left is default. Middle and Right are the other available options.

Control Events

The following table shows all events that could be raised at run-time.

Resized Fires when your Container is collapsed or expanded
HeaderDoubleClick Fires when the user double-clicks the Header
HeaderClick Fires when the user clicks the Header
ActivationClick Fires whenever the Activation button has been clicked; this will fire regardless of whether or not you are using the built-in ContextMenuStrip
ActivationMenuOpened Fires whenever the Activation menu is opened
ActivationMenuClosed Fires whenever the Activation menu is closed
CloseClicked   Fires whenever the Close button has been clicked
DragResizeComplete   Fires when the User has completed drag-resizing
DragResizing   Fires while the BC is being drag-resized
DragResizeBegin   Fires when the user begins to drag-resize

Custom Property Editor - Color Picker

There is a custom property editor included with this project called, 'ColorEditor.' This required several additional steps to implement, all of the details of which can be found in this wonderful article written by Saeed Serpooshan. I made several modifications for my own personal use, but there is simply no way I would have been able to complete this portion of my control without help from that article...so, Thanks Saeed!

Color_Picker.gif

Custom Property Display Values

One of the modifications I made was to force the property window to display the value *I* wanted displayed, rather than the default data it wanted to display.

I had problems getting the Custom Property Editor to work on Color type, and I think that's because Color already uses a custom editor ... I had to learn how to override that internal custom editor before mine will work... Anyway, to get around it, I store all of my control colors as strings in the format, "###, ###, ###", which are nothing more than simple RGB values. But I did not want the string to be displayed: I wanted the color in the color-box, followed by editable text.

To pull that off, you have to first tell the editor that you are going to override the painted value, and then (of course) you have to provide the new paint method yourself:

Public Overrides Function GetPaintValueSupported(_
    ByVal context As System.ComponentModel.ITypeDescriptorContext) As Boolean
    Return True
End Function

and here is the overridden Paint:

Public Overrides Sub PaintValue(ByVal e As System.Drawing.Design.PaintValueEventArgs)
    ' Go fill the area first...
    Dim width As Integer = e.Bounds.Width - 1
    Dim height As Integer = e.Bounds.Height - 1
    Dim brush_HeaderBG As New SolidBrush(_myColor)
    e.Graphics.FillRectangle(brush_HeaderBG, 1, 1, width, height)
End Sub

Anti Aliased Text

Anyone out there think this is horrific and complex, and so much work that it's not worth your time and effort? Think again! Normally, if you want to manually paint text, you would do something like this:

' establish our drawing area (_width/_height
' are defined above but not seen in this
' code snippet)
Dim text_Rectangle As New RectangleF
text_Rectangle.X = 1                ' Upper Left Corner...Left
text_Rectangle.Y = 1                ' Upper Left Corner...Top
text_Rectangle.Width = _width - 1   ' Lower Right Corner..Left
text_Rectangle.Height = _height - 1 ' Lower Right Corner..Right

' establish our formatting
Dim text_Format As New StringFormat
text_Format.Trimming = StringTrimming.EllipsisCharacter  ' draws ellipses (...) at the
                                                         ' truncation point
text_Format.Alignment = StringAlignment.Center           ' Vertical positioning
text_Format.LineAlignment = StringAlignment.Center       ' Horizontal positioning
text_Format.FormatFlags = StringFormatFlags.NoWrap       ' Dont wrap the text...let
                                                         ' the Ellipses do their work

' establish our brush
' (SomeColor is a Color Type defined above but not seen in this code snippet)
Dim text_Brush As New SolidBrush(SomeColor)

' Paint the text
e.Graphics.DrawString("Your Text Goes Here", Me.Font, _
                      text_Brush, text_Rectangle, text_Format)

But, let's say you want that happy little string to be anti-aliased. GDI gives us everything we need...this is a very complex set of code and not commented very well, so please read carefully!

.
.
.
' Anti Alias the text
e.Graphics.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias

' Paint the text
e.Graphics.DrawString("Your Text Goes Here", Me.Font, _
                      text_Brush, text_Rectangle, text_Format)
.
.
.

A similar technique can be used for all Drawing methods like the border used to surround the rounded corners:

.
.
.
' Anti Alias the drawing
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
e.Graphics.DrawArc(BorderPen, _PLeft, _PTop, ArcSize, ArcSize, 180, 90)
e.Graphics.DrawArc(BorderPen, _PWidth - ArcSize, _
                   _PTop, ArcSize, ArcSize, -90, 90)
.
.
.

Trimming the Fat

This last section would be to describe the various areas of the control that can be removed if you're looking for just the basics:

  • Activation Menu: Cutting the Activation button and Context Menu would go hand-in-hand with removing the images for that button as well as the code to activate and raise the events. This would be an easy way to trim.
  • Collapse Panel: This was added for one specific project I was working on, and I've never used it again - there's not a ton of overhead in including the collapse panel, but this would be another, very easy target for removal.
  • Gradient brushes: Unless you're going to require gradient headers, all gradient painting and properties could be removed with very little effort.
  • Resizability: The code that allows this is relatively small - you could remove this quite easily, but you would not be saving very much, and most good UIs have the display elements contained within sizable panels.
  • BorderForm: This is an entire namespace that you could remove with a single-click, and compile, reducing the size of the DLL significantly.
  • Color Picker: Removing this will take a bit more work. It is not as simple as changing the property from the custom editor. Since the parent property is expecting a 'String' type for this property, you'll have to remove the custom color editor and change the color properties back to type 'Color'.

Installation

  1. Unzip the source files and open the BorderContainer project.
  2. Compile the project.
  3. Open the Form Toolbox in Visual Studio.
  4. Right-click on the tab in which you would like to place the control.
  5. Click 'Choose Items...'.
  6. From the 'Choose Toolbox Items' dialog box, click 'Browse'.
  7. Navigate to the Bin folder under BorderContainer (and deeper into either Debug or Release, depending on your settings).
  8. Click on BorderContainer.dll and click 'Open'.

That's it! The BorderContainer is now part of your Toolbox and available for use in any of your VB.NET projects.

History

  • 07/29/2008: Control first introduced to CodeProject.com.
  • 02/10/2010: Bug fixes.