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.
Related
I need to do lots (over 100,000) of ADO writes to a MySQL database. If I do this one at a time it will take hours (not acceptable). So figured I could break them into batches of 20 writes at a time into BackgroundWorker. The problem is that while it writes all the records to the database it does not exit out of the method. This means the only way I am to know if the system was completed was by looking at the database.
The code that creates all the BackgroundWorker;
ObservableCollection<MyClass> mObj = new ObservableCollection<MyClass>();
int recordsPerWorker= 20;
int i = 0;
int loop = 1;
int nLoops = (int)Math.Ceiling((double)numItms / (double)recordsPerWorker);
int remain = numItms % recordsPerWorker;
foreach (var x in MyObject)
{
mObj.Add(x);
i++;
if (loop == nLoops)
recordsPerWorker = remain;
if (i == recordsPerWorker)
{
loop++;
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += AddWoker_DoWork;
worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
worker.RunWorkerAsync(mObj);
mObj = new ObservableCollection<MyClass>();
i = 0;
}
}
while (completeWorkers != nLoops)
{
}
Then Worker_RunWorkerCompleted being;
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
completeWorkers++;
}
I have tried this method as well with the same results
I could be going around this all wrong, so please point me in a different direction.
I'm making a program to send data true USB. In my program I'm making a list view to show what the program is currently doing.
because I'm working with USB I have a timer with a interval of 50, this causes problems when I want to send text to my list view because my text is send 50 times per second in stead of 1 time.
Anyone any idea how to solve this?
Changing my program so when a text is already written in the listbox the program may not send it again is not an option I think because the same action can happen more than 1 time.
Here you can find relevant code.
private void ClickMyRadioButton1()
{
if (radioOff1.Checked)
{
radioOff1.PerformClick();
ListViewItem lvi = new ListViewItem("All USB's are off");
listView1.Items.Add(lvi);
}
}
private void tmrUSB_Tick(object sender, EventArgs e)
{
//Everything in here is repeated constantly
USBObject.receiveViaUSB();
listView1.EnsureVisible(listView1.Items.Count - 1);
if ( tabPage1 == tabControl1.SelectedTab)
{
this.radioOff2.Checked = true;
if (radioOff1.Checked == true)
{
USBObject.fromHostToDeviceBuffer[1] = USB_OFF;
ClickMyRadioButton1(); //This is what I only want to send one time to my ListBox and not 50 times a second
}
}
I'm using Visual C# 2010.
Thanks
try this, let me know if it works for you:
private void ClickMyRadioButton1()
{
if (radioOff1.Checked)
{
radioOff1.PerformClick();
ListViewItem lvi = new ListViewItem("All USB's are off");
listView1.Items.Add(lvi);
}
}
int counter = 0;
private void tmrUSB_Tick(object sender, EventArgs e)
{
if (counter != 50)
{
counter++;
return;
}
else
{
counter = 0;
}
//Everything in here is repeated constantly
USBObject.receiveViaUSB();
listView1.EnsureVisible(listView1.Items.Count - 1);
if ( tabPage1 == tabControl1.SelectedTab)
{
this.radioOff2.Checked = true;
if (radioOff1.Checked == true)
{
USBObject.fromHostToDeviceBuffer[1] = USB_OFF;
ClickMyRadioButton1(); //This is what I only want to send one tine to my ListBox
}
}
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();
}
}
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.
This is the numeric changed event code with timer2 wich didnt solve hte problem the function im calling is DoThresholdCheck()
The problem is that in this function im creating each time im changing the numeric value a temp list each time im moving the numeric value change it the list is been created from the start. The problem is that if im using a big file in my program the list is containing sometimes 16500 indexs and its taking time to loop over the list so i guess when im changing the numeric value its taking time to loop over the list. If im using smaller video file for example the list containing 4000 indexs so there is no problems. I tried to use Timer2 maybe i could wait 0.5 seconds between each time the numeric value is changed but still dosent work good.
When im changing the numeric value while the program is running on a big video file its taking the values to be changed like 1-2 seconds ! thats a lot of time.
Any way to solve it ? Maybe somehow to read the list loop over the list faster even if the list is big ?
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
Options_DB.Set_numericUpDownValue(numericUpDown1.Value);
if (isNumericChanged == true)
{
isNumericChanged = false;
myTrackPanelss1.trackBar1.Scroll -= new EventHandler(trackBar1_Scroll);
DoThresholdCheck();
counter = 0;
}
}
private void timer2_Tick(object sender, EventArgs e)
{
counter++;
if (counter > 1)
{
isNumericChanged = true;
//timer2.Stop();
}
}
This is the DoThresholdChecks() function code:
private void DoThresholdCheck()
{
List<string> fts;
//const string D6 = "000{0}.bmp";
if (Directory.Exists(subDirectoryName))
{
if (!File.Exists(subDirectoryName + "\\" + averagesListTextFile + ".txt"))
{
return;
}
else
{
bool trackbarTrueFalse = false ;
fts = new List<string>();
int counter = 0;
double thershold = (double)numericUpDown1.Value;
double max_min_threshold = (thershold / 100) * (max - min) + min;
//label13.Text = max_min_threshold.ToString();
_fi = new DirectoryInfo(subDirectoryName).GetFiles("*.bmp");
for (int i = 0; i < myNumbers.Count; i++)
{
if (myNumbers[i] >= max_min_threshold)
{
//f.Add(i);
string t = i.ToString("D6") + ".bmp";
if (File.Exists(subDirectoryName + "\\" + t))
{
counter++;
button1.Enabled = false;
myTrackPanelss1.trackBar1.Enabled = true;
trackbarTrueFalse = true;
label9.Visible = true;
// myTrackPanelss1.trackBar1.Scroll += new EventHandler(trackBar1_Scroll);
//myTrackPanelss1.trackBar1.Minimum = 0;
// myTrackPanelss1.trackBar1.Maximum = f.Count;
// myTrackPanelss1.trackBar1.Value = f.Count;
// myFiles = new Bitmap(myTrackPanelss1.trackBar1.Value);
}
else
{
label9.Visible = false;
trackbarTrueFalse = false;
button1.Enabled = true;
myTrackPanelss1.trackBar1.Enabled = false;
myTrackPanelss1.trackBar1.Value = 0;
pictureBox1.Image = Properties.Resources.Weather_Michmoret;
label5.Visible = true;
secondPass = true;
break;
}
//fts.Add(string.Format(D6, myNumbers[i]));
}
}
//myTrackPanelss1.trackBar1.Maximum = _fi.Length - 1;
if (myTrackPanelss1.trackBar1.Maximum > 0)
{
if (trackbarTrueFalse == false)
{
myTrackPanelss1.trackBar1.Value = 0;
}
else
{
myTrackPanelss1.trackBar1.Maximum = counter;
myTrackPanelss1.trackBar1.Value = 0;
SetPicture(0);
myTrackPanelss1.trackBar1.Scroll += new EventHandler(trackBar1_Scroll);
}
//checkBox2.Enabled = true;
}
if (_fi.Length >= 0)
{
label15.Text = _fi.Length.ToString();
label15.Visible = true;
}
}
}
else
{
button1.Enabled = true;
}
}
try to cache results from DoThresholdCheck method
You can't magically get around the time the processing takes, if the processing is really necessary. You've got a couple of avenues to explore:
1) Minimise the processing being done - is all of it necessary? Can you cache any of it and only recompute a small amount each time the value changes?
2) Do the processing less often - do you have to recompute every single time?
3) Do the processing on another thread - then at least your UI remains responsive, and you can deliver the results to the UI thread when the background task is complete. However, this is going to be a relatively complicated variant of this pattern as you're going to need to be able to abort and restart if the value changes again while you're still processing the previous one.