looping through an array one element at a time - c#

When I do this for loop on a windows form app and I click a button to start this for loop, the label just changes to the last item in the array, how do I get it to go through the array one at a time?
for (int i = 0; i < WordsnQuestions.questions.Length; i++)
{
lblScrambled.Text = WordsnQuestions.questions [i++];
}

The loop is too fast... the label changes for every item in the loop (note: loop, not array, because of another issue), but the form doesn't have a chance to repaint anything until after the loop is already finished. By this time we're already up to the last item, so that's what we see.
The typical fix for this is move the index outside of the method, and only show one item for each event:
int currentPosition = 0;
public void btnNext_Click(object sender, EventArgs e)
{
lblScrambled.Text = WordsnQuestions.questions [currentPosition++];
if (currentPosition >= WordsnQuestions.questions.Length) currentPosition = 0;
}
Separate from this, the original code incremented the counter twice per loop iteration... but again, properly designing the interaction avoids this in the first place.
But let's say you wanted an animation effect. Then you might try something like this to slow things down (note only one increment operator is used):
for (int i = 0; i < WordsnQuestions.questions.Length; i++)
{
lblScrambled.Text = WordsnQuestions.questions [i];
Thread.Sleep(1000);
}
But this still won't work, because the code still does not yield control back to the form so it can repaint the window.
Now you might be tempted to do something like this:
for (int i = 0; i < WordsnQuestions.questions.Length; i++)
{
lblScrambled.Text = WordsnQuestions.questions [i];
Application.DoEvents();
Thread.Sleep(1000);
}
This will seem to (finally!) work, because it does allow an event loop to finally process each of WM_PAINT messages. However, there are still all kinds of problems with it. Again, the correct solution is really to think more carefully about how the interaction should work in the first place.

There are two issues here:
i++ is twice so your skipping items #2, 4, 6... and looping over 1, 3, 5 ... etc
lblScrambled.Text will have the last item and program will not fail if you have odd number of items.
Here is the updated code for you to try:
for (int i = 0; i < WordsnQuestions.questions.Length; i++)
{
lblScrambled.Text += WordsnQuestions.questions [i];
}

Related

Send multiple lines to Arduino from a listbox C#

