wyDay blog  |  Downloads  |  Buy
LimeLM
wyBuild
Support forum
wyDay blog
wyDay Home

SplitButton control, written in C#

A week ago I posted a short article describing the process of fixing a SplitButton control. The control was based on this control by a former MS employee.

My SplitButton fixes many of the bugs in her implementation, but owes to her stable base.

Comments, suggestions, and bug-fixes are welcome.

Update July 21, 2007: v1.4 is out, which fixes a null exception if the SplitMenu isn't set. In this version, if you don't set the SplitMenu property, the SplitButton will act like a regular button.

Update July 28, 2007: v1.5 is out. This fixes the small bug of the focus rectangle (i.e. the dotted line) being shown in all cases of focus, when it's only supposed to be shown when the button receives focus from the keyboard.

Update February 8, 2008: v1.6 is out. I've added support for image display and both image and text alignment. There are also many small fixes.

Update May 16, 2008: v2.0 is out. The SplitButton now works with 'ContextMenu' controls in addition to the existing support for 'ContextMenuStrip' controls. This was added so you can use the newly released VistaMenu with the Split Button.

More information, the latest changes, and the 'How-to-use' info.

down_16.pngDownload the SplitButton now. It works with all .NET 2.0 and above languages (C#, VB.NET, etc.)

Jul 12, '07permalink

This doesn't exactly fall into the category of "Comments, suggestions, and bug-fixes", but more or less a question. I like the feature of a splitbutton, but I am unable to get it to do anything besides throw down a menu and make as selection (and click it). How do you set up the event handler so that when you click the button (after the selection is made) to read the selection (from the context menu). I've been really frustrated trying to figure this out and I figure your a good enough person to ask, since you've implemented it and everything.

Thank you,

Fare

Jul 12, '07permalink

This doesn't exactly fall into the category of "Comments, suggestions, and bug-fixes", but more or less a question. I like the feature of a splitbutton, but I am unable to get it to do anything besides throw down a menu and make as selection (and click it). How do you set up the event handler so that when you click the button (after the selection is made) to read the selection (from the context menu). I've been really frustrated trying to figure this out and I figure your a good enough person to ask, since you've implemented it and everything.

Thank you,

Fare

Your question, if I understand it correctly, is how to get event handlers for the menu items. If this is your question, you can do it two ways.

1. The easy way

In Visual Studio designer, click the menu you want to add the even to, then double click one of the sub-items. Visual Studio will automatically generate the click method for that sub-item.

2. The more flexible way

You can also handle more than one of the sub-items in the same method:[attachment=0]multimnuclick.png[/attachment]

After you double click that event handler from the properties window, you can use this code to figure out which item was selected (where menuUpload is the name of my sub-menu):

        private void menuUpload_ItemClicked(object sender, ToolStripItemClickedEventArgs e)        {            int clickedIndex = menuUpload.Items.IndexOf(e.ClickedItem);


            //clickedIndex is the index of the click menu Item            //now use clickedIndex to determine you action        }

I hope I've answered your question.

Jul 12, '07permalink

yes and no...

Yes,in a sense because you showed me that I am setting it up wrong.

Your menuupload sub-menu is what your designing, but it appears that I was designing the actual split button class.

I have the designer set up like...

            //             // splitButton            //             this.splitButton.ContextMenuStrip = new System.Windows.Forms.ContextMenuStrip();            this.splitButton.ContextMenuStrip.Items.Add("Item1");            this.splitButton.ContextMenuStrip.Items.Add("Item2");            this.splitButton.ContextMenuStrip.Items.Add("Item3");            this.splitButton.AutoSize = true;            yadda yadda yadda

This is the way that it was set up on the jfo's site...I think

Is there something else I need to declare? I noticed the path for the menuUpload was System.Windows.etc.etc.etc

Thank you again,

Fare

Jul 12, '07permalink

It almost looks like you're directly editing the "FormName.Designer.cs" file. Normally that's not recommended.

What you want to do is double click the the FormName:

[attachment=1]solexplorer.png[/attachment]

Then, in the ToolBox, click the ContextMenuStrip and drag it to the form.

[attachment=0]dragtoform.png[/attachment]

Visual Studio will automatically take care of all the namespaces (like using System.Windows.Forms; //etc.)

Jul 12, '07permalink

lol, wow...

As you can probably tell, I'm new to the IDE scene...This is a long way from c++ in VIM... It almost seems like cheating...

I got it all to work, and I thank you for that. I was forced to go into the designer class source code to manually add the new contextmenu to the splitbutton, is there a way you can do it from the designer window?

Thank you again, and sorry for the inconvenience (I'm sure this wasn't the intent of your original post),

Fare

Jul 12, '07permalink
... is there a way you can do it from the designer window?

Sure, just click the contextMenuStrip you created, and click the "..." button in the Items property:

[attachment=0]edititems.png[/attachment]

From there you can Add, edit, and remove the menu items.

Thank you again, and sorry for the inconvenience (I'm sure this wasn't the intent of your original post)

It's no problem at all. I was glad to help.

Jul 12, '07permalink
Sure, just click the contextMenuStrip you created, and click the "..." button in the Items property:

I was talking more along the lines of adding the context menu to the splitbutton

this.splitButton1.ContextMenuStrip = this.contextMenuStrip1;

I couldn't find that option in the Items field...

Jul 12, '07permalink

Oh, ok. Well, with my fixed version of the SplitButton it's the SplitMenu property you'll need to set:

[attachment=0]sbmenu.png[/attachment]

I hid the ContextMenuStrip property in my SplitButton because it has quirky behavior when you right click the SplitButton in runtime.

Jul 12, '07permalink

ah, the splitmenu field ( I should have known that after going through that code a hundred times...)

thank you again,

Fare

Jul 12, '07permalink

I'm glad I found your post. I was looking for some cool new (free, of course) components to kind of spice up a new internal application. I could be using this to replace quite a few comboboxes.

Personally, I'm a VBer, but I can read much of C#. I know it isn't of any particular consequence, but I have converted the latest version to VB.NET 2.0 for anyone interested.

Thanks,

Aug 28, '07permalink

I'm glad I found your post. I was looking for some cool new (free, of course) components to kind of spice up a new internal application. I could be using this to replace quite a few comboboxes.

Personally, I'm a VBer, but I can read much of C#. I know it isn't of any particular consequence, but I have converted the latest version to VB.NET 2.0 for anyone interested.

Thanks,

Sure, e-mail it to me and I'll add it to the first post.

-Wyatt

Aug 31, '07permalink
Aaron

Hi,

The FlatStyle "Flat" does not work for this SplitButton. Do you have an idea how i can accomplish that?

Thanks,Aaron

Sep 19, '07permalink

Hi,

The FlatStyle "Flat" does not work for this SplitButton. Do you have an idea how i can accomplish that?

Thanks,Aaron

The flat style is not a theme-inherited style - that is, it doesn't look like the themed buttons in Vista & XP. This means it will not change from one version of Windows to another. So, to accomplish the 'Flat' look is actually a rather simple task.

Just open up the project in Visual Studio (or whichever development environment you use) and edit the 'OnPaint(PaintEventArgs pevent)' method in the SplitButton.cs file. Then it's just a matter of replacing the existing code with a switch statement for each of the button's states:

switch(State){   case PushButtonState.Default:      //TODO: insert painting code   break;   case PushButtonState.Disabled:      //TODO: insert painting code   break;   case PushButtonState.Hot:      //TODO: insert painting code   break;   case PushButtonState.Normal:      //TODO: insert painting code   break;   case PushButtonState.Pressed:      //TODO: insert painting code   break;}

Then where each comment is, replace it with drawing code that draws the rectangle background and the 1px/2px black frame for that particular button state.

The reason I didn't (and won't) implement the alternate FlatStyles is because they look amateur.

However, if you're developing for a client with those particular stylistic needs, then who am I to impose my own standards?

Sep 20, '07permalink
JoeRip

What I'd like is a simple dropdown that allows me to have a different width for the control than for the dropdown list. Since I can't find a forms-friendly control that does that (ie, not a toolstrip bound control), I use your split button, even though I don't need the split itself.

So, given this - is there any way I can get the drop down list to drop if the user clicks anywhere in the button, as opposed to just the right side? I want it to function exactly as if they had right clicked, essentially.

Oct 18, '07permalink

What I'd like is a simple dropdown that allows me to have a different width for the control than for the dropdown list. Since I can't find a forms-friendly control that does that (ie, not a toolstrip bound control), I use your split button, even though I don't need the split itself.

So, given this - is there any way I can get the drop down list to drop if the user clicks anywhere in the button, as opposed to just the right side? I want it to function exactly as if they had right clicked, essentially.

Well, you'll have to change a few methods. For example, the OnKeyDown method will have to be changed to

        protected override void OnKeyDown(KeyEventArgs kevent)        {            if (showSplit)            {                if (kevent.KeyCode.Equals(Keys.Down) || kevent.KeyCode.Equals(Keys.Space))                {                    ShowContextMenuStrip();                }            }


            base.OnKeyDown(kevent);        }

and make similar changes to OnKeyUp. Though, the main thing you'll need to change is to OnMouseDown:

        protected override void OnMouseDown(MouseEventArgs e)        {            if (!showSplit)            {                base.OnMouseDown(e);                return;            }


            //always show the context menu, no matter where clicked            ShowContextMenuStrip();        }

And obviously you'll want to change the drawing code to never draw the "split" line. There will be other subtleties that you'll need to work out to get it working perfectly, but that should get you started.

If you need more help, feel free to ask.

Oct 18, '07permalink
mc_ginley

Hey you, just wanted to say a big thank you. Your control is EXACTLY what i was looking for!!! Really good work. Thanks a lot.regardsjOe

Dec 6, '07permalink
Guy

First thing's first: this is so far the best SplitButton implementation I've come across. Thanks!

Now, on to the whining! 🙂

If I set an image on the SplitButton, and have nothing set for the "SplitMenu" property, then the image is drawn on the button and everything is right in the world. But as soon as I set the SplitMenu property, the button is redrawn without the image. This happens on all the "TextImageRelation" enums I've tried. I assume it's gotta be happening in the OnPaint override, but I'm having trouble tracking it down. Any ideas good sir?

Thanks!

Feb 7, '08permalink
First thing's first: this is so far the best SplitButton implementation I've come across. Thanks!

I'm glad this control is so popular.

Now, on to the whining! 🙂

If I set an image on the SplitButton, and have nothing set for the "SplitMenu" property, then the image is drawn on the button and everything is right in the world. But as soon as I set the SplitMenu property, the button is redrawn without the image.

That's because I didn't implement the image painting in the code. I'll have a fixed version listed on the first post (and a blog post) tomorrow night.

Edit, Feb. 8, 2008: The new version (1.6) has image support. Tell me if you find any bugs.

Feb 7, '08permalink
Guy

Thanks Wyatt! 🙂

Feb 12, '08permalink
dlarkin77

Hi,

I want the SplitButton to have a blue background so I set splitButton1.BackColor = Color.BlueThis has no effect that I can see, the button still has its default color.Is there something else that I need to do to be able to change the backcolor?

Thanks,

dlarkin77

Jul 15, '08permalink
I want the SplitButton to have a blue background so I set splitButton1.BackColor = Color.BlueThis has no effect that I can see, the button still has its default color.Is there something else that I need to do to be able to change the backcolor?

I didn't implement BackColor, so setting the property has no effect. This is similar to another question. All you need to do is open up the SplitButton project and edit the OnPaint method.

It might take a couple of hours to get it the way you like it, But you can ask for help if you have any trouble understanding the code.

I have a few parting questions: Why do you want to override the default theme for XP / Vista? Do your users really want that? Why not just disable the theme on your computer, and set the control color to blue? That way you'll have uniformity across all your apps.

Jul 16, '08permalink
m0by

I have been using your button, and I would like to hide the "button" part of the splitbutton so when it loses focus, only shows the dropdown arrow, and If the user goes and click the arrow, the button shows again. Any idea?Thanks.

Dec 3, '08permalink

m0by, I'm not quite sure what you mean. Are you asking for a combo-box? If not, what you're asking for sounds confusing and non-intuitive.

Maybe I'm misunderstanding you. Perhaps you could post a picture of what you're looking for.

Dec 3, '08permalink
james

How do i use this with Visual Studio 2005.I added referance from bin folder & then choose item in toolbox & check the split button checkbox then nothing happens.Am i doing something wrong 😳

Jul 8, '10permalink

You need to add it to your form. Click the Split Button in the toolbox, and drag it to your form.

Jul 8, '10permalink
BrewmasterOfNone

Has anyone else experienced SplitButton appearance changes between XP and Windows 7?

I had a form with a few SplitButtons that I created in WinXP, but when I got a new computer with Windows 7, the SplitButtons appeared to be a slightly different size and a slightly different location. I assumed that the form had gotten mangled somehow and fixed they layout. However, when I load the form on a WinXP machine, the SplitButtons are a slightly different size again. All of the standard .NET Buttons are the correct size, though.

Has anyone else seen this? Is there a fix for it that I missed?

Thank you for help,

Andy

Jul 30, '10permalink

Hey Andy,

Font sizes on Windows XP vs. Windows 7 are different (see: Windows Vista & 7 Font, Segoe UI, in C# and VB.NET).

Do you have the AutoScaleMode property of your form set? If so, this will move & resize elements on your form.

Jul 30, '10permalink
BrewmasterOfNone

What should AutoScaleMode be set to? I haven't modified it, and it is set to Font.

I don't know if this is really the issue though. You see, all of the split buttons are a different size than the non split buttons. If my entire GUI was mangled, I could understand it being a property like this, but only the split buttons appear to be affected.

However, if I am the only one seeing this, then it must be some property or setting that is causing the problem. If anyone knows what settings might be the problem, I would be much obliged.

Thanks,

Andy

Aug 2, '10permalink
BrewmasterOfNone

My mistake. As it turns out, it isn't a Windows XP / Windows 7 issue, but a large font, small font issue. I designed my form with large fonts, and when I compiled it and move it to a computer that didn't have large fonts turned on, the button was too big.

I think that the problem is in CalculateButtonAutoSize(); there are a couple of places where constants are added to the height and width, and I think those are causing issue when switching between regular fonts and large fonts. There aren't any comments beyond "Pad the text size" and "Pad the result", so I'm not sure where those numbers are coming from. I think that those numbers need to be replaced by values from the operating system, but I don't know which values to get. Does anyone have any suggestions?

Thanks,

Andy

Sep 3, '10permalink

They're arbitrary values. They only add a few pixels to the height and width. I can't reproduce the issues you're having with font sizes.

Sep 3, '10permalink
fred

Hello

Thanks for your nice controlbut there is a color issue.

the ForeColor property is not working.

cheers

fred

Nov 25, '10permalink

Ok, I've fixed it. Redownload the SplitButton.

Thanks for spotting this.

Nov 26, '10permalink
Pen

Pretty nice control but there is a problem with the backcolor property: if you give the control a custom background color and use a Classic Windows desktop background it works perfectly but if you change the desktop to Aero the custom background color change to some standard color.

Jun 21, '11permalink

When we wrote the SplitButton the custom background color property was a second class citizen. By default the splitbutton uses Windows default styling (i.e. the correct way). If you want to use custom colors you can edit the source code. Specifically look at the drawing code.

Jun 22, '11permalink

I can't find anyway the tutorial how to use your SplitButton component. Please help.

Aug 11, '11permalink
  1. Add the button to your form.
  2. Use the SplitMenu or SplitMenuStrip properties.
Aug 14, '11permalink
cryo75

Hi,

Download the splitbutton control. One problem with it is that the control doesn't handle flat style, flat style appearance and background color at all.

Is there a way to get it to work?

May 21, '12permalink

The SplitButton doesn't support the flat style (as per design). You can always add it. It's failry simple to do.

May 21, '12permalink
Allen

Hi,thanks for the SplitButton - it works great and looks good. Unfortunately with one little exception 🙂The text of the button is placed exactly one pixel lower than on normal WinForm buttons.Wouldn't notice this if there wasn't a normal button directly besides my splitbutton.Do you have an idea how to fix this?

I'm developing with .NET 3.5 and experience this problem with Win XP. Haven't testedit with Win 7 yet.

Thanks & cheers

Feb 11, '13permalink

Just edit the paint method.

Feb 13, '13permalink