Click here to Skip to main content
15,881,757 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

 
QuestionIt Just works ! Pin
Member 1256155918-Nov-18 18:37
Member 1256155918-Nov-18 18:37 
Questionnice post Pin
Tridip Bhattacharjee5-Feb-14 8:21
professionalTridip Bhattacharjee5-Feb-14 8:21 
QuestionBug??? Pin
Mark Watts15-Nov-13 5:01
Mark Watts15-Nov-13 5:01 
Questiondropdownpanel Pin
sagar_prajapati6-Oct-13 20:24
sagar_prajapati6-Oct-13 20:24 
QuestionVB.NET? Pin
Jacques_Vorster1-Jul-13 18:11
Jacques_Vorster1-Jul-13 18:11 
GeneralMy vote of 4 Pin
ryuzaft19-Dec-12 4:49
ryuzaft19-Dec-12 4:49 
Generalusable in VS 2005 c++ project? Pin
Member 79925659-Jun-11 2:07
Member 79925659-Jun-11 2:07 
GeneralOne small remark Pin
Evgeniy Stepanow19-May-10 0:11
Evgeniy Stepanow19-May-10 0:11 
GeneralNice! Pin
Mustafa Ismail Mustafa6-Apr-10 23:58
Mustafa Ismail Mustafa6-Apr-10 23:58 
Generalexpand=False at startup Pin
rrre_e2-Oct-08 20:10
rrre_e2-Oct-08 20:10 
GeneralAdded tab-handling Pin
fwd10-Apr-08 23:56
fwd10-Apr-08 23:56 
GeneralAbout Terms of Use of this code Pin
IgnacioGLez13-Dec-07 7:42
professionalIgnacioGLez13-Dec-07 7:42 
QuestionRe: About Terms of Use of this code Pin
guz421715-Dec-08 21:39
guz421715-Dec-08 21:39 
GeneralAdd it in a Table layout and make its dock = Fill. It start flickering on expanding Pin
Armoghan Asif31-Aug-07 3:39
Armoghan Asif31-Aug-07 3:39 
Generalissue Pin
syed_pccs24-Aug-06 23:04
syed_pccs24-Aug-06 23:04 
GeneralRe: issue Pin
rax4059-Sep-09 22:02
rax4059-Sep-09 22:02 
GeneralNew release in development Pin
Dario Solera25-Apr-06 8:45
Dario Solera25-Apr-06 8:45 
GeneralRe: New release in development Pin
vl950t1-May-06 21:59
vl950t1-May-06 21:59 
GeneralRe: New release in development Pin
Dario Solera2-May-06 1:02
Dario Solera2-May-06 1:02 
GeneralRe: New release in development Pin
Mike0916-Jun-06 15:30
Mike0916-Jun-06 15:30 
GeneralRe: New release in development Pin
Dario Solera16-Jun-06 21:19
Dario Solera16-Jun-06 21:19 
QuestionBug? Pin
Gavin Roberts18-Aug-05 9:34
Gavin Roberts18-Aug-05 9:34 
AnswerRe: Bug? Pin
Dario Solera27-Aug-05 21:25
Dario Solera27-Aug-05 21:25 
GeneralRe: Bug? Pin
jabulino19-Dec-05 21:52
jabulino19-Dec-05 21:52 
GeneralRe: Bug? Pin
Dario Solera20-Dec-05 6:17
Dario Solera20-Dec-05 6:17 

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.