I have a foreach statement, and I need to make it so that a method called at the end of the foreach and if statements only executes after 3 seconds from it's last execution time.
Here's the code.
//Go over Array for each id in allItems
foreach (int id in allItems)
{
if (offered > 0 && itemsAdded != (offered * 3) && tDown)
{
List<Inventory.Item> items = Trade.MyInventory.GetItemsByDefindex(id);
foreach (Inventory.Item item in items)
{
if (!Trade.myOfferedItems.ContainsValue(item.Id))
{
//Code to only execute if x seconds have passed since it last executed.
if (Trade.AddItem(item.Id))
{
itemsAdded++;
break;
}
//end code delay execution
}
}
}
}
And I don't want to Sleep it, since when an item is added, I need to get confirmation from the server that the item has been added.
How about a simple time comparison?
var lastExecution = DateTime.Now;
if((DateTime.Now - lastExecution).TotalSeconds >= 3)
...
You could save 'lastExecution' in your Trade-Class. Of course, the code block is not called (items are not added) with this solution if the 3 seconds haven't elapsed.
--//---------------------------------
Different solution with a timer: we add programmatically a Windows Forms timer component. But you will end in Programmers Hell if you use this solution ;-)
//declare the timer
private static System.Windows.Forms.Timer tmr = new System.Windows.Forms.Timer();
//adds the event and event handler (=the method that will be called)
//call this line only call once
tmr.Tick += new EventHandler(TimerEventProcessor);
//call the following line once (unless you want to change the time)
tmr.Interval = 3000; //sets timer to 3000 milliseconds = 3 seconds
//call this line every time you need a 'timeout'
tmr.Start(); //start timer
//called by timer
private static void TimerEventProcessor(Object myObject, EventArgs myEventArgs)
{
Console.WriteLine("3 seconds elapsed. disabling timer");
tmr.Stop(); //disable timer
}
DateTime? lastCallDate = null;
foreach (int id in allItems)
{
if (offered > 0 && itemsAdded != (offered * 3) && tDown)
{
List<Inventory.Item> items = Trade.MyInventory.GetItemsByDefindex(id);
foreach (Inventory.Item item in items)
{
if (!Trade.myOfferedItems.ContainsValue(item.Id))
{
//execute if 3 seconds have passed since it last execution...
bool wasExecuted = false;
while (!wasExecuted)
{
if (lastCallDate == null || lastCallDate.Value.AddSeconds(3) < DateTime.Now)
{
lastCallDate = DateTime.Now;
if (Trade.AddItem(item.Id))
{
itemsAdded++;
break;
}
wasExecuted = true;
}
System.Threading.Thread.Sleep(100);
}
}
}
}
}
Related
Hello I'm trying to update my chart(s) every second, all chart(s) should be always at the same time. For better understanding I'll include an image but first off I'm gonna explain what actually happens.
So I'm ping requests are sent, every time an result is there, it writes it down in an data point array called file. Everything fine, works as expected.
At the same time, two timers are running, one timer calls a method that prepares the data (let's say at a specific time no data is found in the array -> it should just set value 0). The prepared data is than in a buffer.
The second timer is updating the UI and reading from the tempData but this isn't quite working as expected or wished.
Timers:
myTimer.Interval = 1000;
myTimer.Tick += FileReadFunction;
aTimer.Elapsed += new System.Timers.ElapsedEventHandler(prepData);
aTimer.Interval = 1000;
Button Click which starts timers:
private void _tbStartAll_Click(object sender, EventArgs e)
{
lock (_hosts)
{
foreach (HostPinger hp in _hosts)
hp.Start();
myTimer.Start();
aTimer.Enabled = true;
}
}
Method for preparing Data in Form Class:
public void prepData(object objectInfo, EventArgs e)
{
foreach (NetPinger.source.AddGraph b in graphList)
{
b.prepareData();
}
}
Prep Data Method:
public void prepareData()
{
double unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
for (double i = unixTimestamp; unixTimestamp - graphSizing < i; i--)
{
bool exists;
try
{
exists = Array.Exists(file, element => element.XValue == i);
exists = true;
}
catch
{
exists = false;
}
try
{
if (exists == false)
{
TempBuffer = TempBuffer.Skip(1).Concat(new DataPoint[] { new DataPoint(i, 0) }).ToArray();
}
else
{
DataPoint point = Array.Find(file, element => element.XValue == i);
TempBuffer = TempBuffer.Skip(1).Concat(new DataPoint[] { (point) }).ToArray();
}
}
catch (Exception ex)
{
//just for debugging...
}
}
}
File Read Method in Form Class:
private void FileReadFunction(object objectInfo, EventArgs e)
{
foreach (NetPinger.source.AddGraph b in graphList)
{
b.fileRead();
}
}
Method FileRead / Update Chart:
public void fileRead()
{
//double unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
chart_holder.Series[0].Points.Clear();
foreach (DataPoint a in TempBuffer)
{
chart_holder.Series[0].Points.Add(a);
}
}
Image Example of what I mean with time synchronization:
I'm kinda out of ideas why it's not working out, is it because a thread is faster than another? Or what is the reason and how could I fix it? I'm very thankful for your help.
Greetings C.User
I solved the problem by changing the code a bit. To keep it synchronized I prepare the data first, before displaying it at all. After the data is prepared than all the data is getting displayed. Also I only use one timer now instead of two.
I have a CSV file that will read LineByLine ... like :
0
2.25
5
5.30
I need to Timer interval to change ... but there is no effect when its changed...
I need to fill a textbox.
please let me know your solution
while ((currentLine = sr.ReadLine()) != null)
{
string[] temp = currentLine.Split(',');
timerinterval = (int)(Convert.ToDouble(temp[0])*1000);
if ((int)(Convert.ToDouble(temp[0]) * 1000) != 0)
{
mytimer.Stop();
mytimer.Interval = (int)(Convert.ToDouble(temp[0]) * 1000);
mytimer.Start();
txtCurrentLine.Text = currentLine;
txtTime.Text = timerinterval.ToString();
}
}
public TimeCapture
{
public TimeCapture() => Start = DateTime.Now;
public Start { get; }
public TimeSpan Duration => DateTime.Now.Subtract(Start).Value.TotalSeconds;
}
Then when you intend to read each line.
var timer = new TimeCapture();
while(...)
{
...
txtTime.Text = timer.Duration;
}
Now as you iterate every single line you're capturing the duration as it is reading each line. If you are interested in line by line duration, simply create a new object per line, then put duration and it'll be for the linear code block.
I've been using a timer to refresh the listview on my application, but after half a second, I get the error message at first try/catch method in RefreshPlot() in PlotComponent.cs:
An exception of type 'MySql.Data.MySqlClient.MySqlException' occurred in Marketplace.exe but was not handled in user code
Additional information: There is already an open DataReader associated
with this Connection which must be closed first.
What is this down to? I'm tried using using and try/catch, so I am not really clear on the mistake I could be making. When I disable the timer everything works well. But I need to access the database every 0.5 seconds in order to refresh the listview.
If I am not doing it the correct way is there anything else I can do?
Code is as follows:
MainWindow.cs
public MainWindow()
{
InitializeComponent();
// Reset lists
SetPlotList(_filterPlotReference);
// Refresh lists
Refresh();
}
public void Refresh()
{
var myTimer = new System.Timers.Timer();
myTimer.Elapsed += RefreshPlotList;
myTimer.Interval = 500;
myTimer.Enabled = true;
}
public void RefreshPlotList(object source, ElapsedEventArgs e)
{
PlotComponent.RefreshPlot();
Dispatcher.Invoke(() =>
{
if (!string.IsNullOrWhiteSpace(FilterTextBox.Text) &&
(!Regex.IsMatch(FilterTextBox.Text, "[^0-9]")))
{
_filterPlotReference = Convert.ToInt32(FilterTextBox.Text);
}
});
SetPlotList(_filterPlotReference);
FocusPlotItem(_focusPlotReference);
}
public void SetPlotList(int filterReference)
{
// Fill plot list view
List<PlotComponent.PlotList> plotList = PlotComponent.SelectPlotLists(filterReference);
// Find the plot list item in the new list
PlotComponent.PlotList selectPlotList =
plotList.Find(x => Convert.ToInt32(x.PlotId) == _focusPlotReference);
Dispatcher.Invoke(
(() =>
{
PlotListView.ItemsSource = plotList;
if (selectPlotList != null)
{
PlotListView.SelectedItem = selectPlotList;
}
}));
int jobSum = 0;
int bidSum = 0;
foreach (PlotComponent.PlotList item in PlotListView.Items)
{
jobSum += Convert.ToInt32(item.Jobs);
bidSum += Convert.ToInt32(item.Bids);
}
// Determine job/bid list ratio
Dispatcher.BeginInvoke(
new ThreadStart(() => JobBidRatioTextBlock.Text = jobSum + " jobs - " + bidSum + " bids"));
}
private void FocusPlotItem(int focusPlotReference)
{
Dispatcher.Invoke(
(() =>
{
PlotComponent.PlotList plotList =
PlotListView.Items.OfType<PlotComponent.PlotList>()
.FirstOrDefault(p => Convert.ToInt32(p.PlotId) == focusPlotReference);
if (plotList == null) return;
//get visual container
var container = PlotListView.ItemContainerGenerator.ContainerFromItem(plotList) as ListViewItem;
if (container == null) return;
container.IsSelected = true;
container.Focus();
}));
}
DbConnect.cs
http://pastebin.com/pZ0PGrg1
PlotComponent.cs
http://pastebin.com/xiRhKyMM
Thanks so much for your help in advance.
Here is an example to lock timer till it finishes its work:
bool timerRunning = false; // define it as a global variable
// then in your timer process add this easy check
public void RefreshPlotList(object source, ElapsedEventArgs e)
{
if(timerRunning) return; // return if it is busy
timerRunning = true; // set it to busy
PlotComponent.RefreshPlot();
Dispatcher.Invoke(() =>
{
if (!string.IsNullOrWhiteSpace(FilterTextBox.Text) &&
(!Regex.IsMatch(FilterTextBox.Text, "[^0-9]")))
{
_filterPlotReference = Convert.ToInt32(FilterTextBox.Text);
}
});
SetPlotList(_filterPlotReference);
FocusPlotItem(_focusPlotReference);
timerRunning = false; // reset it for next time use
}
P.S: I edited the other answer by adding (exactly) this answer, then I got rejected, the peer review says
This edit was intended to address the author of the post and makes no
sense as an edit. It should have been written as a comment or an
answer
I have no doubt that they did read the edit and evaluate it, not to mention the fact that it doesn't fit in a comment, so here I post it as an answer
Can you disable the timer until the RefreshPlotList function finishes?
May be at the start of the function disable the timer and at the end of RefreshPlotList function Enable the timer. I guess RefreshPlotList function is taking more than .5 seconds and another call is made before the current one is finished.
My program finished the operation from now to next update time. i want to show the user a counter clock count in the format: 00:00:00
Then 00:20:00 and count 20 minutes back.
This is the code where the operation is finished and timer1 should start:
private void DownloadCompletedCallback(object sender, AsyncCompletedEventArgs e)
{
if (e.Cancelled)
{
//... download cancelled...
}
else if (e.Error != null)
{
//... download failed...
Logger.Write("Error: " + e.Error);
}
ActiveDownloadJob adJob = e.UserState as ActiveDownloadJob;
ProgressBar pb = (adJob != null) ? adJob.ProgressBar : null;
lock (_downloadQueue)
{
if (_downloadQueue.Count == 0)
{
if (pb != null)
{
pb.Tag = null;
timer2.Stop();
label8.ForeColor = Color.Green;
label8.Text = "Process Finished";
label7.Visible = true;
Timer3 tick event if empty now but i think there i should make and display the counter back.
Set the execution time, 20 minutes into the future
var rut_at = DateTime.Now().AddMinutes(20);
And bind or refresh every second a variable called timeLeft that is defined as
var timeLeft = run_at - DateTime.Now();
for (int i = 0; i <= 10; i++)
{
if (5 seconds have passed)
{
do something;
}
}
How can I check if 5 seconds have passed? If 5 seconds have passed for example, it "does something" , then again if more 5 seconds have passed, it does the same thing again, and so on.
And important: If I should use date & time to do it, it should not be a specific time, it should be automatic.
You need a reference start date and a "now" date;
if(startDate.addSeconds(5) < DateTime.Now) do something
If I understood well the situation could be like:
DateTime startDate = DateTime.Now;
for (int i = 0; i <= 10; i++)
{
//do something that can take a long time
//...
//..
if(startDate.addSeconds(5) < DateTime.Now) //5 seconds have passed
{
//do something else
}
}
Thread.Sleep(5000); But this will block your application. You could use a Timer.
For .NET 4.5 you could use the await Task.Delay(5000);
I think FelipeP made a great statement..
But the code you gave, and the description of the problem aren't the same.
The code says, if time is passed.
Your description says the loop must wait until the time is passed.
Update:
System.Windows.Forms.Timer _timer = new System.Windows.Forms.Timer();
void CreateTimer()
{
_timer = new System.Windows.Forms.Timer();
_timer.Tick += new EventHandler(_timer_Tick);
_timer.Interval = 5000;
_timer.Enabled = true;
}
void _timer_Tick(object sender, EventArgs e)
{
// do something.
}