• 0

[C#] Enable/Disable button when they can/cant be used


Question

I am wondering what the best method for enabling/disabling form controls such as buttons when they can/cant be used.

Eg, i have 2 text boxes and a button, both text boxes are required to have text in them before the button can be clicked.

Now i could catch the text changed event on both text boxes and then if both have text in them enable the button.

But this seems like alot of code/mess just to accomplish this especially if there are lots, i currently have 20+ buttons which need to be enabled/disabled based on multiple sources.

Is there an easier way to do this? or a neater solution?

11 answers to this question

Recommended Posts

  • 0

That's how it is. Perhaps you need to rethink your design to make it more generic so you don't have to write the same code over and over again? One example would be a container class that contains a list of text boxes and a button. When you add a text box to it, it would automatically add the relevant events and do all the processing internally so that only the button click would be an external event that you would have to handle. You could even develop a user control for it.

  • 0
  hdood said:
That's how it is. Perhaps you need to rethink your design to make it more generic so you don't have to write the same code over and over again? One example would be a container class that contains a list of text boxes and a button. When you add a text box to it, it would automatically add the relevant events and do all the processing internally so that only the button click would be an external event that you would have to handle. You could even develop a user control for it.

Or you could put the button inside a group box and hide the group box until the conditions are met. At least I believe that would work?? Could you elaborate on your described method? That would be helpful to me as well. :) Do you mean to create a class that inherits from the button class and then add the required functionality in that class? If so, good idea because the button class contains all of the code required to draw a button and handle the events. To use your class's functionality you would declare a new button instance with the name of that class instead of just new Button(); (e.g. new SpecialButton() ) . :)

  • 0

If you are using ASP .Net, you can use a Required Field Validator.

If you are using Win Forms then yes, events are the best/easiest way. One thing you can do to reduce your code base is create a single event for all the textboxes. So for instance, when you select the textbox and then view the events in the properties grid, there is the TextChanged event. Just manually put in something like genericTextBox_TextChanged event. Then create an event like such

protected void genericTextBox_TextChanged(sender object, EventArgs events)

{

Textbox textbox = (TextBox) sender;

if(textbox != null)

{

//Logic goes here. For example:

if(String.IsNullOrEmpty(textBox.Text)

{

button1.Enabled = false;

}

}

}

This may not be helpful, but I would want to know more in order to help give more details.

  • 0
  pwhygle said:
If you are using ASP .Net, you can use a Required Field Validator.

If you are using Win Forms then yes, events are the best/easiest way. One thing you can do to reduce your code base is create a single event for all the textboxes. So for instance, when you select the textbox and then view the events in the properties grid, there is the TextChanged event. Just manually put in something like genericTextBox_TextChanged event. Then create an event like such

protected void genericTextBox_TextChanged(sender object, EventArgs events)

{

Textbox textbox = (TextBox) sender;

if(textbox != null)

{

//Logic goes here. For example:

if(String.IsNullOrEmpty(textBox.Text)

{

button1.Enabled = false;

}

}

}

This may not be helpful, but I would want to know more in order to help give more details.

ah I see, so really not a new class, but just set of code in the event. That makes sense. The only thing is that it won't reduce the amount of code/time required lol. If you write it in code, you would have to say something like txt1.TextChanged += ....... txt2.TextChanged += ........ txt3.TextChanged += ...... :) I wonder if there is a trick to narrow it down. For instance,

foreach(Control c in Controls)
{
  ..............
 }

Edited by winlonghorn
  • 0
  winlonghorn said:
Or you could put the button inside a group box and hide the group box until the conditions are met. At least I believe that would work?? Could you elaborate on your described method? That would be helpful to me as well. :) Do you mean to create a class that inherits from the button class and then add the required functionality in that class? If so, good idea because the button class contains all of the code required to draw a button and handle the events. To use your class's functionality you would declare a new button instance with the name of that class instead of just new Button(); (e.g. new SpecialButton() ) . :)

You could put the buttons in a group box/panel if you wanted to enable/disable all the buttons at once, and it was practical to group them layout-wise. I don't think that's what he wants though. It sounds more like he has a table where each row contains X number of text boxes and a button that is tied to that one row (maybe a submit or clear or whatever button.)

What I was describing is basically a simple class that contains a (or multiple) button controls and a list of textbox controls. It would also include a generic event handler like the one pwhygle describes that would be added to each textbox when your method that adds text boxes is called. The handler would enable/disable any buttons that have also been added to the class when all the textboxes contain text.

You would then make an instance of that class for each row of text boxes that you have on your form, and then add those text boxes and the corresponding button(s) to the class instance.

Obviously there are many other ways to implement the same concept, ranging from a user control that implements a table like that, to a "DependentButton" class derived from Button that would house the functionality described (ie a list of textboxes and a generic event handler that disabled/enabled the button itself).

  • 0
  hdood said:
You could put the buttons in a group box/panel if you wanted to enable/disable all the buttons at once, and it was practical to group them layout-wise. I don't think that's what he wants though. It sounds more like he has a table where each row contains X number of text boxes and a button that is tied to that one row (maybe a submit or clear or whatever button.)

What I was describing is basically a simple class that contains a (or multiple) button controls and a list of textbox controls. It would also include a generic event handler like the one pwhygle describes that would be added to each textbox when your method that adds text boxes is called. The handler would enable/disable any buttons that have also been added to the class when all the textboxes contain text.

You would then make an instance of that class for each row of text boxes that you have on your form, and then add those text boxes and the corresponding button(s) to the class instance.

Obviously there are many other ways to implement the same concept, ranging from a user control that implements a table like that, to a "DependentButton" class derived from Button that would house the functionality described (ie a list of textboxes and a generic event handler that disabled/enabled the button itself).

Ah ok! :) When you say a list of textboxes, you mean "List<TextBox> TextBoxes = new List<TextBox>();" correct? Thank you.

