How to execute a method with a button click - c#

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.

Related

Storing value from try for use in second try C#

Good day fellow helpers, i have following problem:
(running MS Visual Community Edition 2015)
private void button4_Click(object sender, EventArgs e) // Senden
{
serialPort2.WriteLine("SR,00,002\r\n");
textBox1.Text = "gesendet";
textBox3.Text = "";
try
{
System.IO.StreamReader file = new System.IO.StreamReader("C:\\blub.txt");
String line = file.ReadToEnd();
string Hallo = line; \\in the beginning there is "0" in the file
file.Close();
decimal counter = Convert.ToDecimal(Hallo); \\just for testing
counter++;
string b = serialPort2.ReadLine();
string[] b1 = Regex.Split(b, "SR,00,002,"); \\cuts off unwanted input from device
decimal b2 = decimal.Parse(b1[1]); \\number like -3000
System.IO.StreamWriter test = new System.IO.StreamWriter("C:\\blub.txt");
test.WriteLine(counter);
test.Close();
textBox7.Text = "Das ist counter:" + counter;
}
catch (TimeoutException)
{
textBox3.Text = "Timeout";
throw;
}
}
Now, the Serialport is a device that returns a lengthmeasurment. As it is a bit weird, or just the way its build it start with a negitve number (between -5000 and -3370). Now as i want to get measurement on the screen that is realistic i want to set the value to 0 and calculate the difference.
Means: I start the programm - press send - get a value (say -3000) - press send again (after pushing the seonsor in) and get the value that its been pushed in > 0 by adding the difference to 0.
I only learned to store values externally when i had a C course a year back like i did within my programm. Is there a way to store the value from the first measurement in the programm so i can use it on the next send/try?
The counter was just for testing and I would exchange it for the "decimal b2"
I hope there is an easy fix for that, not really a pro with C# yet but i'm eager to learn. I thank the willing helpers in advance, MfG, Chris
OK, I will simplify this in order to show concept so it will not have all the code you are actually using.
So, what you want is to click on button, get some values and store them for next click.
Value is stored in variable. If you have variable in function that is handler for click event, as soon as function completes execution, value will be destroyed.
So, what you need is to create variable in outer scope (class level). Your function is already in class of the form so let's get to code:
class Form1
{
string BetweenClickStorage;
private void button4_Click(object sender, EventArgs e)
{
//Load data here
BetweenClickStorage = LoadedData;
}
}
After this, when you click again on the button, value will still be in BetweenClickStorage. It will be also available to all other buttons click handlers and other code in that form.
If I'm understanding your question correctly, the answer is simply to declare a variable outside the try/catch:
//declare variable //
var measurement;
// TRY #1 //
try
{
//assign value to the variable here
}
catch
{
}
// TRY #2 //
try
{
// reference variable here
}
catch
{
}

Executing some code after form closed in a Windows Form Application C#

I'm creating a C# Windows Form Application with a single form, which creates some files. But i want these to be temporary.
So what i intend to do is this.
All the files which are created during the program execution period will be deleted after the form closes(I tried to delete them before closing the form, but i get an error, so that's why i need to delete it after the form closes). But the problem is just cant seem to do it. I tried searching some websites but i couldn't get a solution.So here i am. If anyone knows how to execute some code after form closes ,pls share it with me
Thanks in advance.
----Edit----
Sry guys for not adding the code here.
Im a noob in application development.
Anyways,here's what i tried:
private void Form1_FormClosing(Object sender, FormClosingEventArgs e)
{
int Length = Directory.GetFiles("C:\\Windows\\Temp\\Yamin").Length;
for( int i = 0; i < Length; i++ )
{
File.Delete("C:\\Windows\\Temp\\Yamin\\" + i + ".jpg");
}
}
Also tried this :
private void Form1_FormClosed(Object sender, FormClosedEventArgs e)
{
int Length = Directory.GetFiles("C:\\Windows\\Temp\\Yamin").Length;
for (int i = 0; i < Length; i++)
{
File.Delete("C:\\Windows\\Temp\\Yamin\\" + i + ".jpg");
}
}
I start the program for testing. Everything works fine but when i close the form i expect the functions above to be executed, but they are not being executed.
Thats my problem.
Again, thanks in advance.
Please check the documentation of the Directory.GetFiles Method (String). Perhaps that is a problem or perhaps the code you posted is inconsistent with your actual code.
I created a Windows Forms application and put two buttons on the form, a Create button and a Delete button.
The following is the code for the Create button:
string Name = string.Empty;
for (int i=0; i<3; ++i)
{
try
{
Name = Folder + "SO36922336-" + i.ToString() + ".txt";
StreamWriter sw = new StreamWriter(Name);
sw.WriteLine("File created using StreamWriter class.");
sw.Close();
sw.Dispose();
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message + "\r\n" + Name);
}
}
The following is the code for the Delete button:
string[] Files = Directory.GetFiles(Folder, "SO36922336-*.txt");
foreach (string fn in Files)
{
File.Delete(fn);
}
The code works for me. So either you are doing Directory.GetFiles incorrectly or the problem is in code that you did not show or both. You don't need to do the delete outside of the form.
The easiest solution is to have the OS take care of those temporary files. To do so, call the File.Create overload1) taking a FileOptions argument, and pass DeleteOnClose. That way the file is automatically deleted by the system, once all handles to it are closed. Added bonus: If your application terminates due to a crash, the OS will still clean up the file after you.
1) If you don't know what value to pass for the bufferSize parameter, just pick the default: 4096.

