Click here to Skip to main content
6,595,444 members and growing! (21,872 online)
Email Password   helpLost your password?
Desktop Development » Button Controls » General     Intermediate License: The Code Project Open License (CPOL)

A Managed C++ Button Control

By CodeWizard1951

This is an example custom button control, written entirely in Managed C++.
C++/CLI, .NET (.NET 2.0), WinForms, Dev
Posted:11 Apr 2008
Updated:20 Apr 2008
Views:24,489
Bookmarked:21 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
11 votes for this article.
Popularity: 4.35 Rating: 4.18 out of 5
2 votes, 18.2%
1

2

3
3 votes, 27.3%
4
6 votes, 54.5%
5

mehButton

If you like this article, please vote for it. If you don't like this article, please vote, and please tell me why you don't like it.

Introduction

I started this project to understand how one develops a managed custom control that is similar in quality to the standard .NET Button control. Like most .NET beginners, I started out inheriting from the UserControl class, but quickly learned there are significant limitations to some of the concepts I wanted to implement.

After a considerable number of searches of Google and MSDN documents, I settled on developing a button control that inherits from ButtonBase and IButtonControl. One of the problems with inheriting from ButtonBase is that the class is abstract. This means the button control cannot be obtained directly in the designer. However, it can be added to the toolbox, and it works perfectly well in the form designer.

The control is built for flexibility. It allows for either rounded corners or flat square controls. In addition, you can specify which corners are rounded and which are square. You may also change the radius of the corners. I made many of the colors configurable. I also included the ability to draw color gradients for both hover and normal colors. I implemented most of the events that a standard .NET button control can respond to. By implementing the IButtonControl interface, several standard button behaviors are also exposed.

Background

There are a lot of .NET custom controls uploaded to CodeProject. Why do we need another one? The answer is partly because I am a C++ programmer. I wanted to see what it would take to transfer my WTL and ATL skills to .NET. I wanted to understand the difference between architecting a control for use with WTL and a control for use in VB.NET or C#. I make extensive use of attributes for describing properties and assigning default values. I also added XML documentation tags so that Intellisense would be meaningful when using the control in your form.

I modeled this control based on the work of WiB and Alan Zhao. Both of their articles provided a great deal of inspiration and education.

Compiling and using the source

Download and unzip the demonstration project. Please make sure to preserve the directory structure of the source files.