EDIT: Here is a Class and a set of Methods that I came up with to accomplish the task:

Public class MyControls
{
	 //List of textboxes
	 List&lt;TextBox&gt; TextBoxes;

	 //Button
	 Button MyButton;

	 //Private Counter Variable (used to determine if the button should be enabled).
	 Private int count;

	 //Default Constructor
	 Public MyControls()
	 {
		 //Initialize all controls
		 TextBoxes = new List&lt;TextBox&gt;();
		 MyButton = new Button();
	  }

	 //Count Property
	 Public int Count
	 {
		 get{ return count; }
		 set { count = value; }
	 }

	 //Method to Validate TextBoxes
	 Public void ValidateTextBoxes()
	 {
		 //For each TextBox, Determine if it is empty
		 foreach(TextBox t in TextBoxes)
		 {
			 if(!t.empty)
			 {
				 Count++;
			 }
		  }

		  //Determine whether or not to enable the button
		  if(Count == TextBoxes.Count)
		  {
			  MyButton.Enabled = true;
		  }
		  else
		  {
			  MyButton.Enabled = false;
		  }

		   //Reset Counter
		   Count = 0;
	   }

	   //Method to Show the TextBoxes
	   Public void ShowTextBoxes()
	   {
		   foreach(TextBox t in TextBoxes)
		   {
			   t.Show();
			}
		}

		//Method to Show the Button
		Public void ShowButton()
		{
			//TODO: Add Position Code Here!

			//Show Button
			MyButton.Show();
		}
}

Edited by winlonghorn
  • 0

Ok, here is an edited version of that class (using an event handler):

Public class MyControls
{
	 //List of textboxes
	 List&lt;TextBox&gt; TextBoxes;

	 //Button
	 Button MyButton;

	 //Private Counter Variable (used to determine if the button should be enabled).
	 Private int count;

	 //Default Constructor
	 Public MyControls()
	 {
		 //Initialize all controls
		 TextBoxes = new List&lt;TextBox&gt;();
		 MyButton = new Button();

								//For each TextBox, setup its TextChanged Event to call OnTextChanged
								foreach(TextBox t in TextBoxes)
								{
									t.TextChanged += new EventHandler(OnTextChanged);
								} 
	  }

	 //Count Property
	 Public int Count
	 {
		 get{ return count; }
		 set { count = value; }
	 }

	 //EventHandler Method
	 Public void OnTextChanged(Object sender, EventArgs e)
	 {
		 //For each TextBox, Determine if it is empty
		 foreach(TextBox t in TextBoxes)
		 {
			 if(!t.empty)
			 {
				 Count++;
			 }
		  }

		  //Determine whether or not to enable the button
		  if(Count == TextBoxes.Count)
		  {
			  MyButton.Enabled = true;
		  }
		  else
		  {
			  MyButton.Enabled = false;
		  }

		   //Reset Counter
		   Count = 0;
	   }

	   //Method to Show the TextBoxes
	   Public void ShowTextBoxes()
	   {
		   foreach(TextBox t in TextBoxes)
		   {
			   t.Show();
			}
		}

		//Method to Show the Button
		Public void ShowButton()
		{
			//TODO: Add Position Code Here!

			//Show Button
			MyButton.Show();
		}
}

  • 0

