I write application that simulates pathfinding algorithms. I can run algorithm or step it (like debugging). But when I run algorithm I am not able to draw any changes until the algorithm is done.
private void menu_run_Click(object sender, EventArgs e)
{
algorithm.Reset();
while (algorithm.status == Algorithm.Status.Searching )
{
algorithm.MakeStep();
if (this.speed != 0) System.Threading.Thread.Sleep(this.speed);
drawing_area.Invalidate();
}
}
I guess it's because I'm doing it all in one cycle and system is not able to handle new messages (events) that I trigger.
So how should I change my code to be able to redraw the changes after each iteration?
Should I somehow call Message Dispatcher to let him handle new messages after each iteration?
Should I create own messages and do all the work inside cycle using messages?
Or is there any more elegant way I?
There are a lot of different ways to do this.
Arguably the easiest for your situation would be to use a System.Windows.Forms.Timer object on your form instead of calling Sleep() in an indefinite loop.
Add the timer to your form from the toolbox.
Set its Interval property to this.speed.
Set its Enabled property to true.
Subscribe to the timer's Tick event.
The handler would look something like this:
private void OnTimerTick(object sender, EventArgs e)
{
if (algorithm.Status == Algorithm.Status.Searching)
{
algorithm.MakeStep();
drawing_area.Invalidate();
}
}
You'll probably need to slightly rearrange your control logic (where the algorithm is started and stopped). You can use the Enabled property of the timer for this if it helps.
Another solution would be to create an object with a background thread which raises periodic events as the algorithm runs, and the form would subscribe to those events and redraw accordingly (don't forget to use Invoke on the events since they'll be coming from a non-GUI thread).
There's also BackgroundWorker which you could look into as a third alternative. But I think the timer will be easiest for you.
Related
I'm trying to have serial data sent out continuously while a check button is being pressed in Visual Studio. So far, this is what I've come up with:
private void checkBox1_CheckedChanged_1(object sender, EventArgs e)
{
while (checkBox1.Checked)
{
serialPort1.Write("D");
Task.Delay(100);
if (checkBox1.Checked != true)
{
break;
}
} `
For some reason, whenever I launch the program and check the box, the program
freezes. I can't exit the program or minimize it or anything. It just stops in its tracks.
The user interface in Windows is based on messages. Your while loop runs in the thread where those messages would be handled. While your code runs, no messages are handled. The user interface cannot be redrawn and cannot react to user input.
Better approach: Use a Timer component. The Tick event of the Timer will be executed every n milliseconds according to the Interval property of the Timer. In the Tick event, you can check the Checkbox state and then do something or not depending on whether the checkbox is checked.
This is a good approach if "do something" is a very short activity. For longer activities, you nee a bit more complex setup that is beyond the scope of a SO question unless you provide more details.
You're blocking the UI thread because your event is being handled synchronously. Refer to this answer for some tips on async/await programming: How do I update the GUI from another thread?
I am making my first ever C# GUI. It is using a BackgroundWorker to run a computationally heavy simulation. Periodically, the simulation reports (through the ProgressChanged event) a sizable body of information that needs to be displayed in the GUI.
The GUI is divided into controls and I want each control to know how to 'update itself'.
In my research, I found lots of ways I might be able to do this.
I could think of was to have the method bougnd to ProgressChanged call an update method on each part of the GUI.
I could Invalidate the GUI and bind each controls update method to the Validating event.
I could bind each control's update method to the ProgressChanged event.
I could have each control implement the INotifyPropertyChanged interface (but I'm skeptical that this would work)
Of all of these options, which one is best practices for updating the entire GUI upon the ProgressChanged event? (or am I out in left field?)
From comment:
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
Simulation simulation = new Simulation();
while(true)
{
simulation.RunIteration();
backgroundWorker.ReportProgress(-1, simulation);
}
}
You should not have to do anything special.
Your ProgressChanged handler can 'unpack' the data and set the relevant properties of controls. Invalidation and repainting is automatic and it runs on the GUI thread.
You should only be careful with updating 'too often'. How often is too often depends on the volume of data, the handler should be finished well before the next update. If not, build in some throttling mechanism.
ProgressBar is the method I recommend. If the data you want to send to the GUI is text then you could have a rich textbox or just a regular textbox and pass text to it when the progress bar is changed:
public void SomeThread_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
/* Update progress bar */
ProgressBar.Value = (e.ProgressPercentage);
if (e.UserState != null)
{
TextBox.Text += (string)e.UserState;
}
}
For other forms of data you could include an If statement which does X when the progress bar is given a certain value.
But ithout knowing more about what you're specifically trying to do I'm afraid I can't provide any more help than that.
In windows form on click on Next I need to display other form and start some processing. Am coding in .Net C#
The problem is before the form is complete visible, the method gets triggered and the processing starts and the UI looks like it crashed. Processing started even before controls are loaded. and once processing is done all controls are visible.
The actual output must be all controls should be loaded and then processing must start.
I need to call the method to start processing after the form (user control) is visible and is loaded completely.
I tried this and this, but no luck.
Added code:
private void FeatureRemovalControl_Load(object sender, EventArgs e)
{
pictureBox2.Image = Properties.Resources.line;
prgbar.Value = 0;
//code to load images and some other stuff
StratProcess();
}
You're calling StartProcess (which seems to block until it's finished) from your UI thread. Because WinForms repaints occur on that thread, nothing is painted, and it appears that your process has hung. You should look at using a BackgroundWorker, or other way to call StartProcess asynchronously.
Best way, if you ask me, would be to start processing asynchronously, so that you maintain full control of the UI and process at the same time.
http://msdn.microsoft.com/en-us/library/2e08f6yc(v=vs.71).aspx
Try calling that method at the end of the FormLoad event, the control should have finished loading by then. If it hasn't that you may need perform some checks and possibly create a custom event that fires when you're happy that it is ready.
Another solution is to have a button that the user must press to trigger the processing, which they will only be able to click once everything has loaded
EDIT: The reason it look's like it's happening is because you're starting the process in one of the control's load method, which I assume is not the last control to load, so it's starts processing before the other controls are given a chance to load. Make StratProcess method public and call it in the FormLoad method of the parent form instead, like so:
private void ParentForm_Load(object sender, EventArgs e)
{
FeatureRemovalControl.StratProcess(); // Should it be called StartProcess instead?
}
Beware though this is still doing the processing on the UI thread, so the screen may appear to 'hang' whilst this is happening so I advise you move it to a background thread as others have suggested.
I have some WinForms in my application.
On some form , I am loading other forms which have lot of data to show.
So when I click a button to load these forms they take, 9-10 seconds to load,
I wana improve this. I have heard about Background thread but don't know how to use this.
Means on the button click what should i do so that I can see my form imidiately and the processing is done by background thread ?
Please guide me so that I can improve my UI.
Getting the form to show immediately, should be fairly simple and you don't need a background thread to do it.
My guess is that you are retrieving all that data prior to loading the form or you are retrieving the data on the same thread that loads the form. You should be able to call the form with the data it needs to retrieve the rest of the data (such as ID's).
Then you just need to find a way for the data processing to happen on a thread other than the thread that creates the form.
This may not be the most elegant solution, but it gets the job done. It uses a System.Windows.Forms.Timer
private void Form1_Load(object sender, EventArgs e)
{
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Stop();
//fill controls with data
}
If you have several sets of data that you are retrieving, you may want to consider setting up a queue of tasks to retrieve each set.
Any way that you do it. Make sure to disable any buttons(or other ui) that could cause errors if the data is not loaded.
Edit: It should be noted that winform controls don't always play nice with threads. The nice thing about the System.Windows.Forms.Timer (as opposed to System.Timers.Timer)is that it designed to play nice with controls.
BackgroundWorker are easy to use. Mainly you subscribe to DoWork event, this is where you'd put your work that will be done in a seperate thread. And you also subscribe to RunWorkerCompleted event. This will get raised when your DoWork has completed.
In this method you'd simply bind the data fetched by the DoWork method.
You can use the DoWork eventarg to pass data between DoWork and RunWorkerCompleted.
You can also cancel the work and also the you can use the RunWorkerCompleted eventArg to get the data from the DoWork and also inspect the Error property for exception handling.
IF you have lots of data, you can use a batching process, to get data per batch and display them into your UI. You can show how many total records will be fetch and the progress of it 100 out of 1000 have been loaded, 200 out of 1000 have been loaded etc, to keep the user informed. You could also provide a Cancel option so the user can stop the fetch.
In your button click you'd simply call myBackgroundWorker.RunWorkerAsync().
this will call your DoWork Handler which will be done in a seperate thread not the main UI Thread, so your UI will not FREEZE during the background worker DoWork.
The backgroundworker also support report progress.
If your problem is the main form Freezing, what you need is to collect the data on a separated Thread than the Main form is running.
To achieve that, you can do something like this:
BackgroundWorker worker;
public Form1()
{
InitializeComponent();
worker = new BackgroundWorker();
}
private void button1_Click(object sender, EventArgs e)
{
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerAsync();
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
//Collect data and open your second form here;
}
I'm running a data import, using a Windows form to kick off the import and show progress.
I've got this whole thing so nice and user friendly, with major and minor progress bars and everything... but just one problem... the form refresh keeps going AWOL.
I have a call to Form.Refresh() every time I update my labels/progress bars, and it usually starts off working. But if ever I need to break into debug mode, just to hand-hold the import a bit, the Refresh() call stops working, and sometimes even if I'm running without Debug mode, at some unpredictable point the same thing happens: the labels and progress bars do not get updated, and if you hide the form and reopen it, the form does not repaint at all - it just shows up entirely white.
Why, oh why, does Form.Refresh() stop working, and how can I fix this?
It sounds as if the import runs on the UI thread, which means that this thread is blocked, preventing the form from repainting itself. A better approach would be to use a BackgroundWorker component, do the import in the DoWork event handler and use the ProgressChanged to update the UI.
Example:
private void StartImport()
{
backgroundWorker.WorkerReportsProgress = true;
backgroundWorker.RunWorkerAsync();
}
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// do some work simulating a lenghy process which occasionally
// reports progress with data back to the caller
for (int i = 0; i < 100; i++)
{
Thread.Sleep(200);
backgroundWorker.ReportProgress(i, "Item No " + i.ToString());
}
}
private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
listBox.Items.Add(e.UserState.ToString());
}
Using this approach you will typically not need to call Refresh to force a repaint of the form.
You may want to change your code into using BeginUpdate and EndUpdate, like so:
Control.BeginUpdate();
// Do something to the control, e.g. add items or whatnot
Control.EndUpdate();
This way Refresh shouldn't be necessary.
AFAIK constantly calling Refresh is really a hack and should be avoiding, as it stresses the CPU quite a bit (it has to refresh everything instead of just the things which are changed).
Edit: If the form starts being white, it seems the drawing code is not been called at all, which indicates it's somewhat not responding.
I'd check the code for anything that can deadlock or otherwisely hang.
You could use observer pattern..in short if anything changes in model observer pattern will make sure that change is visible on form..
google it for some examples..
Depending on what .NET framework you're using, you can use the Task.Run approach:
private void btnShowProgress_Click(object sender, EventArgs e)
{
progressBar1.Value = 0;
Task.Run(() =>
{
for (int i = 0; i <= 100; i++)
{
Thread.Sleep(100);
progressBar1.Invoke(new MethodInvoker(delegate { progressBar1.Value = i; }));
}
});
}
Task.Run info
Using invoke with controls
The solution may not be the best practice but it definitely works for small applications.
In Form1 create a bool to check to see if the form is closed.
public bool formclosed = false
Then in Form2 on the Form Closing Event Handler add
formclosed = true
also in the Form2 after
InitializeComponent();
add
formclosed = false;
In Form1 create a timer.
In the timer1.Tick event handler say
private void timer1_Tick(object sender, EventArgs e)
{
if(formclosed == true)
{
Application.Restart();
}
}
This will restart the application and refresh everything ... I also had my text saved to the Properties.Settings.Default so everytime the application started the default settings would show.
I created an initial version of a Progress control using a BackgroundWorker. The Progress control computed and displayed nice things like Estimated Duration, Estimated Time to Completion. Each statistic was displayed by custom control based on a Label control. The Progress control worked in my production code.
Then I made some changes to the Progress control. I switched from basing my custom statistics controls from Label to Panel. I successfully ran all my tests (using NUnit). Then, I created a Test Windows Forms app. The Progress control successfully worked in the Test Windows Forms app.
When I ran my production Windows app with the updated Progress control it didn't display the statistics.
I tried Thread.Sleep(N), Form.Refresh(). None of those worked to update the statistics.
I eventually called Control.Invalidate() on each Statistic control. The Invalidate caused OnPaint to be called and the control happily updated the display with its specific statistic.
For Each Stat_Obj As Control in Statistics_Controls
Stat_Obj.Invalidate()
Next
You might need to give the window time to redraw itself. I understand you're doing the import in a loop and the loop is running on the main UI thread? Try adding this line to the loop:
Application.DoEvents();