int nums = lstbox.SelectedItems.Count;
for (int i = 0; i < nums; i++)
{
string itemz = (lstbox.SelectedItems[i].ToString());
serialPort1.Write(itemz);
Thread.Sleep(50);
I want to turn on some LEDS using this method. It doesnt work for more than 1 item with this method, which is the first one. Thread.sleep doesnt work, i was thinking maybe i can pause between tasks. Any suggestion? Thank you.

Why doesn't my counter count?

This really suprised me. One of the simplest things doesn't work, making a counter. I'm making a kinda game application in c# and there is also a timer who counts the time. Very simple right? I know how to code this and this is something I did before but I don't understand why it isn't working now.
int i = 0;
i++;
label1.Text = i.ToString();
label1.Text turns in to 1 and nothing else happens. Also tryied this with a timer but it freeezes in 1. I know this post isn't really going to help other people but it is very frustrating.
Why you are always getting 1 in your label1 text?
The reason is very simple, each time you are getting to the first line, i is 0:
// Line 1
int i = 0; // declaring and setting i to 0
// Line 2
i++; // incrementing i to 1
// Line 3
label1.Text = i.ToString(); // displaying i (which is equal to 1)
and then again you are getting to the Line 1 and setting i=0, etc...
I presume you have a UI application (win form, web form etc...)
You already mentioned you have a timer that works fine and a label where you output the incremented i variable.
As already commented in order to see a change in your label you can use a loop as following:
int length = 100; // for example
for (int i = 0; i < length; i++)
{
label1.Text = i.ToString();
}
The output in label1 text will be 0, then 1, then 2 .... and finally 99.
Obviously you won't be able to see all those values except the last one 99 at run-time but you can debug and see how it works.
I presume, what you needed is to have your label text changing each time the timer will tick.
Following a code example how you could implement it:
private int i = 0; // initialized once in this UI class
private void timer1_Tick(object sender, EventArgs e)
{
label1.Text = i.ToString();
i++; // will increment by one each time the timer is ticking
}
Set your timer interval to ~1000 so you could clearly see how your text label increments at run-time.
If you want to increment it you have to add the incrementing logic in a loop like for or while loop:
If you want to use timer to count something please refer to this question : here

Changing The Label Text in Button Click - Understanding For Loop

When I clicked button starts for loop from i=0 and I want to see on the label value of i. However I only see last values of i.
public partial class Form1 : Form
{
int i;
public Form1()
{
InitializeComponent();
}
private void btnclick_Click(object sender, EventArgs e)
{
for ( i = 0; i < 3; i++)
{
lblForLoopExample.Text = i.ToString();
System.Threading.Thread.Sleep(1000);
}
}
}
when I run the my code I only see on the label ; 2 .
I want to see such a like below;
When the started For loop, i = 0, I must see the 0 on the Label.Text. An then when the i = 1, I must see 1 on the label.Text. And when i = 2, I must see 2 on the Label.Text.
I added Thread.Sleep(1000) however, result didn't change.
Where I am make mistake?
Please help me,
if you help me , I will appreciate you.
Thanks,
You need to append the lbl to get all the values. Right now, it finishes the loop and give you the last value in your label
public partial class Form1 : Form
{
int i;
public Form1()
{
InitializeComponent();
}
private void btnclick_Click(object sender, EventArgs e)
{
for ( i = 0; i < 3; i++)
{
lblForLoopExample.Text + = i.ToString();
}
}
}
Your problem is that you're doing work on the UI thread while expecting the UI thread to update your form.
While you process your loop, the UI thread is actually executing this code. The UI thread is therefore unable to update the form with the intermediate values you are setting within the loop. Once your code completes, the UI thread is then free to update the form. That's why you see the last value only.
You can see this better if you updated your code to loop ten million times instead of 3. Your form will become unresponsive and will appear locked up. That's because Windows knows your UI thread is locked in an intensive process and is unable to update the UI.
The solution is to use a background thread to run your process and synchronize updates with the UI thread. You'll also have to slow your loop down to see the changes, as others have suggested.
To learn more about how the UI thread works, and how to synchronize background threads with it, read this article (it's about WPF, but it covers the general case).
Each loop you re-write the string. Instead of saying
lblForLoopExample.Text = i.ToString();
You need to add to the string on each iteration. I'd create a variable to hold the value, and so something like this:
string myString = string.Empty;
for(i=0;i < 3; i++)
{
myString += i.ToString() + ", ";
}
lblForLoopExample.Text = myString.substring(0, (myString.length - 1));
substring is just so you don't have that trailing comma. It's kind of dirty code, but it will work.
First of all, your code won't compile as you are missing the exact format of the ToString() method in i.ToString along with the ;
lblForLoopExample.Text = i.ToString();
^^^
As per your code, you should try this:
for ( i = 0; i < 3; i++)
{
lblForLoopExample.Text += i.ToString() + ", ";
}

Automatic function linked to an external timer

I have an automatic function, the idea is to execute in an specific time some actions.
It receives a ListView with the actions and specific times.
It runs almost pefect. I say almost because sometimes it doesn't executes one action (lets say action #10, and it has 30 actions to do) and when this happen the rest of the actions neither get executed.
I have some validations where I check if the previous actions is executed then the current one is excuted, but it doesn't make any difference, it continues stopping at some point.
Here the code for this automatic function:
Constructor
public RunAutomatic()
{
InitializeComponent();
stopwatch = new System.Windows.Forms.Timer();
stopwatch.Interval = 5;
stopwatch.Tick += new EventHandler(stopwatch_Tick);
repSeconds = 0;
for (int x = 0; x < repeatActions.Capacity; x++)
{
repeatActions.Add(x);
finished.Add(x);
}
}
Run Function
private void RunFaster()
{
if (contPos > 1)
{
ArrayList tmp = (ArrayList)repeatActions[contPos - 1];
if ((bool)tmp[tmp.Count - 1] == true) //This is where it is supposed to validate that the previous action is already executed
Execute(2);
else
{
contPos = contPos - 1;
Execute(2);
}
}
else
Execute(2);
}
I have tried to solve this but can't get over it.
Thanks to all replies.

How do I check the state of a thread

I have winform application where i am trying to play multiple videos and i am creating threading for that. My code is :
public String[,] vpath = new String[3, 7];
public Video[,] video = new Video[3, 7];
public static Thread[,] th = new Thread[3, 7];
public void playclick(object sender, EventArgs e)
{
int i, j;
for (j = 0; j <= 7 - 1; j++)
{
for (i = 0; i <= 3 - 1; i++)
{
if (btnp[i, j].Capture)
{
//play();
th[i, j] = new Thread(new ThreadStart(play));
th[i, j].IsBackground = true;
th[i, j].Start();
}
}
}
}
public void play()
{
int i, j;
for (j = 0; j <= 7 - 1; j++)
{
for (i = 0; i <= 3 - 1; i++)
{
if (th[i, j].ThreadState == ThreadState.Running) // Having problem here
{
if (video[i, j].State != StateFlags.Running)
{
video[i, j].Play();
}
}
}
}
}
So with out that if statement it will run all the videos on single button press. But i want to run the particular video which the thread is in ..
pls help me guys
ThreadState is a bitmask-type property (enum has the [Flags] property, that's always the hint), so you don't check it directly using ==, you only need to check the relevant bit:
if ((t.ThreadState & ThreadState.Running) == ThreadState.Running) { ...
Read here about the meanings of the ThreadState values. From reading that and possibly the whole article, or whole book (highly recommended!) you'll also most likely notice that yours is probably not the ideal approach.
Not knowing your exact endgame though, it;s hard to suggest an exact one.
As to why you are getting an exception, HaemEternal nailed that in his comment. You are only initializing one thread at a time, yet you are checking all of them. A null thread object does not have a ThreadState value.
May I suggest though, that you change your design altogether;
There is no need to constantly check which thread was activated. You can change the signature of the Play() method to accept an Object, and you can pass the correct video to the method using that Object.
public void playclick(object sender, EventArgs e)
{
int i, j;
for (j = 0; j <= 7 - 1; j++)
{
for (i = 0; i <= 3 - 1; i++)
{
if (btnp[i, j].Capture)
{
//play();
th[i, j] = new Thread(new ParameterizedThreadStart(play));
th[i, j].IsBackground = true;
th[i, j].Start(video[i,j]);
}
}
}
}
public void play(object video)
{
Video vid = video as Video;
if (vid.State != StateFlags.Running)
{
vid.Play();
}
}
An even better approach is to encapsulate these three elements in a single object that contains a Video object, a Thread object, and a path string.
If you own the Video class, you might even want to make the Thread and the string values fields of that class.
You might even want to create a field on your buttons of type of this new object, so each button will be associated with a button.
This is much more typical of object oriented design. There is no reason you should maintain four separate identically sized arrays, each of different type.
The answer by #tar gives some hints but the code is wrong (as commented by #Sampath).
This come from the fact that ThreadState is implemented in a questionable strange way:
Normally a bitmask state is implemented using for example bit 1 for state on and the
same bit for the opposite off. This is not the case, in fact, for example, the Running
state has a 0 value, whereas the 1 value is taken by StopRequested.
So it is not wise to do a bit check.
A first approach would be to check for state with an or statement:
while (t.ThreadState == ThreadState.Running ||
t.ThreadState == ThreadState.Background)
Application.DoEvents();
t.Join();
Keep in mind that if you start a process in background you will have the
ThreadState.Background enum value returned and not ThreadState.Running,
this is why I have put both.
The better and simpler approach is:
while (t.IsAlive)
Application.DoEvents();
t.Join();
if (th.ThreadState.Equals(ThreadState.Unstarted))
th.Start();

Categories

Resources