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
}
}
Related
I am looking for the best practice to pause foreach or for loops (it has to wait until the user inserts text and presses a button to confirm).
private void btnStarten_Click(object sender, RoutedEventArgs e)
{
//using a foreach loop blocks the UI I read?
for (int i = list.Count; i >= 0; i--)
{
//Here I want to pauze the loop and being able to insert a valeu in a textbox after I
//clicked another button to confirm, I resume the Loop
}
}
My final code looked like this:
private void btnResultaat_Click(object sender, RoutedEventArgs e)
{
if (leerlingIngave.RandomLijst.Count - 1 == leerlingIngave.AntwoordEnUitkomstLijst.Count)
//I compair my 2 lists to eachother (theRandom list was already filled)
{
btnResultaat.IsEnabled = false; // I ended the loop by disabeling the button
leerlingIngave.VerderZettenLoop();
}
else
{
leerlingIngave.VerderZettenLoop();
}
}
public void VerderZettenLoop() // Add object to the list
{
AntwoordEnUitkomstLijst.Add(new LeerlingModel(Uitkomst, Antwoord));
}
I would recommend separating out your code a bit, rather than having a loop that "waits".
For example:
private int _loopIndexer = 0;
public void ContinueLoop()
{
for (; _loopIndexer < list.Count; ++_loopIndexer)
{
if (list[_loopIndexer].Property == "value")
{
// on a matching condition do something and then exit the method
++_loopIndexer; // we need to increment the position before we exit the method
return;
}
}
}
private void btnStarten_Click(object sender, RoutedEventArgs e)
{
// reset to the beginning
_loopIndexer = 0;
ContinueLoop();
}
private void btnContinue_Click(object sender, RoutedEventArgs e)
{
// If the end of the loop is reached, quit (or do whatever)
if (_loopIndexer + 1 == list.Count)
{
// _loopIndexer = 0; // you could reset it to 0 if you wanted to loop again
return;
}
ContinueLoop();
}
The idea is that btnStarten will start the loop, and the loop will stop whenever a condition is met. Then, when you click the Continue button, it will continue the loop if there are any list items left.
Try it online
I am adding items to the listbox using backgroundworker. It is showing all the items present in the list one by one after some interval of time. I want to show only current item in the list and not all the items.
This is what I have tried.
private void backgroundWorker3_DoWork(object sender, DoWorkEventArgs e)
{
List<string> result = new List<string>();
var found = obj.getFiles();//List<strings>
if (found.Count != 0)
{
for (int i = 0; i < found.Count; i++)
{
int progress = (int)(((float)(i + 1) / found.Count) * 100);
if (found[i].Contains("SFTP"))
{
result.Add(found[i]);
(sender as BackgroundWorker).ReportProgress(progress, found[i]);
}
System.Threading.Thread.Sleep(500);
}
e.Result = result;
}
}
private void backgroundWorker3_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.UserState != null)
listBox3.Items.Add(e.UserState);
}
I want to show only current item in the list and not all the items.
Although this is a bit of a hack, I think it should work for what you describe:
// just call clear first
listBox3.Items.Clear();
listBox3.Items.Add(e.UserState);
Truth be told, are you sure you want a ListBox in this circumstance? After all, it's not really a list, it's only an item.
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 usually figure things out but this has me beat.
I have an array of listboxes on a form and a submit button. The user can pick items from any listbox then click the submit button to choose the confirm the item, but what needs to happen is that if they select something from listbox 1 then change their mind and select something from listbox 2, the item selected in listbox 1 should become unselected.
I can code that in to the eventhandlers but the problem is as soon as I change a value in another listbox programatically it fires another event. I can't seem to logic my way out of it.
Any ideas would be great otherwise I guess I will just have to put multiple submit buttons.
EDIT:
I figured out what I think is quite an obvious and simple solution in the end. I made use of the focused property to distinguish whether the user or the program was making changes. Works for both mouse and keyboard selections.
Thanks for the suggestions...
for (int i = 0; i < treatments.Length; i = i + 1)
{
this.Controls.Add(ListBoxes[i]);
this.Controls.Add(Labels[i]);
this.Controls.Add(Spinners[i]);
Labels[i].Top = vPosition - 20;
Labels[i].Left = hPosition;
Labels[i].Width = 600;
ListBoxes[i].Left = hPosition;
ListBoxes[i].Top = vPosition;
ListBoxes[i].Width = 600;
Spinners[i].Top = vPosition + ListBoxes[i].Height;
Spinners[i].Left = hPosition + ListBoxes[i].Width - 60;
Spinners[i].Width = 40;
for (int d = 25; d > 0; d = d - 1) { Spinners[i].Items.Add((d).ToString()); }
Spinners[i].SelectedIndex = 24;
//EVENT HANDLER CODE that is executed if any selectetindexchange in any LIstbox in array
ListBoxes[i].SelectedIndexChanged += (sender, e) =>
{
for (int s = 0; s < i; s = s + 1)
{
//FIND WHICH LBs[s] IS THE SENDING LISTBOX
if (ListBoxes[s] == sender && ListBoxes[s].Focused == true)
{
string msg = "sender is ListBox " + s.ToString() + "\nFocus is" + ListBoxes[s].Focused.ToString();
// MessageBox.Show(msg);
}
else if(ListBoxes[s].Focused==false)
{
ListBoxes[s].SelectedIndex = -1;
}
}
}; //end of event handler
}
I generally solve this kind of problem with a flag that lets me know that I am changing things, so my event handlers can check the flag and not take action in that case.
private int codeChangingCount = 0;
private void combobox1_SelectedIndexChanged(object sender, EventArgs e) {
codeChangingCount++;
try {
combobox2.SelectedIndex = someNewValue;
} finally {
codeChangingCount--;
}
}
private void combobox2_SelectedIndexChanged(object sender, EventArgs e) {
if (codeChangingCount == 0) {
//I know this is changing because of the user did something, not my code above
}
}
You can do this with a simple bool instead of an int, but I like the counter approach so that I can keep incrementing codeChangingCount in nested calls and not accidentally reset it. In my production code, I have a class dedicated to this kind of flagging, and it (mis)uses IDisposable to decrement, so I can just wrap my calls in a using block, but the above snippet is simpler for illustration.
Check if Focused ListBox == ListBox2 and SelectedIndex > -1 then deselect Index[0]
if (ListBoxes[s] == sender && ListBoxes[s].Focused == true)
{
if(s == 1 && ListBoxes[s].SelectedIndex > -1) //assuming 1 is listbox2
{
ListBoxes[0].SelectedIndex = -1; // Deselect ListBox1
}
string msg = "sender is ListBox " + s.ToString() + "\nFocus is" + ListBoxes[s].Focused.ToString();
}
I have a timer event that does several things. One item I am trying to get it to do is to programmatically remove the CheckListBox items that are checked once the timer hits the completed action I am performing.
This is the code for the timer and what I have tried to do.
private void timer1_Tick(object sender, EventArgs e)
{
string s;
if (DbFirmwareUpdateComplete.WaitOne(1))
{
DbFirmwareUpdateComplete.Reset();
mnuLoadKeyFile.Enabled = true;
}
if (DbUpdateComplete.WaitOne(1))
{
DbUpdateComplete.Reset();
mnuLoadKeyFile.Enabled = true;
btnLoad.Enabled = true;
}
if (CacheComplete.WaitOne(1))
{
CacheComplete.Reset();
btnLoad.Enabled = true;
}
if (UpdateRunning)
{
bool UpdateDone = true;
int StillActive = 0;
// loop through all active jobs to check if all have completed
foreach (clsCnaPair cna in ActiveJobs)
{
if (cna.Job.JobComplete == false)
{
UpdateDone = false;
StillActive++;
}
else
{
if (cna.Job.UpdateSuccess)
{
// Update color of CLB.Items.Selected if success.
int count = CLB.Items.Count;
for (int index = count; index > 0; index--)
{
if(CLB.CheckedItems.Contains(CLB.Items[index-1]))
{
CLB.Items.RemoveAt(index - 1);
}
}
}
else
{
// Update color of CLB.Items.Selected if failed.
}
}
}
if (UpdateDone)
{
UpdateRunning = false;
log("All Update jobs have finished.");
}
if (ckTop.Checked == true)
{
ckTop.Checked = false;
}
else
{
ckTop.Checked = false;
}
When I run the program and it hits this piece;
if (cna.Job.UpdateSuccess)
{
// Update color of CLB.Items.Selected if success.
int count = CLB.Items.Count;
for (int index = count; index > 0; index--)
{
if(CLB.CheckedItems.Contains(CLB.Items[index-1]))
{
CLB.Items.RemoveAt(index - 1);
}
}
}
I get an error:
System.ArgumentOutOfRangeException: InvalidArgument=Value of '-1' is not valid for 'index'.
Parameter name: index
The Error occurs after this piece of code;
private void CLB_SelectedIndexChanged(object sender, EventArgs e)
{
// One of the CNA IPs was selected. sender is the CheckedListBox.
// Here we want to display its fingerprint in the text box, or if the push is running, the status.
// get the CnaPair class represented by this IP:
clsCnaPair CnaPair = (clsCnaPair)CLB.Items[CLB.SelectedIndex];
// Display the corresponding fingerprint string in the editBox:
if (CnaPair.Job != null) txtStatus.Text = CnaPair.Job.GetStatus();
else txtStatus.Text = CnaPair.GetInfo();
}
Or more specifically at the line:
clsCnaPair CnaPar = (clsCnaPair)CLB.Items[CLB.SelectedIndex];
What am I missing? Searching google, shows the way I am doing the remove is consistent with the examples found there.
Thanks,
It's dangerous to modify the contents of the ChecklistBox inside a loop when the loop conditions depend on the contents of the ChecklistBox. Once you call RemoveAt(), the CheckedItems list and the CLB.Items.Count has changed and you will have a problem. In this case, the loop fired the SelectedIndexChanged() event with an invalid Index (-1).
Better to do this in a do-while loop:
bool done;
do
{
done = true;
for (int index = CLB.Items.Count; index > 0; index--)
{
if(CLB.CheckedItems.Contains(CLB.Items[index-1]))
{
CLB.Items.RemoveAt(index - 1);
done = false;
break;
}
}
}while(!done);
This way, every time an item is removed, you break out and start the loop all over again.
After some experimentation, I commented out the CLB_SelecteIndexChanged code and it now completes with the original code.
That leaves one issue. What is the work around with the CLB_SelectedIndexChanged code left in. I will work on that one more and see f I can figure it out with what you guys have provided.
Thanks to both m.rogalski and mcNets.