Make buttons in List send unique data to method

I made a application which will place out buttons in a grid where the user specifies how big the playfield should be.
I create the buttons in a list, specify some data like backgroundimage, size, and location. I then need to, in some way make the different buttons execute different code. I figured I could do this in one method, (if there aren't any good ways to programmatically create methods), if I could somehow make the buttons send a unique piece of information to the method to identify which button is pressed.
public void buttonplacer()
{
int nbrofbtns = Form2.puzzlesize * Form2.puzzlesize;
List<Button> btnslist = new List<Button>();
for (int i = 0; i < nbrofbtns; i++)
{
Button newButton = new Button();
btnslist.Add(newButton);
this.Controls.Add(newButton);
newButton.Name = "btn" + i.ToString();
newButton.Width = btnsidelength;
newButton.Height = btnsidelength;
newButton.Top = btnsidelength * Convert.ToInt32(Math.Floor(Convert.ToDouble(i / Form2.puzzlesize)));
newButton.Left = btnsidelength * Convert.ToInt32(Math.Floor(Convert.ToDouble(i)) - Math.Floor((Convert.ToDouble(i)) / (Form2.puzzlesize)) * (Form2.puzzlesize));
newButton.BackgroundImage = Lights_out_.Properties.Resources.LightsOutBlack;
newButton.Click += new EventHandler(Any_Button_Click);
}
}
void Any_Button_Click(object sender, EventArgs e)
{
}
(If you want to know I'm doing a game called "Light's out")
Thanks in advance!
The Any_Button_Click method receives an object sender that is the button that got clicked. You just need to cast it to a Button:
void Any_Button_Click(object sender, EventArgs e)
{
Button b = (Button)sender;
// do stuff here
}
You can use the button's Location property to figure out where it sits on the game board, or you can assign an arbitrary object to the button with any information you choose at initialization time using the Tag property like this:
button.Tag = "someHelpfulString";
or like this:
button.Tag = new Tuple<int, int>(xpos, ypos);
(where xpos and ypos are positions in the button grid)
or like this:
button.Tag = new ButtonInfoObject(foo, bar, baz);
(Here it's up to you to define the ButtonInfoObject class.)
As an alternative to other answers, and in particular to somewhat address the part "good ways to programmatically create methods", there is part of the C# language called Lambda Expressions. To keep long story short, you could write something along these lines:
newButton.Click += (s, e) =>
{
//here you have access to all variables accessible in current scope,
//including "newButton" and "i";
//you could, for example, call some method passing "i" as an argument
//or just put that method's code inside this block
};
The only downside of this approach is that you need to take some extra care if you're planning to unregister the handler at some later point (see this question or this question for reference).
EDIT
As pointed in comments I overlooked the fact that i stays in scope for the whole for loop, so using it inside lambda is pretty much pointless (all handlers will use it's final value). To make it behave like expected one can simply define a variable inside the loop so it goes out of scope at the end of each iteration and is stored separately for each handler:
var btnNo = i;
newButton.Click += (s, e) =>
{
//use "btnNo" instead of "i"
//you can still safely use "newButton" reference
//since it's defined inside the loop
}
Use the sender object to get the button's name that was pressed:
void Any_Button_Click(object sender, EventArgs e)
{
switch ((sender as Button).Name)
{
case "btn0":
//...
break;
case "btn1":
//...
break;
//...
}
}

Addition in Button Event C#

private void button2_Click(object sender, EventArgs e)
{
int a,sum=0;
a = 10;
sum = sum + a;
MessageBox.Show( sum + "Sum Result");
}
Every time I click on the button I get the answer 10. I want to store result. Suppose I click 5 times then there should be 50.The above code for better understanding should give you some idea of what I'm going for.
Other option if possible I get this result outside of the button event by some method. I am new in C# so feeling lot of problem.
As #tnw tried to tell you - move sum outside the function like this:
private sum = 0;
private void button2_Click(object sender, EventArgs e)
{
sum = sum + 10;
MessageBox.Show( sum + "Sum Result");
}
This should work
explanation
The problem you face is that every variable declared inside a function will get initialized every time you call this function and is discarded when you exit the function.
With the variable beeing outside you made it a field of your class and it will be kept in memory as long as the instance you are using (for example the instance of your form) will be.
It is because sum=0; gets re-initialized every time you call the function. Try setting it as a global variable inside the Class and then call it.
This way, when ever the function will be called, the value of sum won't get back to 0, but will increment from where it was left.
// somewhere above
int sum = 0;
// then the function
private void button2_Click(object sender, EventArgs e)
{
sum = sum + 10;
MessageBox.Show(sum + " = Sum Result");
}
..since you're not using a or b. I have removed them. However, if you're using them inside the function (in a code which you haven't posted) please add them back.
Each time you called the function, you created new variable called sum and if gets deleted at the end of the function. So, each time you pressed the button, sum had a value of 0 in it as initially. Adding 10 to it, would always return 10.
Global variables are declared inside the class itself. Every variable inside the function (such as this one) would be recreated each time you call the function and will have the value you're providing it with. So it is a better approach to write the variables globally, whose value is required next time.

How to use event argument outside the event

I'm trying to create a custom download app. Its all working except for the download all button that cant pick up the "percent1" variable from the "DownloadProgressChangedEventArgs". I have instantiated it prior to the mainForm constructor but it wont read the changed value.
Here's the code, partially stripped since most of it isnt relevant to the question:
public partial class Main : Form
{
//Variables (not all, just the one im having issues with)
private double percentage1;
//Main form constructor
public Main(){...}
//Download File Async custom method
public void DldFile(string url, string fileName, string localPath, AsyncCompletedEventHandler completedName, DownloadProgressChangedEventHandler progressName)
{
WebClient webClient = new WebClient();
webClient.DownloadFileAsync(new Uri(url), localPath + "\\" + fileName);
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(completedName);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(progressName);
}
//Button 1 click event to start download
private void btnDld1_Click(object sender, EventArgs e)
{
if (url1 != "" && Directory.Exists(localPath1))
{
_startDate1 = DateTime.Now;
DldFile(url1, fileName1, localPath1, completed1, progress1);
}
//took out the try/catch, other ifs to try and cut it down
}
//Download Progress Changed event for Download 1
public void progress1(object sender, DownloadProgressChangedEventArgs e)
{
percentage1 = e.ProgressPercentage; //THIS IS WHERE I WAS EXPECTING TO UPDATE "percentage1"
progressBar1.Value = int.Parse(Math.Truncate(percentage1).ToString());
}
//Button that starts all downloads click event where all my problems are at the moment
private void btnDldAll_Click(object sender, EventArgs e)
{
//The progress bar that should let me know the global status for all webClients
progressBarAll.Value = (
int.Parse(Math.Truncate(percentage1).ToString()) + //HERE IS MY PROBLEM
int.Parse(Math.Truncate(percentage2).ToString()) + //HERE IS MY PROBLEM
int.Parse(Math.Truncate(percentage3).ToString()) + //HERE IS MY PROBLEM
int.Parse(Math.Truncate(percentage4).ToString()) + //HERE IS MY PROBLEM
int.Parse(Math.Truncate(percentage5).ToString())) / 5; //HERE IS MY PROBLEM
//Checks if the link exists and starts it from the download button click event
if (url1 != "")
{
btnDld1.PerformClick();
}
//Continues for url2, 3, 4, 5 and else
}
}
So this is the shortest way i found of letting you know what im trying to pull off, if there's something missing please let me know, i'll try to add any info as fast as possible.
I have tried to instantiate "progress1" to try and acess its percentage1 variable, but it didnt work. I've tried doing the same thing with the webClient but didnt work either. I have used google and stackflow search to no avail. So im not sure if the question is too dumb, or there's a diferent way to look at the issue thats completely out of my mindset.
So main problem is updating the "percentage1" variable and using it.
There are other problems regarding the "progressBarAll.Value" calculation that will be solved when i can get my hands on the right value. So no need to worry about that if you see it.
Try not to think about 'using the event arguments outside the event'. Think about updating the state of your form.
Use properties to simplify the update logic:
public partial class Main : Form
{
private double percentage1;
private double percentage2;
private double percentage3;
private double percentage4;
private double percentage5;
private double Percentage1
{
get
{
return this.percentage1;
}
set
{
this.percentage1 = value;
this.UpdatePercentageAll(); // this will update overall progress whenever the first one changes
progressBar1.Value = GetValueFromPercentage(value);
}
}
private double Percentage2
// same code as for Percentage1
void UpdatePercentageAll()
{
this.PercentageAll = (this.Percentage1 + this.Percentage2 + this.Percentage3 + this.Percentage4 + this.Percentage5) / 5;
}
static int GetValueFromPercentage(double percentage)
{
return (int)Math.Truncate(percentage);
}
double percentageAll;
private double PercentageAll
{
get
{
return this.percentageAll;
}
set
{
this.percentageAll = value;
progressBarAll.Value = GetValueFromPercentage(value);
}
}
//Download File Async custom method
public void DldFile(string url, string fileName, string localPath, AsyncCompletedEventHandler completedName, DownloadProgressChangedEventHandler progressName)
{
WebClient webClient = new WebClient();
webClient.DownloadFileAsync(new Uri(url), localPath + "\\" + fileName);
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(completedName);
webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(progressName);
}
//Button 1 click event to start download
private void btnDld1_Click(object sender, EventArgs e)
{
if (url1 != "" && Directory.Exists(localPath1))
{
this.StartDownloadFile1();
}
//took out the try/catch, other ifs to try and cut it down
}
void StartDownloadFile1()
{
this.Percentage1 = 0;
_startDate1 = DateTime.Now;
DldFile(url1, fileName1, localPath1, completed1, progress1);
}
//Download Progress Changed event for Download 1
public void progress1(object sender, DownloadProgressChangedEventArgs e)
{
this.Percentage1 = e.ProgressPercentage; // update property, not field
//this will be done in property setters
//progressBar1.Value = int.Parse(Math.Truncate(percentage1).ToString());
}
// then add similar code for other download buttons
//Button that starts all downloads click event where all my problems are at the moment
private void btnDldAll_Click(object sender, EventArgs e)
{
//Checks if the link exists and starts it from the download button click event
if (url1 != "")
{
this.StartDownloadFile1();
}
//Continues for url2, 3, 4, 5 and else
}
}
I would refactor the code even further, but I think it will be easier for you to understand if the code is closer to the original.
The main idea is to create a set of linked properties which work like mathematical functions. When writing the PercentageX properties I'm kind of saying 'let PercentageAll be the average of all percentages'. Then I have each download update it's own progress. Once any progress is updated it updates the average, and I don't have to rememver that inside the progress changed event handler.
And the last point is updating progress bars from percentage properties. It's quite straightforward: once a percentage is changed, I need to update a bar. If so, why bother writing something like
this.Percentage1 = x;
this.progressBar1.Value = (int)Math.Truncate(x);
In this case I have to remember everywhere that once I change the Percentage1 I have to update the bar. And in my example I just create a strict rule for that which is only in one place and works everytime. So I just cannot forget it. And if I need to change the rule, I need to change only one place, so again I cannot make a mistake.
The technique I demonstrate can be expressed as a well-known rule: 'one rule - one place', which means that you should try to have only single place in code that expresses each logical rule that exists in your program. It is a very important idea, I suggest you learn and use it.

Categories

Resources