C# event click containing more than one method - c#

I am trying to nest methods, or place methods within other methods. Using C# and Microsoft Visual Studio for the first time and my dilemma is this. I have created form with an event click button to validate user input, which is fine in itself, but I need to validate more than one input when the button is clicked. In the Calculate button’s click event handler, perform input validation on the three text boxes (the three that the user will use for data entry). For code efficiency I want to use separate methods to achieve this. I have tried writing more methods directly within the event handler, but no matter how I start the method public, private, static, void, main etc I always get errors. Any assistance/advice would be greatly appreciated.
private void btnCalculate_Click(object sender, EventArgs e)
{
int txtLength = 0;
if ((txtLength < 5) & (txtLength > 50))
MessageBox.Show("Length measurement is invalid" + "\r\n" + "Please enter a value between 5 and 50", "Data Invalid");
int txtWidth = 0;
if ((txtWidth < 2) & (txtLength > 20))
MessageBox.Show("Width measurement is invalid" + "\r\n" + "Please enter a value between 2 and 20");
int txtAvgDepth = 0;
if ((txtAvgDepth < 2) & (txtAvgDepth > 4))
MessageBox.Show("Width measurement is invalid" + "\r\n" + "Please enter a value between 2 and 20");*/
}
Changed code in method along with the error messages it throws. The original code had no syntax errors.
Problem solved. Thank you all very much for your help :)

Just add them to the class:
private void CalculateButton_Click(object sender, EventArgs e)
{
ValidateLength();
ValidateWidth();
ValidateDepth();
}
private void ValidateLength()
{
int txtLength = LengthTextBox.Value;
if ((txtLength < 5) & (txtLength > 50))
MessageBox.Show("Length measurement is invalid" + "\r\n" + "Please enter a value between 5 and 50", "Data Invalid");
}
private void ValidateWidth()
{
int txtWidth = WidthTextBox.Value;
if ((txtWidth < 2) & (txtLength > 20))
MessageBox.Show("Width measurement is invalid" + "\r\n" + "Please enter a value between 2 and 20");
}
private void ValidateDepth()
{
int txtAvgDepth = DepthTextBox.Value;
if ((txtAvgDepth < 2) & (txtAvgDepth > 4))
MessageBox.Show("Depth measurement is invalid" + "\r\n" + "Please enter a value between 2 and 4");*/
}
I guess you're trying to tidy this up and have a single validation routine:
private void CalculateButton_Click(object sender, EventArgs e)
{
ValidateRange(LengthTextBox.Value, 5, 50, "Length");
ValidateRange(WidthTextBox.Value, 2, 20, "Width");
ValidateRange(DepthTextBox.Value, 2, 4, "Depth");
}
private void ValidateRange(int value, int min, int max, string msg)
{
if (value < min || value > max)
MessageBox.Show(
string.Format("{0} measurement is invalid\r\nPlease enter a value between {1} and {2}", msg, min, max),
"Data Invalid");
}

Click Handlers are known as delegates, they subscribe to events in a one-event, many subscribers fashion. What you are trying to achieve is completely possible but not from the IDE GUI, as it is designed to manage a single subscription. You could instead subscribe to the event from code like this
btnCalculate.Click += ClickHandler1;
btnCalculate.Click += ClickHandler2;
btnCalculate.Click += ClickHandler3;
Even though it's possible, i'd strongly advise against it as it seems over-engineered and it's not really how the platform was thought out to be used. It shouldn't have any bad side effects as the .Net event/delegate system is ready to handle this use case but the maintainability suffers in the process.
I'd rather go with an orchestrator method. Subscribe once and call each validation method from there.
More reading material:
https://msdn.microsoft.com/en-us/library/17sde2xt%28v=vs.90%29.aspx
https://msdn.microsoft.com/en-us/library/bb534960(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/018hxwa8(v=vs.110).aspx

Related

How to execute a method with a button click