When you first load the solution, you may see a number of messages regarding a missing reference. This is because the assembly has not been built on your machine. (I didn't include any binary files in the source distribution, hence the missing references.) Simply select release or debug mode, and and recompile. The assembly will be built, and all references will be validated. You can add the control to your toolbox at this point, by dragging the assembly to the toolbox surface, or selecting "Add Item..." from the context menu and navigating to <root dir>\mehControls\release and selecting mehButton.dll.

Using the component

After you've added the control to your toolbox, you can drag it to any form. I've implemented a designer component so all properties show up correctly in the "Properties" view. You'll notice that I've removed some of the most difficult to implement properties in the PostFilterProperties method of the designer. Other properties, such as the "Flat" properties, are redundant. Programming the mehControl is fairly standard. The following code illustrates how the form designer wizard initializes the control in a C# project:

// 
// mehButton1
// 
this.mehButton1.BackColor = System.Drawing.SystemColors.Control;
this.mehButton1.ButtonStyle = mehControls.mehButton.ButtonStyles.Rectangle;
this.mehButton1.CurveMode = mehControls.mehButton.CornerCurveStyle.None;
this.mehButton1.DialogResult = System.Windows.Forms.DialogResult.None;
this.mehButton1.GradientStyle = mehControls.mehButton.GradientStyles.None;
this.mehButton1.HoverBorderColor = System.Drawing.SystemColors.ControlDark;
this.mehButton1.HoverColorA = System.Drawing.SystemColors.ButtonFace;
this.mehButton1.HoverColorB = System.Drawing.SystemColors.ButtonHighlight;
this.mehButton1.Image = null;
this.mehButton1.Location = new System.Drawing.Point(12, 122);
this.mehButton1.Name = "mehButton1";
this.mehButton1.NormalBorderColor = System.Drawing.SystemColors.WindowFrame;
this.mehButton1.NormalColorA = System.Drawing.SystemColors.ButtonHighlight;
this.mehButton1.NormalColorB = System.Drawing.SystemColors.ButtonFace;
this.mehButton1.Radius = 0;
this.mehButton1.Size = new System.Drawing.Size(127, 38);
this.mehButton1.SmoothingQuality = mehControls.mehButton.SmoothingQualities.AntiAlias;
this.mehButton1.TabIndex = 4;
this.mehButton1.Text = "m&ehButton Flat";
this.mehButton1.UseVisualStyleBackColor = false;
this.mehButton1.MouseLeave += new System.EventHandler(this.mehButton1_MouseLeave);

...

// The control's events are implmented in a standard fashion.
// The C# design wizard is able to auto-fill the events
// properly from the "Properties" sheet.
private void mehButton1_MouseLeave(object sender, EventArgs e)
{
    this.lblEventText.Text = "Mouse has left mehButton1";
}

Implementing a designer

When you develop a custom visual control for .NET, you will want to implement a designer. The designer may be simple (as the one I've implemented), or as complex as you want. The following code illustrates the definition of a minimal designer:

namespace mehControls
{
    ref class mehButtonDesigner : 
        public System::Windows::Forms::Design::ControlDesigner
    {
    public:
        mehButtonDesigner(void)
        {
        };

        ~mehButtonDesigner(void)
        {
        };

    protected:
        virtual void PostFilterProperties(IDictionary ^) override;
        virtual void OnPaintAdornments(PaintEventArgs ^e) override;

    };
}

Attributing properties

You'll want to properly attribute your properties. This will allow you to control where the property is grouped on the Properties display and the default value of the property.

[DefaultValue(System::Drawing::Color::typeid, "System::Drawing::SystemColors::Control")]
[Description("Background Color for button"), Category("Appearance")]
// This is how you split a property definition
// This is useful if the property has many lines of
// code or you do not want to expose the
// inner workings of your code in the header.
property virtual Color BackColor
{
    // The property function prototypes are specified here
    Color get() override;
    void set(Color value) override;
}

Handling the OnPaint event for the control

As with Native mode programming, most of the work is handled in the OnPaint (or OnPaintBackground) event of the control. In the case of the control, DrawRoundRectangle does most of the heavy-lifting. In order to implement rounded corners, I make heavy use of gp->AddArc(arc, angle1, angle2) where GraphicsPath ^gp = gcnew GraphicsPath().

Summary

The button implements many of the properties of a .NET 2.0 button. It was a lot of fun figuring out how to add the painting of the "hot" border. I had to use my tenth grade geometry to calculate the correct center of the arcs when drawing the rounded corners. This is the basic diagram I used for developing the rounder corner algorithm:

RoundedCorners1.JPG

I was also able to implement gradient drawing of the background, which allows for some very cool effects when there is a mouse over or click event for the button. The following enum illustrates the gradient types that are implemented:

enum class GradientStyles
{
    None,
    Horizontal,
    Vertical,
    ForwardDiagonal,
    BackwardDiagonal
};

The control is far from complete. I've added attributes for all of the properties. However, there is considerable work to be done with the XML documentation tags. I also have not implemented themes in this version of the control.

Things you should know

There are a few items that I found to be a lot easier in managed and mixed mode C++. First of all, you do not have to worry about importing API calls. You include any header files from the Platform SDK, and Visual C++ will take care of the call for you. This is a huge help, and can save a lot of time when working with API calls. Moving back and forth between wchar_t and String is a lot simpler in a managed C++ project.

VS 2005 does not have the nice wizards for C++ that C# has. When you select a Windows Control project, that is what you get. No designer. No bells and whistles. You'll have to consult the documentation often in the early going. However, I found that I learned a lot more about my environment doing it the hard way. Before I knew it, I wasn't consulting the documentation very often.

Adding references to projects is different between C++ and C#. You use the project properties page to add references. Just navigate to Common Properties, and click the Add New Reference... button.

Specifying namespaces and resolving referenced names: in Managed C++, you'll use "::" instead of "." when resolving names.

// You'll use this syntax in managed C++
using namespace System::Windows::Forms;
// Instead of the C# syntax
//using System.Windows.Forms;

History

  • Version 1.0 - April 11, 2008 - Initial release of the control.

License

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

About the Author

CodeWizard1951


Member
I am a C++ coder. I am also proficient with Oracle PL/SQL. A lot of folks dislike Oracle, but I find Oracle is a significant revenue enhancer. Customers pay for first rate Oracle programming skills.

I have extensive experience with COM+, COM, ATL, WTL and installation package development. I've developed several packages in C#, but I prefer managed/native C++. I've been coding for nearly thirty plus years, getting my start with atomic and molecular orbital calculations in FORTRAN. I've been working with C or C++ since the days of QuickC, Desmet C, Datalight C and MSC 5.1.

One of my pet peeves in life is a programmer's lack of attention to the details of error handling. Most example code I see on the internet lacks depth. No use of Window's Event Logging and a lack of understanding as to how to handle exceptions. If folks actually think about how to properly debug and test, there would be fewer "slop" articles and a lot higher quality.

Including instrumentation in your software to allow proper diagnosis of failures is far more important to a user than the latest Gee-Whiz-Bang visual effects. Graphical gotta-haves fade like the lettuce in a refrigerator, but solid programs just keep on running, no matter what environment they are placed in.

My Web Site, Blog & Wiki
Occupation: Software Developer (Senior)
Company: Southwest Research Institute
Location: United States United States

Other popular Button Controls articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 9 of 9 (Total in Forum: 9) (Refresh)FirstPrevNext
Questionchecking if event is subsribed or not? PinmemberADumbProgrammer6:22 19 Aug '08  
AnswerRe: checking if event is subsribed or not? PinmemberCodeWizard19516:52 19 Aug '08  
GeneralHave u seen WPF ?? Pinmemberyassir hannoun14:35 20 Apr '08  
GeneralRe: Have u seen WPF ?? PinmemberCodeWizard195115:28 20 Apr '08  
GeneralRe: Have u seen WPF ?? Pinmemberyassir hannoun3:05 21 Apr '08  
GeneralRe: Have u seen WPF ?? PinmemberCodeWizard19513:41 21 Apr '08  
GeneralRe: Have u seen WPF ?? Pinmemberyassir hannoun10:20 21 Apr '08  
GeneralIntegrating Themes into mehButton PinmemberCodeWizard19517:35 20 Apr '08  
GeneralIs it a crummy article? PinmemberCodeWizard19515:47 17 Apr '08  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 20 Apr 2008
Editor: Smitha Vijayan
Copyright 2008 by CodeWizard1951
Everything else Copyright © CodeProject, 1999-2009
Web21 | Advertise on the Code Project