Click here to Skip to main content
15,881,204 members
Articles / Programming Languages / C#
Article

DropDownPanel: a complete Expandable Panel

Rate me:
Please Sign up or sign in to vote.
4.36/5 (30 votes)
4 Aug 2005CPOL5 min read 164.8K   5.6K   114   44
Useful and simple, it can be used for options pages in your apps.

Image 1

Introduction

DropDownPanel is a control inherited from System.Windows.Forms.Panel class. I developed this to build up a complete and beautiful options page for applications. A lot of time was spent to achieve high performances, memory saving and complete absence of flickering.

Features

The main features and functionalities of DropDownPanel are:

  • It works exactly like a Panel.
  • It can be collapsed and expanded.
  • It can be moved by dragging its header.
  • It can show a small context menu (on the header) to manage its functionalities.
  • It has some cool customizing possibilities.
  • It fits system colors.

Note: All the properties of DropDownPanel can be set directly in Visual Studio Properties window, because all the ‘simple’ properties are correctly interpreted by the IDE, whilst for the other ones I have created a specific UITypeEditor, compatible with Visual Studio. Please see this image:

Image 2

How to use DropDownPanel

First, you have to add a reference to DropDownPanel.dll. You can add to the Visual Studio toolbox a new Item, in order to use the component in visual mode. To do this, switch to design mode, right-click on the ‘Components’ toolbox, choose ‘Add/Remove Items…’, browse to the DLL and select it. After this, you can drag-drop DropDownPanels to your Forms. On selecting a DropDownPanel on your Form, the Properties page will be displayed. At the bottom you can find all the custom properties.

Public properties

The public properties exposed by DropDownPanel are:

  • AutoCollapseDelay: specifies the delay (in milliseconds) after which the DropDownPanel collapses automatically. Negative values disable this feature.
  • EnableHeaderMenu: specifies if the ContextMenu in the Header is displayed when the user right-clicks on it. This menu contains some useful items to set behavioral data (try the demo App).
  • ExpandAnimationSpeed: specifies the speed for the expand/collapse animation. There are four values available, High, Medium, Low and NoAnimation.
  • Expanded: specifies the status of the DropDownPanel. If true, the Panel is expanded (in design mode some refresh problems may occur on modifying this property; I hope to fix them as soon as possible).
  • HeaderFont: the Font to use for the Header text.
  • HeaderHeight: the header height (in pixels). Ranging from 16-48.
  • HeaderIconNormal: an optional Bitmap to set, will be drawn on the left of the Header text when this is in normal state. The width is arbitrary, but the height must be less than HeaderHeight – 4 pixels.
  • HeaderIconOver: an optional Bitmap to set, will be drawn on the left of the Header text when this is in HotTrack (mouse is over it) state. The width is arbitrary, but the height must be less than HeaderHeight – 4 pixels.
  • HeaderText: the text to be shown in the header. It is like the title.
  • HomeLocation: the location where the Panel will be moved when RestoreHomeLocation() is called. This value is automatically modified when you set the DropDownPanel’s location in the editor.
  • HotTrackStyle: the Header’s behavior, applied when the user moves the mouse pointer on it. Available values are: None (no reaction), FillingOnly (the header is colored with the SystemBrushes.ControlLight color), LinesOnly (the header’s lines and text are colored with the SystemBrushes.HotTrack color) and Both (both the Fillings and Lines are colored as before).
  • ManageControls: if true, the controls added with the AddManagedControl() method will be moved up and down automatically when the DropDownPanel collapses/expands. I’m sorry but the controls must be added via code and not from the designer… The controls can be removed with RemoveManagedControl().
  • Moveable: specifies if the DropDownPanel can be moved by the user (by dragging its header).
  • RoundedCorners: specifies if the DropDownPanel will be drawn with rounded corners or not.

Public methods

The public methods exposed by DropDownPanel are:

  • AddManagedControl(): adds a control to the ManagedControls list.
  • RemoveManagedControl(): removes a control from the ManagedControls list.
  • RestoreHomeLocation(): restores the HomeLocation of the DropDownPanel.
  • SwitchStatus(): switches the status of the DropDownPanel. If it was expanded, this method will collapse it, and vice versa.

