how to implement a step-by-step button in c#? - c#

I implemented an algorithm in c# and I want to make a gui for it, in my gui i want to put a button that with any click the gui shows a step forward in algorithm, so i think i need to put something like pause? statements in my code that with any click it can resume. how should i do that? or is there any other suggestion for implementing this idea?

It sounds like really you need to turn your algorithm into a state machine - instead of actively "pausing" it, you would actively "advance" it.
You may find iterator blocks useful... if your algorithm is pretty much in one method at the moment, you may be able to change it to insert a yield return statement at the end of each logical step, returning some indication of the current status.
That's not an entirely normal use of iterator blocks, but it could be the simplest way forward here. Your UI would call GetEnumerator once at the start, and then MoveNext() each time the button is clicked (followed by accessing the Current property to get at the current state). Don't forget to dispose of the iterator when you've finished with it.

Run your algorithm in a thread different than your UI thread.
For synchronization, create some kind of wait handle, e.g. an AutoResetEvent.
The "pause" statement you are looking for is myWaitHandle.WaitOne() (called by your algorithm thread).
Allow the algorithm to continue by executing myWaitHandle.Set() in your UI thread.
This method has the advantage that your user interface stays responsive while a step of your algorithm is being executed.

You have to decide what is a "step" in your algorithm. Then you need to rewrite your algorithm and wrap it in a class with the following interface:
interface ISteppedAlgorithm
{
bool NextStep(); //returns if the algorithm is finished
IStepResult LastStepResult {get;}
}
and now your GUI will drive the algorithm prepared in this way. After you press the button, the NextStep() method will be invoked. If it returns false disable the button (or indicate in whatever other way that its all done). Then read the LastStepResults and update the display.h

From your description I think you want a "wizard" that is basically an application with previous / next buttons.
http://www.differentpla.net/content/2005/02/implementing-wizard-c
However If you just have a long running task and want to have some breaks in it, there are different ways to solve it.
Sperate you task in multiple methods.
After a method is completed, wait until the user hit's next.
Let the task run in it's own thread and at a point where it should wait let the thread sleep until you set a specific var:
LongRunningMethod1();
while(continue1 == true)
{
Thread.Sleep(50);
}
LongRunningMethod2()
while(continue2 == true)
{
Thread.Sleep(50);
}
Set continue1 and 2 to true in your main thread to let the background thread do his work.

If it's just to "observe" the state of the algorithm as it develops, why not add some events (probably just one at the end) and let the event handler store an array of the states. The UI can simply iterate forward\backwards over this as and when needed.

Related

C# WinForms - Determine when void method returns

I'm trying to figure out how to determine best practice when a void method returns for a program I'm working on. Basically the program has a call to a 3rd party grid to tell it to save the contents to an Excel sheet. The method to save the grid is a void method grid.SaveExcel(string filename, ...). I was thinking it would require the use of the await and async commands but have read in multiple places that this isn't best practice. I'm curious how you would go about doing this correctly as I'm a noob in terms of await, async, Lamda, Invoke, Action, Task, delegate stuff in C# and think I'm just confusing myself. I basically know how to open SQL connections, populate a grid, handle button event handlers, build basic classes, etc (very basic stuff).
I basically want to call the grid.SaveExcel method and then update a progress bar while I'm waiting for the saving of the grid to complete. Once it completes, I want to move on to the next few lines of code. Can someone help point me in the right direction and show me some code to attempt to accomplish this? Thanks in advance!
You can invoke your function on a BackgroundWorker.
https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx
This class will then automatically raise an event on completion, as well as allow you to report progress during execution that will also raise events on your object invocation thread. Here's a run through of setting one up:
https://www.dotnetperls.com/backgroundworker
All of this is assuming you do indeed need this process to be asynchronous.If you do not, you can simply invoke your save, and then immediately follow it with whatever post-save functionality you desire. If the save takes less than 200ms, you'd be better off just inlining it with the UI.

Coroutine to run SQL in Unity3d

I'm trying to understand Unity coroutines deeper. They can block execution yielding null or wait, but they are really not new threads.
In my case Unity should read info from database, which can take some time. And this is synchronous operation. This single line of code may potentially block execution for seconds.
Part of me tells just to start new thread. But I'm wondering whether it can be achieved with Unity-style coroutines.
private IEnumerator FetchPlayerInfo(int id)
{
// fetch player from DB
using (var session...)
{
// this line is NHibernate SQL query, may take long time
player = session.QueryOver<Player>()...;
}
// raise event to notify listeners that player info is fetched
}
I just don't see where to put yield. Does anyone know?
Thx in advance.
You can only return yield instructions when the control flow is in your own coroutine. If you have to run a long synchronous operation, and it has no asynchronous API (which is something to be expected from a database), then you really better off with starting another thread.
However, be aware that using other threads in Unity is a little bit tricky: you won't be able to use any of Unity's API and you'll have to check in the main thread for when the worker thread has a result ready. Consider looking at ready solutions, such as Loom.
You can think of yielding as breaking a large task into chunks. After each chunk you yield to let other things happen, then come back and do another chuck. In your case you would load X number of rows each chunk until all your data is loaded.