Here's my proposed alternative. Add this class to your project and compile. You will then have a new control in your Toolbox.

It extends the standard TextBox control with an extra property called ButtonToValidate. This property will present you with a nice list of all buttons on your form, in your Properties window.

Quick Usage:

  1. Add buttons with Enabled = False
  2. Add some ValidatingTextBox controls, and set their ButtonToValidate property to any of the buttons on your form.
  3. Win!

public class ValidatingTextBox : TextBox
	{
		private Button _Btn;

		// Property
		public Button ButtonToValidate
		{
			get { return _Btn; }
			set { _Btn = value; }
		}

		// Constructor
		public ValidatingTextBox():base()
		{
			this.TextChanged += new EventHandler(HandleTextChanged);
		}

		// Event Handler
		void HandleTextChanged(object sender, EventArgs e)
		{
			// If no associated button, ignore
			if (ButtonToValidate == null) 
				return;

			int emptyTextCount = 0;
			ValidatingTextBox currTxtBox;

			// Checks all controls in the parent 
			foreach (Control ctrl in Parent.Controls)
			{
				currTxtBox = ctrl as ValidatingTextBox;

				if (currTxtBox != null &amp;&amp; // If the correct object type
					currTxtBox.ButtonToValidate == this.ButtonToValidate &amp;&amp; // and validates the same button
					currTxtBox.Text.Trim() == string.Empty) // and is empty, or contains only spaces
				{
					emptyTextCount++;
				}

			}

			// Enable button only if no text boxes are empty
			if (emptyTextCount == 0)
				ButtonToValidate.Enabled = true;
			else
				ButtonToValidate.Enabled = false;
		}
	}

  • 0
  Rejinderi said:
there IS a neater way to do it, use the validate/validated event.. if u need help with it let me know ill show u my sample :)

Please do. I never got the hang of validation events.

The less code we have to write, the better. Which is why I proposed my stuff above; Once we have the custom textbox there is no more code involved however many textboxes & buttons are in the form.

  • 0

sorry.. looks like what ure doing is simple, if you dont have like 50 textboxes u dont actually have to maintain a list of textboxes.. its not very practical :s.. and since what you need is just making sure they arent 0 lengths i guess you dont have to use validating events either...

just do something simple like this... it wont hurt.. both textboxes are subscribed to the textBox_TextChanged event. Performance wise, its better than looping all textboxes :)

public partial class Form1 : Form
	{
		public Form1()
		{
			InitializeComponent();
			button1.Enabled = false;
			//Set tags
			textBox1.Tag = false;
			textBox2.Tag = false;
		}

		private void textBox_TextChanged(object sender, EventArgs e)
		{
			TextBox textBox = sender as TextBox;
			if (textBox.Text.Length == 0)
				textBox.Tag = false;
			else
				textBox.Tag = true;
			ValidateButton();
		}

		private void ValidateButton()
		{
			this.button1.Enabled = (bool)textBox1.Tag &amp;&amp; (bool)textBox2.Tag;
		}
	}

however if u wanna show the user a colour if the textbox is not set, you can use validating.. this is not a very good example as its not very useful but the concept is there.. if the user enters a textbox and switches to another control without typing anything the validating event will trigger and the textbox will become red...

	public partial class Form1 : Form
	{
		public Form1()
		{
			InitializeComponent();
			button1.Enabled = false;
			//Set tags
			textBox1.Tag = false;
			textBox2.Tag = false;
		}

		private void textBox_TextChanged(object sender, EventArgs e)
		{
			textBox_ValidateEmptyTextBox(sender, null);
		}

		private void ValidateButton()
		{
			this.button1.Enabled = (bool)textBox1.Tag &amp;&amp; (bool)textBox2.Tag;
		}

		private void textBox_ValidateEmptyTextBox(object sender, CancelEventArgs e)
		{
			TextBox textBox = sender as TextBox;
			if (textBox.Text.Length == 0)
			{
				textBox.BackColor = Color.Red;
				textBox.Tag = false;
			}
			else
			{
				textBox.BackColor = SystemColors.Window;
				textBox.Tag = true;
			}
			ValidateButton();
		}
	}

Edited by Rejinderi
This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.