Looping and control flow - c#

Thanks in advance for your help. I'm not a programmer or student asking for homework help, just a technician helping out with work projects.
This one should be easy, but I've brain-farted and I need your help. I've written a GUI control program in C#, but I'll write examples in semi-pseudocode for clarity. I have two boolean control variables and List of void doSomething() methods.
bool ready = true;
bool willLoop = true;
runButton.Click(...) { ...
willLoop is set true/false by a toggle button. I want runButton.Click(...) to iterate through the List of doSomethings(), each of which set ready to false and then back to true when they have finished executing. When ready is set back to true, the next Item in the list will execute and set ready to false and back to true when it is finished. If willLoop is true then the program should iterate though the List over and over again, executing each item. If somebody presses the toggle button and sets willLoop to true or false while the program is executing, I need the program to finish iterating through the list and then either stop(break?) if willLoop is false after the last Item is executed, or iterate again if willLoop is true. All the threading/realtime stuff is handled automatically, I just need a (nested?) looping structure that will use the control variables to do what I need.
I'm only interested in the looping/iterating portion of the code so pseudocode will be fine. The real-world application is controlling an external device with a serial port - each item in the list is a method which sends a command to the device and sets ready to false. When the device finishes moving, it sends a string back and that listener sets ready back to true.
Thanks again for your help.

the structure you need is something like
runButton.Click(...) {
ready = true
while (willLoop)
for each item in list
ready = false
process item
wait until (ready == true)
}
I'm not practical with C# but I guess that Click callback is no asynchronous so as soon as you click the button everything will stop and you won't be able toggle it again. Did you already take care of manage such multithreading issues?

Here is my though on the matter :
public partial class MyFormClass : Form
{
private bool ready = true;
private object readyLock = new object();
private bool willLoop = true;
List<Action> myFunctionList = new List<Action>();
private void button1_Click(object sender, EventArgs e)
{
Queue<Action> remainingActions = new Queue<Action>();
do
{
remainingActions = new Queue<Action>(myFunctionList);
while (remainingActions.Count > 0)
{
lock (readyLock)
{
// In case someone was already in the while,
// but took the last item in the queue.
if (remainingActions.Count == 0) break;
ready = false;
Action currentAction = remainingActions.Dequeue();
currentAction();
ready = true;
}
}
} while (willLoop);
}
}
You'll understand that you can substitute "myFunctionList" by whatever mean you want your function list to be stored.

Related

How to constantly delay the execution of a method

I have a ICollectionVIew named 'CompanyView'.
I also have a Filter for it called 'CompanyFilter'.
And a Textbox bound to a 'SearchCompanyTitle' property.
As I type in a databound textbox, 'CompanyFilter' gets fired with every letter and the 'CompanyView' gets filtered to show relevant results.
That works fine.
Unfortunately the table I'm filtering has about 9 000 rows so there tends to be a notable delay between the moment you press the key on the keyboard and it showing up on screen.
So what I decided to do instead was ensure that the filter was automatically fired when the user had finished typing. Which raises the question of how does the ViewModel know when the user has finished?
What I did is the below;
// This is the property the Textbox is bound to
private string _searchCompanyTitle = "";
public string SearchCompanyTitle
{
get { return _searchCompanyTitle; }
set
{
_searchCompanyTitle = value;
OnPropertyChanged("SearchCompanyTitle");
// After a character has been typed it will fire the below method
SearchCompany();
}
}
// This method is fired by the above property everytime a character is typed into the textbox
// What this method is meant to do is wait 1000 microseconds before it fires the filter
// However I need the timer to be reset every time a character is typed,
// Even if it hasn't reached 1000 yet
// But it doesn't do that. It continues to count before triggering the filter
private async void SearchCompany()
{
bool wait = true;
while (wait == true)
{
await Task.Delay(1000);
wait = false;
}
CompanyView.Filter = CompanyFilter;
}
// And this is the filter
private bool CompanyFilter(object item)
{
company company = item as company;
return company.title.Contains(SearchCompanyTitle);
}
So that's my problem. I need the filter to fire only when the timer hits 1000 and not before. At the same time I need the timer to go back to 0 every time the method is fired by the property. Clearly I'm not doing it right. Any ideas?
Sounds like a perfect candidate for binding Delay:
<TextBox Text="{Binding SearchCompanyTitle, Delay=1000}"/>
One solution could be to use the System.Threading.Timer class.
You can give it a callback to be called when the time set is elapsed.
Put the filter method as the callback and reset the timer's time on every key stroke.
You can find an example here.
--EDIT--
I didn't see that you were using WPF, Sinatr answer is the correct one, just use binding delay

New to threading, need help making a static variable thread safe with background worker

As the title suggests, I'm new to the concept of threading and I'm learning as I go. I'm working on a program as part of a research project involving a 3D printer. I have two pieces of hardware I need to interface with: a small stage that moves up and down, and a force sensor that can detect when an object on the stage makes contact with the sensor which acts as the signal to stop moving the stage. As I said, I'm new to the whole threading concept, so I'm not even sure if I'm designing this correctly, if I should use backgroundworker or the Thread class, how to ensure thread-safety, etc.
I"m writing the program in C# using Windows Forms and decided to use two background worker controls in Visual Studio/.NET Framework, one to monitor the force sensor reading and the other to control the stage moving up and down.
It has to be fast and accurate; the stage needs to stop moving the moment a pre-defined sensor value is detected. I have two static classes, a ZStageControl static class and a ForceSensorControl static class.
ForceSensorControl has a method called UpdateSensor() which returns the current value of the force sensor, and the ZStageControl has a private static bool variable, forceDetected (set to false by default), a public property ForceDetected that gets/sets this variable, and a method called GoodToMove. GoodToMove is defined as follows:
public static bool GoodToMove()
{
if (forceDetected == true ||
Position() < MinHeight ||
Position() > MaxHeight)
return false;
else
return true;
}
My sensor update backgroundworker dowork code is defined as follows:
private void sensorUpdateBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
double currentForceValue;
while (ForceSensorControl.IsConnected() == true)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
try
{
currentForceValue = Double.Parse(ForceSensorControl.UpdateSensor());
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
disconnectForceSensor();
return;
}
if (currentForceValue >= forceSensorStopValue)
{
if (this.ForceDetected != null)
{
this.ForceDetected(this,
new ForceDetectedEventArgs(ZStageControl.Position(), currentForceValue));
}
}
else if (ZStageControl.ForceDetected == true)
ZStageControl.ForceDetected = false;
forceSensorValueLabel.Text = currentForceValue.ToString() + "g";
}
}
}
So as long as the sensor remains connected, continuously loop and update the force sensor vlaue. If it detects the proper force value, it fires the ForceDetected event. If it reads the value as less than the force sensor stop value, but ForceDetected is still set to true, it simply sets to false (since when the force is detected, it will stop the stage from moving and then return it to its default position, so it should reset the force detected variable).
The event code is defined as follows:
public void FormMain_ForceDetected(object sender, ForceDetectedEventArgs e)
{
if (ZStageControl.ForceDetected == true)
return;
ZStageControl.ForceDetected = true;
feedbackRichTextBox.Text += "\nForce Detected at position " +
e.ForceDetectedPosition.ToString() + " with a value of " +
e.ForceDetectedValue.ToString() + "\n";
ScrollToEndOfFeedbackBox(feedbackRichTextBox);
soundPlayer.Play();
}
The thread to move the Z-Stage up or down is defined as follows:
private void zStageMoveBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
ZStageMoveDirections direction = (ZStageMoveDirections)e.Argument;
while (ZStageControl.IsConnected == true)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
System.Threading.Thread.Sleep(zStageSpeed);
if (direction == ZStageMoveDirections.Down)
{
ZStageControl.MoveDown(true);
}
if (direction == ZStageMoveDirections.Up)
{
ZStageControl.MoveUp(true);
}
zStagePositionUpdateLabel.Text = ZStageControl.Position().ToString();
}
}
}
The code that calls the DoWork event for the Z-Stage move is controlled by an if statement that checks if ZStageControl.GoodToMove() is true. So while GoodToMove() returns true, the Z-Stage thread can fire.
The issue I'm having is that I'm not sure if I'm designing this right, if I'm using the backgroundworker properly, and I know my variables are not thread-safe because at certain points GoodToMove() returns true and other times it returns false, even though there is clearly no force being detected. It seems to have a mind of its own. I just know nothing about thread-safety. Should I simply use the THread class instead of the background worker, is there a certain way to ensure the forceDetected variable/GoodToMove() method operates properly across these threads?
I think your approach is inherently flawed.
You seem to be designing a system with a constantly looping monitor and then a check of that monitor when you want to execute a "move."
This is inherently problematic because you've created a race condition between your safety check operation and your move operation.
Consider this:
1 // check if move is ok -- PASS
(async) // move suddenly becomes not ok!
2 // move is executed
Instead you should think about this problem as entirely synchronous (as validation checks and executions should be entirely atomic). Whenever a move is requested you should check if it's permitted and then decide whether or not to execute.
1 // exclusive lock
2 // check if move is ok -- PASS
3 // execute move
4 // release lock