Events

When the DropDownPanel finishes its collapsing or expanding operations, a StatusChanged event is raised. The definitions of the event, the delegate and the DropDownPanelEventArgs are:

C#
public delegate void DropDownPanelEventHandler(object sender, 
                                      DropDownPanelEventArgs e);
public event DropDownPanelEventHandler StatusChanged;
protected virtual void OnStatusChanged(DropDownPanelEventArgs e){
    if(StatusChanged != null) {
        StatusChanged(this, e);
    }
}

public class DropDownPanelEventArgs : System.EventArgs {

    private bool expanded;

    public DropDownPanelEventArgs(bool expanded) {
        this.expanded = expanded;
    }

    public bool PanelExpanded {
        get {
            return expanded;
        }
    }
}

The event is raised in case of changes in code status or by user action, without differences. The events are raised as follows:

C#
// expanded is the private field representing the status
OnStatusChanged(new DropDownPanelEventArgs(expanded));

Architecture

The DropDownPanel directly extends the System.Windows.Forms.Panel class. The header is a FlickerFreePanel, which extends the same Panel class and adds a new constructor, which sets the ControlStyle property in order to prevent flickering:

C#
public FlickerFreePanel() {
    SetStyle(ControlStyles.DoubleBuffer, true);
    SetStyle(ControlStyles.UserPaint, true);
    // Do the following step only if you 
    // have already set the UserPaint flag!
    SetStyle(ControlStyles.AllPaintingInWmPaint, 
                                           true);
}

The same operation is performed for the DropDownPanel too. With this stuff, the DropDownPanel results are completely flicker-free. The lines and the text are drawn using some GraphicsPath objects and the system colors available in System.Drawing.SystemBrushes class.

Notes about UITypeEditor

In order to allow properties modification in Visual Studio Property pages, you have to consider some issues:

  • Properties must be structured as .NET properties (get, set).
  • Data types such as numbers (all formats), string, Point, Size, bool, etc. are correctly presented by VS without any other operation.
  • All complex data types must be ‘wrapped’ manually.

The easiest way to implement a custom property is to use enum data type. I report here the example of the HotTrackStyle property. The enum is defined as follows:

C#
public enum HotTrackStyle {
    Both, LineOnly, FillingOnly, None
}

To edit this property from VS, you have to add to the code the following [Editor()] statement (please note the using clauses).

C#
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Windows.Forms.Design;
using System.Drawing.Design;

// HotTrackStyleEditor is the class that 
// manages the property in visual mode
[Editor(typeof(HotTrackStyleEditor), 
                    typeof(UITypeEditor))]
public HotTrackStyle HotTrackStyle {
    // get set ...
}

After this, you have to implement the HotTrackStyleEditor class.

C#
public class HotTrackStyleEditor : UITypeEditor {

    // Your value input control
    public ListBox lstValues;
    // Necessary to show the control 
    public IWindowsFormsEditorService wfes; 

    public override UITypeEditorEditStyle GetEditStyle(
                          ITypeDescriptorContext context) {
        if(context != null && context.Instance != null) {
            return UITypeEditorEditStyle.DropDown;
        }
        return base.GetEditStyle(context);
    }