BackgroundWorker problems on exit

I am having a bit of a conundrum here, and would like to know a couple of things:
Am i doing this wrong?
What is the expected behaviour of a backgroundworker in different scenarios...
If possible, get an answer as to why i am getting specific behaviour would be nice...
For point 1, and ultimately 3 as well, i will explain what i am doing in Pseudo-Code so that you have the details without actually spitting out thousands of lines of code. While i write this post, i will look at the code itself to ensure that the information is accurate as far as when and what is happening. At the very end, i will also detail what is happening and why i am having issues.
Pseudo-Code details:
I have a main UI thread (WinForms form), where after selecting a few configuration options you click a button.
This button's event does some preliminary setup work in memory and on the file system to get things going and once that's done fires off ONE backgroundworker. This backgroundworker initializes 5 other backgroundworkers (form scope variables), sets their "Done" flags (bool - same scope) to true, sets their "Log" vars to a new List<LogEntry> (same scope) and once that's done calls a method called CheckEndConditions. This method call is done within the DoWork() of the initial backgroundworker, and not in the RunWorkerCompleted event.
The CheckEndConditions method does the following logic:
IF ALL "Done" vars are set to True...
Grab the "Log" vars for all 5 BWs and adds their content to a master log.
Reset the "Log" vars for all 5 BWs to a new List<LogEntry>
Reset the "Done" vars for all 5 BWs to False.
Call MoveToNextStep() method which returns an Enum value representative of the next step to perform
Based on the result of (5), grab a List<ActionFileAction> that needs to be processed
Check to ensure (6) has actions to perform
If NO, set ALL "Done" flags to true, and call itself to move to the next step...
If YES, partition this list of actions into 5 lists and place them in an array of List<ActionFileAction> called ThreadActionSets[]
Check EACH partitioned list for content, and if none, sets the "Done" flag for the respective thread to true (this ensures there are no "end race scenarios")
Fire off all 5 threads using RunWorkerAsync() (unless we are at the Finished step of course)
Return
Each BW has the exact same DoWork() code, which basically boils down to the following:
Do i have any actions to perform?
If NO, set my e.Result var to an empty list of log entries and exit.
If YES, loop for each action in the set and perform 4-5-6 below...
What context of action am i doing? (Groups, Modules, etc)
Based on (4), what type of action am i doing? (Add, Delete, Modify)
Based on (5), perform the right action and log everything you do locally
When all actions are done, set my e.Result var to the "log of everything i've done", and exit.
Each BW has the same RunWorkerCompleted() code, which basically boils down to the following:
TRY
From the e.Result var, grab the List<LogEntry> and put it in my respective thread's "Log" var.
Set my respective "Done" var to true
Call CheckEndConditions()
CATCH
Set my respective "Done" var to true
Call CheckEndConditions()
So that is basically it... in summary, i am splitting a huge amount of actions into 5 partitions, and sending those off to 5 threads to perform them at a faster rate than on a single thread.
The Problem
The problem i am having is that i often find myself, regardless of how much thought i put into this for race scenarios (specifically end ones), with a jammed/non-responsive program.
In the beginning, i had setup my code inefficiently and the problem was with End Race Scenarios and the threads would complete so fast that the last call made to CheckEndConditions saw one of the "Done" vars still set to false, when in fact it wasn't/it had completed... So i changed my code to what you see above which, i thought, would fix the problem, but it hasn't. The whole process still jams/falls asleep, and no threads are actually running any processing when this happens which means that something went wrong (i think, not sure) with the last call to CheckEndConditions.
So my 1st question: Am i doing this wrong? What is the standard way of doing what it is i want to do? The logic of what i've done feels sound to me, but it doesn't behave how i expect it to so maybe the logic isn't sound? ...
2nd question: What is the expected behaviour of a BW, when this scenario occurs:
An error occurred within the DoWork() method that was un-caught... does it fire off the RunWorkerCompleted() event? If not, what happens?
3rd question: Does anyone see something obvious as to why my problem is occurring?
Thanks for the help!
Reposting my comment as answer per OP's request:
The RunWorkerCompleted event will not necessarily be raised on the same thread that it was created on (unless it is created on UI thread) See BackgroundWorker RunWorkerCompleted Event
See OP comments for more details.

correct way to handle exit from infinite loop in c#