How can I add a function to a button that will run a method I've created. I want to write out an array into a message dialog box with a press of a button, but I don't seem to be getting anywhere so i turned to stackoverflow for some help, since googling didn't really help me with my problem.
static void Tractors(Tractor[] tractors)
{
for (int i = 0; i < tractors.Length; i++)
{
Console.WriteLine((i + 1) + ", " + tractors[i].ToString());
}
}
This is my function that writes out the table of "Tractors".
private void button1_Click(object sender, EventArgs e)
{
}
What should I write into the button1_click method so that it would work?
You need to bind the event handler with the button control and write the logic inside this event handler. If its windows form application you can do like this.
this.button1 = new System.Windows.Forms.Button();
this.button1.Click += new System.EventHandler(this.button1_Click);
private void button1_Click(object sender, EventArgs e)
{
//Call your methods here
}
You would call Tractor() the exactly same way you call Console.WriteLine(). Both are static functions.
However the function is utterly messed up and propably not salvageable. The proper name would be printTractorsToConsole(). As it contains the Console.WriteLine() call, it is strongly tied to Console Applications - avoid tying functions to one Display Technology like that.
You need a more general function that creates and returns a string. You can then send that string to WriteLine(), assign it to Label.Text or wherever else you want the string to be. Strings primarily exist for intput from or output towards the user - and there is too many ways to get it to them.
//Not tested against a compiler, may contain syntax errors
static string TractorArrayToString(Tractor[] tractors){
string output = "";
for (int i = 0; i < tractors.Length; i++)
{
output += (i + 1) + ", " + tractors[i].ToString()) + Environment.NewLine;
}
return output;
}
But even function might be a bad idea, as that function would tie all representations to a single format. Generally you would write that loop directly into the Click Event. But this function looks like it is for printing for debug purposes, so it might work.

Latency issues with time between 2 events

I had a task to make reflex meter app, and I got and exe as an example. I made it work but I don't get the same results from example I was given and my app, it's like I have 60-70 ms lost somewhere. App is supposed to show a text at random time between 0.5 and 5 seconds and when text shows, the user is supposed to click a button that will stop the stopwatch class I was using here and write it into last and best times.
First I was saving TotalMilliseconds , seconds , milliseconds and minutes as double , and now as TimeSpan, I felt as when I saved it in TimeSpan it reduced time but not enough to be close as example app or even online reflex app. I was thinking about delay between events or even mouse click, but I don't think its supposed to be like 50 60 ms. And if that is the problem how to measure those.
These are start events
private void Start_B_Click(object sender, EventArgs e)
{
Random rnd = new Random();
RndTimer.Interval = rnd.Next(500, 5000);
RndTimer.Start();
}
Stopwatch s = new Stopwatch();
private void RndTimer_Tick(object sender, EventArgs e)
{
NOW_L.Visible = true;
s.Reset();
s.Start();
Random rnd = new Random();
RndTimer.Interval = rnd.Next(500, 5000);
}
and this is button click event
public double o;
private void Click_B_Click(object sender, EventArgs e)
{
if (NOW_L.Visible == true)
{
s.Stop();
TimeSpan ts = s.Elapsed;
NOW_L.Visible = false;
if (LtimeRez_LB.Text == "00:00:00" || ts.TotalMilliseconds < class1.m)
{
LtimeRez_LB.Text = ts.Minutes.ToString() + ":" + ts.Seconds.ToString + ":" +
ts.Milliseconds.ToString();
BesttimeRez_LB.Text = ts.Minutes.ToString() + ":" + ts.Seconds.ToString + ":" +
ts.Milliseconds.ToString();
class1.m = ts.TotalMilliseconds;
o = class1.m;
}
else if (ts.TotalMilliseconds > o || ts.TotalMilliseconds == o)
{
LtimeRez_LB.Text = ts.Minutes.ToString() + ":" + ts.Seconds.ToString + ":" +
ts.Milliseconds.ToString();
}
NOW_L.Visible = false;
}
}
LtimeRez variable is label that is displaying last result and BestTimeRez is best time result, also I used public static double variable called m
Use the MouseDown event of the Button instead of the Click event. The Click event will only be triggered some time later than when the user pressed the mouse button on the control because it first waits for the user to also release the mouse button and because it also has to perform some internal tasks first (redrawing the button, validation checks).
Additional notes on the code:
Don't create a new instance of the Random class each time. Create one instance once and reuse it all the time. See How do I generate a random int number in C#?
In the Timer Tick function, only start the Stopwatch after setting the timer interval. The button will actually only become visible when the code leaves that function and has a chance again to process Windows messages.
Please give o and m some meaningful names. You don't need both variables. They always have the same value. You only need one of them.
In CLick_B_Click, you don't need the if in the else part.
In the current version of the code, when the user does not click immediately, the timer click event can happen multiple times before the user clicks the button, resetting the stopwatch too early...
One problem I am seeing here is string concatenation in you code. In C# world, while concatenating you should use String.Format() method. Using plus operator to join the string will add delay. So use below line to form string -
LtimeRez_LB.Text = String.Format("{0}:{1}:{2}", ts.Minutes, ts.Seconds, ts.Milliseconds);
~Nilesh