Determine who fired an event

Background:
In my winforms form, I have a Checked ListView and a "master" checkbox called checkBoxAll.
The behaviour of the master is as follows:
If the master is checked or unchecked, all ListViewItems must change accordingly.
If the user unchecks a ListViewItem, the master must change accordingly.
If the user checks a ListViewItem, and all other ListViewItems are checked aswell, the master must change accordingly.
I have written the following code to mimic this behaviour:
private bool byProgram = false; //Flag to determine the caller of the code. True for program, false for user.
private void checkBoxAll_CheckedChanged(object sender, EventArgs e)
{
//Check if the user raised this event.
if (!byProgram)
{
//Event was raised by user!
//If checkBoxAll is checked, all listviewitems must be checked too and vice versa.
//Check if there are any items to (un)check.
if (myListView.Items.Count > 0)
{
byProgram = true; //Raise flag.
//(Un)check every item.
foreach (ListViewItem lvi in myListView.Items)
{
lvi.Checked = checkBoxAll.Checked;
}
byProgram = false; //Lower flag.
}
}
}
private void myListView_ItemChecked(object sender, ItemCheckedEventArgs e)
{
//Get the appropiate ListView that raised this event
var listView = sender as ListView;
//Check if the user raised this event.
if (!byProgram)
{
//Event was raised by user!
//If all items are checked, set checkBoxAll checked, else: uncheck him!
bool allChecked = true; //This boolean will be used to set the value of checkBoxAll
//This event was raised by an ListViewItem so we don't have to check if any exist.
//Check all items untill one is not checked.
foreach (ListViewItem lvi in listView.Items)
{
allChecked = lvi.Checked;
if (!allChecked) break;
}
byProgram = true; //Raise flag.
//Set the checkBoxAll according to the value determined for allChecked.
checkBoxAll.Checked = allChecked;
byProgram = false; //Lower flag.
}
}
In this example, I use a flag (byProgram) to make sure an event was caused by the user or not, thereby preventing an infinite loop (one event can fire another, which can fire the first one again etc. etc.). IMHO, this is a hacky solution.
I searched around but I couldn't find a MSDN documented method to determine if an User Control Event was directly fired thanks to the user. Which strikes me as odd (again, IMHO).
I know that the FormClosingEventArgs has a field which we can use to determine if the user is closing the form or not. But as far as I know, that is the only EventArg that provides this kind of functionality...
So in summary:
Is there a way (other than my example) to determine if an event was fired directly by the user?
Please note: I don't mean the sender of an event! It won't matter if I code someCheckBox.Checked = true; or manually set someCheckBox, the sender of the event will always be someCheckBox. I want to find out if it is possible to determine whether it was through the user (click) or by the program (.Checked = true).
Aaand also: 30% of the time it took to write this question was to formulate the question and the title correctly. Still not sure if it is a 100% clear so please edit if you think you can do better :)
No, there's no practical way to determine whether the change came from GUI or was done by program (in fact, you could analyze the callstack - but that's not recommended because it's very slow and error-prone).
BTW, there's one other thing you could do instead of setting byProgram. You could remove and add the event handler prior or after, respectively, change your controls:
checkBoxAll.CheckedChanged -= checkBoxAll_CheckedChanged;
// do something
checkBoxAll.CheckedChanged += checkBoxAll_CheckedChanged;
Instead of using the changed event, you could use the clicked event to cascade the change through to the relevant controls. This would be in response to a user click, and not the value being changed programatically.
This is something I come across quite a lot and what I tend to try do is not split it between user interaction vs program interaction - I use more generic code i.e. the UI is being updated and doesn't require any events to be handled. I usually package this up through BeginUpdate/EndUpdate methods e.g.
private int updates = 0;
public bool Updating { get { return updates > 0; } }
public void BeginUpdate()
{
updates++;
}
public void EndUpdate()
{
updates--;
}
public void IndividualCheckBoxChanged(...)
{
if (!Updating)
{
// run code
}
}
public void CheckAllChanged(...)
{
BeginUpdate();
try
{
// run code
}
finally
{
EndUpdate();
}
}