In my apps i find the need to have infinite while loops mostly to do some repeated action continuosly unless another event takes place so what i am doing is
while(chkFlag)
{
//do something here which takes around 30 seconds
}
Then in some other event say a button press to stop the loop i do
chkFlag = false;
Now this does the work but the problem is this does not stop the loop instantaneously as the chkFlag is checked only after the complete execution of the loop takes place. So can anybody please tell me how i can exit a loop instantaneouly based on an event.
The "blocking" code should likely be moved into some kind of worker thread (which can be terminated and/or have the results discarded). If using a BackgroundWorker (recommended, as it makes this simple), there is built-in support to handle a cancel operation.
Then the loop can either be moved inside the BackgroundWorker or the completion (RunWorkerCompleted) event of the worker can trigger the next worker to start (which causes an implicit loop).
Happy coding.
There are more "aggressive" ways of terminating/signaling a thread; but suggesting these would require more information than present.
you can't make it exit instantly (well, you could run the loop in a new thread and Abort it, if it's really safe to have an exception thrown from it at any time), but you could scatter if(!chkFlag) break; at various points within the loop that it's safe to exit. The usual method of doing this is to use a BackgroundWorker or a CancellationToken rather than a simple boolean flag.
Of course, it will still need to be run in another thread so that the button event can run at all. BackgroundWorker will take care of this automatically.
You are looking for break;.
I suppose, based on the anonymous downvoter, I should elaborate. The syntax above will immediately exit the loop that you are in (it works in the other loops as well; it's probably worth noting that continue exists to restart the loop at the beginning, which will perform increment logic in for-style loops).
How you decide to execute break is up to you, but it must be within the loop itself.
There are multiple approaches to this, such as placing checks for the event within the loop and calling break; if it occurs. Others have noted the other approaches with BackgroundWorkers and Cancel Tokens (this is preferred given it's not within the loop).
Is it possible you want to use a new thread? What are you doing for 30 seconds in the loop. Sounds like maybe there's a better design to use.
Have you considered using a timer, or setting up an event handler?

How can a function be triggered with an event?

I have an application wherein I would like a function to be executed in the same thread when an event is fired. For example:
SomeCode()
{
// Do something...
// Fire event to run SomeOtherCode().
}
SomeOtherCode()
{
// Do something else...
}
I do not want to simply call the function because it will hold things up. SomeOtherFuction() needs to be executed in the same thread because it needs to access the form controls, and I need it to begin execution from an event trigger firing. I am using Microsoft Visual C# 2008 Express Edition. Thanks.
::: EDIT:::
Additional Details: The bottom line is that the contrustor of my form application is taking far too long to complete, and it is causing a significant delay, from when the user launches the application to when the application window appears on the display. This is not a problem on faster computers, but on slower computers it is a big problem. I need to exit the contrustor as soon as possible, thus allowing the framework to draw the application window, and continue initialization outside the constructor. (All essential items would still be initialized inside the constructor.)
An event-triggered function call would be ideal. I would prefer not to use a timer. Interlacing the affected code with Invokes is impractical in my situation and would require much more time to implement than I have to work on this. A simple example of an event-driven function call is all I'm really looking for. Thanks.
From your posts it's seems like you're confusing a few issues. The standard pattern in .Net is for events to run synchronously. The following lines are essentially identical in terms of when they execute.
Option #1
SomeCode();
SomeOtherCode();
Option #2
SomeEvent += delegate { SomeOtherCode(); }
...
SomeCode();
SomeEvent(this,EventArgs.Empty);
If you want to unblock the UI thread and run the code later you'll need to use some mechanism to delay the running of the SomeOtherCode function. The easiest way to do this in a WinForms application is to use a WinForms Timer instance. This will raise an event on the UI thread at a later point in time that you can respond to. It also won't block the UI thread during this time allowing your form to continue processing.
You seem to be asking to run SomeOtherCode() later.
You can call BeginInvoke (either from the UI thread or from any other thread) to queue a function to run during the next message loop:
BeginInvoke(new Action(SomeOtherCode));
It seems that you would want to add an event to the class that exposes the SomeCode method. Then, the class that implements the SomeOtherCode method would attach an event handler that calls the SomeOtherCode method.
It's completely viable to have this done in one class, in case you have some sort of state model where you want to add/remove the call depending on some other logic.
I think you want to put SomeOtherCode into a Task or BackgroundWorker, which would then synchronize with the UI thread to send it updates.
I recently posted on my blog a class that makes updating the UI from a Task as easy as from a BGW. I do recommend using Task rather than BackgroundWorker.
Simialr to what Stephen said, I would recommend that you move as much of that initialization code to a background thread or task. Let the background thread do as much work as possible, then send the necessary window updates to your UI thread via Action<>'s. Here's some quick psuedo-sample code:
protected void LoadMyListInBackground(object state)
{
List<string> myList = Databse.FetchMyList(myParameters); // This take a while, so the UI thread isn't waiting
ShowMyList(myList);
}
protected void ShowMyList(List<string> theList)
{
if(InvokeRequired)
Invoke(new Action<List<string>>(ShowMyList, theList);
else
{
foreach(string item in theList)
myListBox.Items.Add(item);
}
}
In this example the UI thread is free to keep drawing your window while the background thread does the lengthy database work. The problem is, even if you fire an event outside of your constructor, and that event occurs on the UI thread and takes a long time, the user might see the window but that window is going to 'freeze' and possibly appear to be 'crashed' to the user. This technique prevents that and provides a better user experience.

Categories

Resources