NumericUpDown ValueChanged preventDefault?

I want to create a form that allows the user to set a certain amount of points in five different fields (NumericUpDown). When that amount of points reaches 0, the user can't add any more. (I still want the user to be able to remove points, though.)
Here is my code so far:
private void calculateValue() {
decimal tempValue = CMB_num_Aim.Value + CMB_num_Reflexes.Value +
CMB_num_Positioning.Value + CMB_num_Movement.Value + CMB_num_Teamwork.Value;
controlValue = currentValue - tempValue;
MyBox.CMB_tb_cv.Text = controlValue.ToString();
}
This Method (calculateValue) is calculates how many points the user have left (controlValue).
private void CMB_num_Aim_ValueChanged(object sender, EventArgs e) {
calculateValue();
if (controlValue < 0) {
//Prevent Default here
MessageBox.Show("You are out of points!");
}
}
This method (CMB_num_Aim_ValueChanged) fires when the value of the NumericUpDown control has changed. I have one of these for each field, each doing the same thing.
The method fires as expected, but I can't prevent it from happening - the user can apply more points than they have. How can I prevent the user from applying more points?
(I thought about making a mouseUp method, but I don't know if the user will use the mouse or if he will type in the value using the keyboard.)
Seems like you want to create a point distribution system between some skills - aim, movement, teamwork etc. You can do that easily by setting Maximum value of NumericUpDown control when you enter it. Subscribe all skill updown controls to the same event handler:
private void SkillNumericUpDown_Enter(object sender, EventArgs e)
{
var skill = (NumericUpDown)sender;
var availablePoints = 42;
var maxSkillPoints = 20; // usually you cannot assign all points to one skill
var unassignedPoints = availablePoints - SkillPointsAssigned;
skill.Maximum = Math.Min(maxSkillPoints, unassignedPoints + skill.Value);
if (unassignedPoints == 0)
{
MessageBox.Show("You are out of points!");
return;
}
if (skill.Value == maxSkillPoints)
{
MessageBox.Show("Skill maximized!");
return;
}
}
private decimal SkillPointsAssigned =>
CMB_num_Aim.Value +
CMB_num_Reflexes.Value +
CMB_num_Positioning.Value +
CMB_num_Movement.Value +
CMB_num_Teamwork.Value;
Benefit - you will not be able to input illegal value neither by arrows nor manually.
Replace
if (controlValue < 0) {
By
if (controlValue <= 0) {

Logic trouble with loop

I am creating a windows form that is a random number guessing game. I've made these before in C++ and never had an issue, however I have a big one here- I have no idea how to get the user back to input a number after the loop has began running. Here is my code:
private void btnGuess_Click(object sender, EventArgs e)
{
int guess = 0;
int count = 0;
int accumulator = 0; // accumulator
Random rand = new Random();
int number = rand.Next(1, 100);
txtAnswer.Focus();
while (guess != number)
{
guess = int.Parse(txtAnswer.Text);
if (guess < number)
{
MessageBox.Show("Too Low! Guess again!");
txtAnswer.Text = "";
txtAnswer.Focus();
count++;
accumulator++;
}
else if (guess > number)
{
MessageBox.Show("Too High! Try again!");
txtAnswer.Text = "";
txtAnswer.Focus();
count++;
accumulator++;
}
else
{
MessageBox.Show("Correct! you guessed the number in " + accumulator + " tries!");
break;
}
}
}
}
}
I just filled the while loop arguments with something for you guys, even though i know it won't work. Basically, I need to run the loop, get feedback (if the users guess was too high or low) then get the user to be able to input another number BEFORE the loop runs again. I don't know how to get that to happen with a text box control which is where the input will be. Any ideas?
You should not loop inside in the btnGuess_Click. Instead you need to store the state (the number, count, and the accumulator variables) in the scope of the form itself.
Initialize the random number when the form loads, or using some kind of start button.
Then inside the guess button handler, read the text box value and compare it to the number variable, such as what you are doing currently.
What you are building is more a console style application. So there is 1 main loop that is executing all the code.
In forms applications it is an event driven environment. So the user gets a form, presses a button, the form is evaluated and then the method handling ends.
So you have on a class level some variables for counts, in the constructor you add the initialization and the method for submit will be something like
private void btnGuess_Click(object sender, EventArgs e)
{
//Increment counters
//Check
//Show feedback
//Leave the button click code
}
For some more info, check this out:
https://msdn.microsoft.com/en-us/library/dd492132.aspx

C# textbox user input processed by a button object [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C# GUI application that stores an array and displays the highest and lowest numbers by clicking a button
This is updated from 13 hours ago as I have been researching and experimenting with this for a few. I'm new to this programming arena so I'll be short, I'm teaching myself C# and I'm trying to learn how to have integers from a user's input into a textbox get calculated from a button1_Click to appear on the form. Yes, this is a class assignment but I think I have a good handle on some of this but not all of it; that's why I'm turning to you guys. Thanks for all of the advice guys.
I'm using Microsoft Visual Studio 2010 in C# language. I'm using Windows Forms Application and I need to create a GUI that allows a user to enter in 10 integer values that will be stored in an array called from a button_Click object. These values will display the highest and lowest values that the user inputted. The only thing is that the array must be declared above the Click() method.
This is what I have come up with so far:
namespace SmallAndLargeGUI
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void inputText_TextChanged(object sender, EventArgs e)
{
this.Text = inputText.Text;
}
public void submitButton_Click(object sender, EventArgs e)
{
int userValue;
if(int.TryParse(inputText.Text, out userValue))
{
}
else
{
MessageBox.Show("Please enter a valid integer into the text box.");
}
int x;
x = Convert.x.ToString();
int squaredResults = squared(x);
int cubedResults = cubed(x); squared(x);
squaredLabel.Text = x.ToString() + " squared is " + squaredResults.ToString();
cubedLabel.Text = x.ToString() + " cubed is " + cubedResults.ToString();
}
public static int squared(int x)
{
x = x * x;
return x;
}
public static int cubed(int x)
{
x = x * squared(x);
return x;
}
}
}
Now I can't run this program because line 38 shows an error message of: 'System.Convert' does not contain a definition for 'x' Also I still have to have an array that holds 10 integers from a textbox and is declared above the Click() method. Please guys, any help for me? This was due yesterday.
As a couple of comments have mentioned, there really isn't enough information here to provide you with a useful answer. There are two main User Interface frameworks in .Net for windows applications. One of these is commonly referred to as "WinForms" and the other is "WPF" or "Windows Presentation Foundation."
I'm going to go with you are most likely using WinForms as it is the older of the two technologies. The approach here can be used on both sides with a little tweaking. Setting text in a text box is very similar to setting text programaticly on a label. You can get more detail on that on MSDN: How to: Display Text on a Windows Form; How to: Use TextBox Controls to Get User Input.
If you are using WPF the "back end" code is pretty much the same. You just need to make sure your textbox has an x:Name="userInputTextBox" so you can reference it in your code behind. Be mindful that your users can input "1", "3" or "abcd" in the field. Ensuring your app doesn't bomb is most likely outside of the assignment but feel free to look up C# int.TryParse(...) and "Try Catch" :-)
Your button handler could look like this:
void btnUserClick_Click(object sender, System.EventArgs e)
{
int userValue;
if(int.TryParse(txtUserInput.Text, out userValue))
{
// We have the value successfully, do calculation
}
else
{
// We don't have the users value.
MessageBox.Show("Please enter a valid integer into the text box.")
}
}
In your retrieveInput_Click handler you are assigning the min/max numbers to a local int. Once you determine your min/max numbers in the logic, you will need to assign those local integers to a UI element for display.
Since we don't have any details on your specific UI choices, one simple solution could be to add 2 labels to your form, and then in the code you would place the result in the label:
for (int i = 0; i < numbers.Length; ++i)
{
if (numbers[i] < min)
min = numbers[i];
if (numbers[i] > max)
max = numbers[i];
}
// Assign Minimum to Label1
Label1.Text = "Minimum Value: " + min.ToString();
// Assign Maximum to Label2
Label2.Text = "Maximum Value: " + max.ToString();
define the textbox named textbox1 or txt_name
you can write the button1_Click function :
int i_value = Convert.ToInt16(txt_name.Text);
ok. I haven't try catch the exceptions.... :(
maybe above answer is right.
btw, i think this question mainly focus on how to get int type from text box. right?

Categories

Resources