Click here to Skip to main content
Click here to Skip to main content

Drop and Forget Dialog Buttons

, 7 Sep 2006
Rate this:
Please Sign up or sign in to vote.
OK, Cancel, Yes and No buttons that set their own Text, Name, DialogResult and Accept/Cancel status

Sample Image - DropAndForgetButtons.gif

Introduction

If you are anything like me, you've been spoiled by Intellisense and want everything to go as quickly as possible when coding. So, when I make dialog boxes (as I am sure you do too), why should I have to set 4-5 things every time I want an OK or Cancel button on a form?

Whenever I drop a button on a form, I inevitably forget one of the following 4 steps (except #3, that one's kind of obvious).

  1. Set the Name to something resembling "OK" or "Cancel" so that it's not just called "button1".
  2. Set the DialogResult to DialogResult.OK or DialogResult.Cancel.
  3. Set the Text to "OK" or "Cancel".
  4. Set the Form's AcceptButton/CancelButton to your new OK/Cancel button (or pressing Enter/ESC won't press OK/Cancel).

I can't tell you how many times I have hit OK or Cancel and then wondered why it didn't do anything. Or the right thing. Or only half of the right thing--the half in the OK button's event handler but not the half in the form's if (dialog.ShowDialog() == DialogResult.OK) block. It seems like when it comes to OK and Cancel buttons, they should "just work".

Out of completeness, I have added "Yes" and "No" buttons as well, which allows us to do Yes/No and Yes/No/Cancel scenarios as well. I'll leave the useless Abort/Retry/Ignore scenario as a reader exercise.

Background

It's a (fairly) simple matter to overload these controls to get very close to what we want. This article is nothing groundbreaking, just a nice time-saver. If you don't have any experience in making custom controls, this will be a nice primer for you.

Using the code

If you just want to use the buttons, right-click on your Toolbox and select Choose Items... from the menu. Then just hit Browse and go to where you saved the DLL. Hit OK.

Four new buttons will appear in your Toolbox. They all have the [ab] graphic like the built-in buttons, but they are called OK, Cancel, Yes and No.

Just drop the OK button on a Form and you will see that the button is named "ok1", has the text "OK", has a DialogResult of OK, and has the bold outline which signifies that this is the AcceptButton. If your dialog only has an OK button, you are done.

If you have a Cancel button, just drop one of those. You will see it's named "cancel1" and has the text "Cancel" and is , in fact, a working Cancel button (even if you hit Esc).

You can do the same with Yes/No buttons as well. For a Yes/No/Cancel scenario, just be sure you drop the Cancel button on the form after the No button, so that Esc behaves as expected.

Points of Interest

How does this code work? Well, it's fairly simple, but a little more difficult than I thought at first glance.

First, we need to inherit from the Button class. Simple enough, but to get the correct Bitmap in the Toolbox, we have to use the Attribute [ToolboxBitmap(typeof(Button))]. We wanted something that is immediately identifiable as an OK button, so I just called the class OK. This way, it is labeled "OK" in the ToolBox, telling us immediately what this is for.

    [ToolboxBitmap(typeof(Button))]
    public class OK : Button

From this, Visual Studio will make controls named ok1, ok2, etc. (although I don't know why you would ever need 2 OK buttons). I really wanted it to just be called OK, but I will settle for ok1, since I have a feeling it will be very difficult to convince Visual Studio to cooperate on this point.

OK, it was simple enough to satisfy requirement #1. A button in a dialog named "ok1" is obviously the OK button. Nobody reading the code should be confused when they see a method called ok1_Click. Next we need to set the DialogResult, which can be easily done in the constructor.

        public OK()
        {
            this.DialogResult = DialogResult.OK;
        }

There, #2 is easily solved as well. Changing the text to read "OK" when you drop it was not so simple. Because at some point during the design process (after your control is created and shown), Visual Studio goes into it's default text-setting mode of setting the Text to the same as the Name. I wasn't exactly sure of the best way of handling this, so I just did something that seemed easy enough.

I attached a handler to the TextChanged event and then see if the Text is the same as the Name. If it is, I change it to "OK". This should make it "OK" when dropped but still allow you the freedom of changing it to "Submit" or "Save" or "Exit" later if somebody so desires ("somebody" being a company-wide committee that doesn't understand Windows CUA guidelines, but that's a story for another day--and yes, they acutally had us rename all our OK buttons to "Exit", even when it said "Exit" and "Cancel", which would be considered by most to be the same thing--but I digress).

        public OK()
        {
            this.DialogResult = DialogResult.OK;
            this.TextChanged += OK_TextChanged;
        }

        private void OK_TextChanged(object sender, EventArgs e)
        {
            if (this.Text == this.Name)
                this.Text = "OK";
        }

OK, #3 is solved. Now, the button will immediately change it's own Text to "OK" when Visual Studio goes through it's renaming operation. It's fun to watch it drop on there and always be labeled "OK". I feel like I'm cheating the system somehow.

Setting the form's AcceptButton was the most difficult part of all. The problem is, the OK could be dropped on a Panel or any other container.

I figured that the method I used to set the Text would be a good one here as well. Specifically, when the OK is dropped on a Form (or anywhere else), it's Parent property would change at that moment. So, I just travel up the generational tree parent to grandparent to great-grandparent, etc., until I find a Form or a null. If I find a Form, I set it's AcceptButton property to myself (this).

        public OK()
        {
            this.DialogResult = DialogResult.OK;
            this.TextChanged += OK_TextChanged;
            this.ParentChanged += OK_ParentChanged;
        }

        private void OK_ParentChanged(object sender, EventArgs e)
        {
            Control parent = this.Parent;

            while (!(Parent is Form) && !(parent == null))
            {
                parent = parent.Parent;
            }

            if (parent is Form)
            {
                Form f = (Form)parent;
                f.AcceptButton = this;
            }
        }

The design of the Cancel, Yes and No buttons are extremely similar, with the CancelButton property being set instead for the Cancel and No buttons. I probably could have used some inheritance, but the code is short enough that I didn't bother. I don't expect to make that many changes to it anyway.

Again, it is important to remember if you are making a custom Yes/No/Cancel dialog that you must drop the buttons in that order if you want the Cancel button to, in fact, be the form's CancelButton.

History

2006-08-31 Uploaded to the CodeProject.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

PRMan!!!
Web Developer
United States United States
Paul Reid is the CEO (and still part-time programmer) of Product4Me Corporation, a web site company devoted to helping consumers get the individualized best fit for home theater (and other) products.

Comments and Discussions

 
GeneralOriginally :) Pinmembersotona24-Feb-07 8:46 
GeneralInheritance PinmemberLaurent Muller30-Oct-06 3:23 
GeneralFiles missing Pinmemberdave.kelly7-Sep-06 21:30 
QuestionWhat about inheritence? PinmemberPaul Brower7-Sep-06 7:43 
Generalquick suggestion PinmemberJockerSoft6-Sep-06 4:35 
GeneralRe: quick suggestion PinmemberPRMan!!!7-Sep-06 6:13 

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

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

| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 7 Sep 2006
Article Copyright 2006 by PRMan!!!
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid