List<System.Timers.Timer> myTimers = new List<System.Timers.Timer>();
private void startFunction()
{
for (var parameter = 0; parameter < list.Count; parameter++)
{
System.Timers.Timer timer = new System.Timers.Timer(TimeSpan.FromMinutes(10).TotalMilliseconds);
timer.Elapsed += new ElapsedEventHandler(someFunction);
timer.Start();
myTimers.Add(timer);
}
}
// without the int parameter this code works
public void someFunction(object sender, ElapsedEventArgs e, int parameter)
{
// some code that have to run over time
}
So on the someFunction method I used a parameter (int) and without it, this is working out fine. I just want to send a parameter through this function and with searching online and trying different methods it still does not work.
Anyone having knowledge on how to send a parameter using the function someFunction every 10 minutes?
Since parameter is just a local variable, you can create a lambda which captures this variable, and passes it to your someFunction method.
private void startFunction()
{
for (var parameter = 0; parameter < list.Count; parameter++)
{
var timer = new System.Timers.Timer(TimeSpan.FromMinutes((10)).TotalMilliseconds);
int parameterCopy = parameter;
timer.Elapsed += (o, e) => someFunction(o, e, parameterCopy);
timer.Start();
myTimers.Add(timer);
}
}
The parameterCopy is required because of this issue.
Related
static void Main()
{
int timersLength = 4;
int interval = 1000;
int[] timerNum = new int[timersLength];
Timer[] timers = new Timer[timersLength];
for (int i = 0; i < timersLength; i++)
{
timerNum[i] = i;
timers[i] = new Timer(interval);
//Console.WriteLine($"Timer {timerNum[i]} is running");
timers[i].Elapsed += (o, e) =>
{
Console.WriteLine($"Timer {timerNum[i]} is running");
};
}
foreach (Timer timer in timers)
timer.Start();
Console.ReadKey();
}
whenever I'm trying to make a countdown to the Timer array it gives an
"System.IndexOutOfRangeException: 'Index was outside the bounds of the array."
on the Elapsed line:
timers[i].Elapsed += (o, e) =>
{
Console.WriteLine($"Timer {timerNum[i]} is running");
};
The code seems fine but for some reason it gives this error.
If you don't want to create a class to store the name of the Timer next to it then you can simply create a Dictionary<Timer, string> collection for mapping.
Dictionary<Timer, string> timers = new Dictionary<Timer, string>(timersLength);
for (int i = 0; i < timersLength; i++)
{
var timer = new Timer(interval);
timers[timer] = $"Timer {i}";
timer.Elapsed += (sender, _) => Console.WriteLine($"{timers[(Timer)sender]} is running");
}
foreach (KeyValuePair<Timer, string> mapping in timers)
mapping.Key.Start();
The Elapsed event handler will be called by passing the sender object
The sender's type is object so you need to cast it to Timer
That object can be used to do the look up in the timers collection
Since yo don't use the EventArgs of the Elapsed I suggest to use the discard operator there to express your intent more clearly
well i am new to C#, and implementing a code, in which i have two buttons, with one acting as starting of data acquisition and storing it in a csv file and other button to stop it.
well codes for all these are as follows:
//button for start DAQ
private void stdaq_Click(object sender, EventArgs e)
{
stopped = false;
process();
}
//button for stoping DAQ
private void spdaq_Click(object sender, EventArgs e)
{
stopped = true;
}
// process function
private process()
{
int iAvail = 0;
int iRead = 0;
string filename = #textBox3.Text;// taking csv file name from user
// jit:
//a function calculating the total number of values and storing it in iAvail
int[] iRawData = new Int32[iAvail];
double[] dScaledData = new Double[iAvail];
//a function transferring the data from buffer and storing it in dscaledData array
List<double> data = new List<double>();
for (int i = 0; i < iAvail; i++)
{
data.Add(dScaledData[i]);
}
Task myFirstTask = Task.Factory.StartNew(()
=>
{
while (stopped == false)
{
Write(data.ToArray(), filename);
// goto jit;
}
});
}
// csv creater and data writer
public static void Write(double[] data, string outputPath)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < data.GetLength(0); i++)
{
if (stopped) break;
sb.AppendLine(string.Join(",", data[i]));
}
if (File.Exists(outputPath))
{
File.AppendAllText(outputPath, sb.ToString());
}
else
{
File.WriteAllText(outputPath, sb.ToString());
}
}
this is what i am implementing, and the problem with this code is that when the data is first transferred and written to the file, then again the same data is written again and again irrespective of new data and i tried implementing that Goto statement(can be seen in comments) but it is giving error - " Control cannot leave the body of an anonymous method or lambda expression ", and if i don't use the While loop the data is not written at all.
So i want to call my process function and to transfer data to csv starting on press of a start button, take fresh data everytime and write it to csv or can say call the process method again from it's start point and to stop it on click of the stop button, but i am unable to do it irrespective of various tries with different loops and some threading functions also.
please help with this.
Assuming you only need to Write once, you should remove this or change it from while to if:
while (stopped == false)
The loop will cause Write to be called infinitely until stopped becomes true.
Also, you might want to change Write to return rather than break if stopped is true, so that you don't write anything if you are supposed to be stopping:
if (stopped) break;
to
if (stopped) return;
If you want to generate data again and really do want to loop forever, just move that code into the loop:
Task myFirstTask = Task.Factory.StartNew(()
=>
{
while (stopped == false)
{
List<double> data = new List<double>();
// TODO: Generate data here - move all relevant code here
Write(data.ToArray(), filename);
}
});
I think this is a job for the BackgroundWorker.
This code will start you up:
public partial class Form1 : Form
{
int loopCounter = 0; // variable just used for illustration
private static BackgroundWorker bw = new BackgroundWorker(); // The worker object
// This function does your task
public void doSomeStuff(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 1000; i++)
{
loopCounter = i; // Pass the loop count to this variable just to report later how far the loop was when the worker got cancelled.
Thread.Sleep(100); // Slow down the loop
// During your loop check if the user wants to cancel
if (bw.CancellationPending)
{
e.Cancel = true;
return; // quit loop
}
}
}
// This button starts your task when pressed
private void button1_Click(object sender, EventArgs e)
{
bw.WorkerSupportsCancellation = true; // Set the worker to support cancellation
bw.DoWork += doSomeStuff; // initialize the event
if (!bw.IsBusy) // Only proceed to start the worker if it is not already running.
{
bw.RunWorkerAsync(); // Start the worker
}
}
// This button stops your task when pressed
private void button2_Click(object sender, EventArgs e)
{
// Request cancellation
bw.CancelAsync();
textBox1.Text = "The bw was cancelled when 'loopCounter' was at: " + loopCounter.ToString();
}
}
This is what i want to do:
....
for(i=0;i<=99;i++)
{
btn[i].Click += new EventHandler(btn_Clicked,i);
}
}
private void btn_Clicked(object sender, EventArgs e,int i)
{
compute((Button)sender, picRetrieved[i]);
}
Please help. It is showing error. But, I want to send the value of i for further processing. Is there any way to do it?
Thank you.
Thanks to closures and anonymous functions you can do something similar:
for(int i=0;i<=99;i++)
{
int j = i;
btn[i].Click += (sender, e) =>
{
// Very important! Here use only j, not i!
compute((Button)sender, picRetrieved[j]);
};
}
There is a small "problem" (that isn't a problem, it's how they are done) so that you mustn't use the i variable inside the anonymous function, but if you copy it somewhere else (j for example) then you can use j.
You can't. The signature of the event handler is fixed, you can't change it.
In this case, you could use an anonymous delegate to get what you want.
for(i = 0; i <= 99; i++)
{
int dummy = i;
btn[i].Click += delegate(object sender, EventArgs e)
{
compute(btn[dummy], picRetrieved[dummy]);
}
}
Another option is to 'tag' the button:
for(i = 0; i <= 99; i++)
{
btn[i].Click += btn_Clicked;
btn[i].Tag = i;
}
private void btn_Clicked(object sender, EventArgs e,int i)
{
Button b = (Button)sender;
int i = (int)b.Tag;
compute(b, picRetrieved[i]);
}
I'm making a WP7-app for my programming class and I want to implement a callback function for checking the state of an integer and not calling the function for checking it explicitly. The integer iterates at the push of a button and when it reaches it's max input I would like to have a callback function checking this, but I'm not completely sure how to implement it.
private void Right_Button_Click(object sender, RoutedEventArgs e)
{
if (current_input <= MAX_INPUT)
{
user_input[current_input] = 3;
current_input++;
display_result();
}
}
#endregion
void display_result()
{
//will move alot of this to the a result page
DateTime time_end = DateTime.Now;
TimeSpan difference = time_end.Subtract(timer);
time_stamp = difference.ToString();
bool combination_error = true;
if (current_input == 4)
{
for (int i = 0; i < MAX_INPUT; i++)
{
if (user_input[i] != combination[i])
{
combination_error = false;
break;
}
}
if (combination_error)
{
MessageBox.Show("Correct combination The timer is " + time_stamp);
}
else
{
MessageBox.Show("Wrong combination");
}
}
}
It's after I increment current_input that I now explicitly call display result something I wish not to do and instead create a callback function for it.
You can't really put a callback function on an integer, however, you could expose your integer as a property and call a function from the property setter. Look at this example:
private int _myInteger = 0;
private int MyInteger {
get
{
return _myInteger;
}
set
{
_myInteger = value;
if (_myInteger <= MAX_INPUT)
MyCallBackFunction();
}
}
private void Right_Button_Click(object sender, RoutedEventArgs e)
{
MyInteger = MyInteger + 1;
// Do your other stuff here
}
private void MyCallBackFunction()
{
// This function executes when your integer is <= MAX_VALUE
// Do Whatever here
display_result();
}
What this is doing is exposing your integer through a private property. As long as you set the property through the setter (e.g. use the MyInteger = MyInteger + 1; syntax), you can have your setter check the condition and execute your call back function.
I have a for loop, and each time through I invoke the same method. I need to find a way to learn what the previous equation was. I have to find this without using the value of incrementation. for example:
for (int i = 0; i < 101; i++) {
checkBox[i].Click += new System.EventHandler(checkBoxMethod); }
Somehow checkBoxMethod should get the previous function in this case for instance:
checkBox[50].Click
Inside of the for loop, also set the tag of each checkbox. I am assuming you are using Windows Forms here. So, here is what the modified for loop would look like:
for (int i = 0; i < 101; i++) {
checkBox[i].Click += new System.EventHandler(checkBoxMethod);
checkBox[i].Tag = i;
}
Then in your event handler you can cast the sender variable to a checkbox like so:
void checkBoxMethod (object sender, EventArgs args)
{
CheckBox box = (CheckBox)sender;
int number = (int)box.Tag;
}
Whatever 'i' was at the time of creating that checkbox's event handler will be retrieved in the variable 'number' and you can use it however you want.
Instead of using a for loop, use recursion and pass the current count into the function:
void checkBoxMethod (object sender, EventArgs args)
{
CheckBox box = (CheckBox)sender;
int number = (int)box.Tag;
myRecursiveMethod(number);
}
private void myRecursiveMethod(int count)
{
//do whatever stuff I need to do
if (!timeToExitTheMethod)
myRecursiveMethod(count++);
}
You've given us no explanation of exactly what you are doing in your for loop and your question doesn't make a lot of sense (i.e. what are the CheckBoxes you allude to?), so I can't be very specific with my code example. Note that you'll have to code an exit point for the recursive method (otherwise it will be called until you get a stack overflow).
If you are simply looking to count the number of times a function has been called then do this:
public class MyClass
{
private int _myCounter = 0;
void checkBoxMethod (object sender, EventArgs args)
{
CheckBox box = (CheckBox)sender;
//do whatever you need to do
_myCounter++;
}
}
If you be more specific with your requirements then we can be more specific with our suggestions.
You can pass the required information to handler using lambda experssions.
for (int i = 0; i < n; i++) {
int number = i;
buttons[i].Click += (sender, args) => OnButtonClick(sender, args, number);
}
...
private void OnButtonClick(object sender, RoutedEventArgs e, int number) {
MessageBox.Show(number.ToString(CultureInfo.InvariantCulture));
}