conditional check to wait for favourable condition

i have a condtion if (!e.ComponentUp) ,if its true then i need to wait until it Up what check i can give here
I did this code but its not working
if (!e.ComponentUp)
{
do
{
while (e.ComponentUp);
}
}
Your code cannot work.
First, if the predicate is false, then the while loop will exit immediately. You would need to loop on the negation.
Second, unless it's volatile and being changed asynchronously, the loop won't end.
Third, this sort of polling will max out the CPU.
Use an event.
You could create an event on your Component called something like 'UpChanged' and subscribe to the event. When you come to the code that can only run when the component is in the 'Up' state you could set a flag that indicates your 'task' is waiting for the up state to change. Something like this:
//When you initialize
var e = ...;
e.UpChanged += new EventHandler(Component_UpChanged);
bool waitingForUp = false;
//The code snippet that is waiting for up to be enabled
if (!e.ComponentUp)
waitingForUp = true;
else
DoWorkHere();
//The delegate
void Component_UpChanged(object sender, EventArgs e)
{
if (e.ComponentUp && waitingForUp)
DoWorkHere();
waitingForUp = false;
}
Why don't you use events ? Is that a 3rd party component ?

C# WinForms: Waiting for a button press inside an infinite loop

I'm making a simple Guess-The-Number game with a GUI. I need to wait on a loop waiting for the user to input a number in a text box and press "OK". How do I wait for an event inside a loop?
Note: I don't want message boxes. This is done in the main window, hence the need to wait for input.
EDIT: I should have explained myself better. I know that there's a loop inside the GUI. What I want is another loop inside a method. Maybe there's a better way to do this. I could code stuff inside the button's event handler, now that I think about it. Although I'd need global variables. Whataver, I'll think about it, but I hope my question is clearer now.
EDIT 2: Sorry that my question wasn't clear and the edit didn't do much help. First of all, the code is too big to be posted here. I'd probably have to post a screenshot of the GUI, so it wouldn't be of much use. Basically, I have two fields, "Max number" and "Number of allowed guesses". The user enters these two and clicks "Play". A new panel becomes available, with a text box and a "Guess" button. The user enters a guess, and the program checks to see if it's correct.
The purpose of the second infinite loop is to avoid global variables. See, each time the user clicks "Play", the game has to generate a new random number as the correct guess. If everything is done inside a method, no problem. But if the "Guess" button's event handler is called multiple times, the number has to be stored as an instance variable of the Form. Sure, it's not big deal, but I think the number should be a property of the method directing the current game, not of the Form.
I'd also have to keep track of the remaining number of guesses outside of the method. Again, it's no big deal. I just want to avoid globals if I can.
Again, I'm sorry that my question wasn't too clear. I'm kind of tired, and I didn't feel like writing too much. If this still isn't clear, then don't bother. I'll think of something.
C# automatically loops infinitely waiting for events until your form is closed. You just need to respond to the button click event.
Jason Down's suggestion is wise, create a new GuessingGame class and add it to your project. I know you're worried about "global variables" (which everyone is taught in school never to use unless you absolutely have to), but think about your design specifications for a minute.
But if the "Guess" button's event handler is called multiple times, the number has to be stored as an instance variable of the Form. Sure, it's not big deal, but I think the number should be a property of the method directing the current game, not of the Form.
As an alternative, store an instance of your GuessingGame class in the form. This is not a global variable! You said so yourself, the point of the game is keep track of the guesses and generate new numbers to guess every time "Play" is clicked. If you store an instance of the game in the form then open another form (e.g. a Help or About box), then the game's instance would not be available (thus, not global).
The GuessingGame object is going to look something like:
public class GuessingGame
{
private static Random _RNG = new Random();
private bool _GameRunning;
private bool _GameWon;
private int _Number;
private int _GuessesRemaining;
public int GuessesRemaining
{
get { return _GuessesRemaining; }
}
public bool GameEnded
{
get { return !_GameRunning; }
}
public bool GameWon
{
get { return _GameWon; }
}
public GuessingGame()
{
_GameRunning = false;
_GameWon = false;
}
public void StartNewGame(int numberOfGuesses, int max)
{
if (max <= 0)
throw new ArgumentOutOfRangeException("max", "Must be > 0");
if (max == int.MaxValue)
_Number = _RNG.Next();
else
_Number = _RNG.Next(0, max + 1);
_GuessesRemaining = numberOfGuesses;
_GameRunning = true;
}
public bool MakeGuess(int guess)
{
if (_GameRunning)
{
_GuessesRemaining--;
if (_GuessesRemaining <= 0)
{
_GameRunning = false;
_GameWon = false;
return false;
}
if (guess == _Number)
{
_GameWon = true;
return true;
}
else
{
return false;
}
}
else
{
throw new Exception("The game is not running. Call StartNewGame() before making a guess.");
}
}
}
This way, all the data related to the game is encapsulated within the class. Hooking up the events is easy in the codebehind of the form:
GuessingGame game = new GuessingGame();
private void btnPlay_Click(object sender, EventArgs e)
{
int numberOfGuesses = Convert.ToInt32(txtNumberOfGuesses.Text);
int max = Convert.ToInt32(txtMax.Text);
game.StartNewGame(numberOfGuesses, max);
}
private void btnGuess_Click(object sender, EventArgs e)
{
int guess = Convert.ToInt32(txtGuess.Text);
bool correct = game.MakeGuess(guess);
if (correct)
lblWin.Visible = true;
if (game.GameEnded)
{
// disable guess button, show loss label
}
}
You should probably look for a book to actually learn windows programming.
The very basics:
1) There is already an infinite loop deep down in the windows code somewhere. Any windows program is constantly looping and scanning for input.
2) Once input is found, this loop fires off an Event.
3) Your mission, should you choose to accept it, is to write event handlers to handle those events.
you are most likely doing it wrong as it has already been pointed out, but you can use this
Application.DoEvents();
to process events when you are on an actual loop
to do it the right way
- don't use a loop
- use an edit box for the input, then a button
- implement the button onclick event
Yes, and What if I am waiting for Speech events, it could happen anytime event when a function is running, I need to handle that without recursively call a function

Categories

Resources