    // This method shows the value selection 
    // control (in this case a ListBox)
    // and returns to VS the correct value
    public override object EditValue(ITypeDescriptorContext context, 
                            IServiceProvider provider, object value) {
        if(context == null || context.Instance == null) {
            return value;
        }
        wfes = (IWindowsFormsEditorService)provider.GetService(
                                  typeof(IWindowsFormsEditorService));
        if(wfes == null) {
            return value;
        }

        // Create your control as a normal Windows Forms control
        lstValues = new ListBox();
        lstValues.BorderStyle = BorderStyle.None;
        lstValues.Items.Add("Both");
        lstValues.Items.Add("LinesOnly");
        lstValues.Items.Add("FillingOnly");
        lstValues.Items.Add("None");

        // Be sure to select the actual value before editing
        lstValues.SelectedIndex = (int)value;

        // Add MouseUp event handler in order to hide the control when
        // the mouse is released
        lstValues.MouseUp += new MouseEventHandler(lstValues_MouseUp);

        // Show the control in the VS Property page
        wfes.DropDownControl(lstValues);

        // Manage the return value, that MUST 
        // be (although it will be boxed
        // into an object) the same Data Type of 
        // the property: in this case
        // it is correctly casted to HotTrackStyle type
        int val = lstValues.SelectedIndex;

        // Always destroy unused objects
        lstValues.Dispose();
        lstValues = null;

        switch(val) {
            case 0:
                return HotTrackStyle.Both;
            case 1:
                return HotTrackStyle.LinesOnly;
            case 2:
                return HotTrackStyle.FillingOnly;
            case 3:
                return HotTrackStyle.None;
        }

        // Return a default value: NEVER return null!!!
        return HotTrackStyle.Both;
    }

    // Closes the property popup area when the mouse is released
    private void lstValues_MouseUp(object sender, 
             System.Windows.Forms.MouseEventArgs e) {
        if(wfes != null) {
            wfes.CloseDropDown();
        }
    }
}

Conclusions

The DropDownPanel is a simple but (in my opinion ;) powerful control. You can use it for options pages or for whatever you want. Comments and suggestions are always welcome!

Next steps

I have to fix the Expanded property problems (in Design Mode): these are neither nice nor so heavy. I hope I will find a way to include in the Visual Studio property page the list of ManagedControls (simply until now I had no time, but I hope it is possible).

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Italy Italy
Software Development Manager working on IaaS cloud computing. Cloud believer, (former) entrepreneur, F1 addict.

Follow me at dariosolera.it or on Twitter.

Comments and Discussions

 
AnswerRe: Snap-to Position Reordering? Pin
Dario Solera4-Aug-05 21:50
Dario Solera4-Aug-05 21:50 
GeneralSlight Bug Pin
Claude Martel-Olivier4-Aug-05 7:43
Claude Martel-Olivier4-Aug-05 7:43 
GeneralRe: Slight Bug Pin
Dario Solera4-Aug-05 8:19
Dario Solera4-Aug-05 8:19 
GeneralRe: Slight Bug Pin
Claude Martel-Olivier5-Aug-05 5:22
Claude Martel-Olivier5-Aug-05 5:22 
GeneralBugs fixed Pin
Dario Solera4-Aug-05 5:06
Dario Solera4-Aug-05 5:06 
GeneralGreat control Pin
alterego1304-Aug-05 1:44
alterego1304-Aug-05 1:44 
GeneralRe: Great control Pin
Dario Solera4-Aug-05 4:40
Dario Solera4-Aug-05 4:40 
GeneralRe: Great control Pin
Dario Solera4-Aug-05 5:13
Dario Solera4-Aug-05 5:13 
I've just fixed that problem. It was the result of the porting of DropDownPanel from VB to C#. During that I've modified the system that manages the position of the controls.

Sincerely I don't know why I've done that... The 'new' tecnique was very absurd... The old one was so simple and, above all, it works!


GeneralRe: Great control Pin
alterego1304-Aug-05 22:22
alterego1304-Aug-05 22:22 
GeneralGOOD. Pin
sreejith ss nair26-Jul-05 17:59
sreejith ss nair26-Jul-05 17:59 
GeneralRe: GOOD. Pin
Dario Solera26-Jul-05 20:55
Dario Solera26-Jul-05 20:55 
GeneralGreat but... Pin
Carl Mercier26-Jul-05 9:11
Carl Mercier26-Jul-05 9:11 
GeneralRe: Great but... Pin
Dario Solera26-Jul-05 9:44
Dario Solera26-Jul-05 9:44 
GeneralRe: Great but... Pin
gxdata26-Jul-05 16:37
gxdata26-Jul-05 16:37 
GeneralRe: Great but... Pin
Dario Solera26-Jul-05 20:53
Dario Solera26-Jul-05 20:53 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.