I have been programming a button_Click event, where I need the following:
Set visibility of a gif to true (in picture box, was false at first)
Wait one second with the picture shown (its a gif and I need it moving, which means System.Threading.Thread.Sleep(1000) will stop the animation)
Exit program
I have this:
private void button1_Click(object sender, EventArgs e)
{
loading.Visible = !loading.Visible;
// pause for a second, then exit
Environment.Exit(0);
}
Thanks!
You may use the following:
// ↓↓↓↓↓ << notice the `async` keyword.
private async void button1_Click(object sender, EventArgs e)
{
loading.Visible = !loading.Visible;
// Wait for one second.
await Task.Delay(TimeSpan.FromSeconds(1));
Application.Exit();
}
The Task.Delay() method does the following:
Creates a task that will complete after a time delay.
And using the await keyword, we asynchronously wait for the task to complete. "asynchronously" means that the current thread (the UI thread in this case) will not be blocked. Therefore, the animation will not be affected.
Related
I have a method tied to a button that does time consuming thing. So I have created a label and binded it to property to inform user that application is actually doing something.
private void Button_OnClick(object sender, RoutedEventArgs e)
{
_viewModel.BottomBarMessage = "Loading..."; //part 1
//do very long thing, for example
System.Threading.Thread.Sleep(3000); //wait for 3 seconds to simulate long operation
_viewModel.BottomBarMessage = "Done."; //part 2
}
Issue is part 1 does not seem to be ever executed. Label switches to Done but never to Loading.
I have suspected its because UI gets blocked, but changing Sleep to be executed as Task changes nothing.
use await Task.Delay instead of Thread.Sleep - you are blocking UI thread.
Something like:
private async void Button_OnClick(object sender, RoutedEventArgs e)
{
_viewModel.BottomBarMessage = "Loading..."; //part 1
//do very long thing, for example
await Task.Delay(3000);
_viewModel.BottomBarMessage = "Done."; //part 2
}
I have a button on a windows form application that when pressed runs two functions that are in different classes. The processing time takes 10 seconds or so and I would like to run a progress bar simply as aesthetic feedback for the user so they know something is happening. It does not need to actually progress as the work is done. The problem is it never actually starts moving ... the rest of the application works fine (ie database is loaded and results are processed) but the progress bar doesn't ever do anything. Any help someone can provide would be great! Thanks!!
private void button1_Click(object sender, EventArgs e)
{
//START PROGRESS BAR MOVEMENT
pb.Style = ProgressBarStyle.Marquee;
LoadDatabase.Groups();
ProcessResults.GroupOne();
//END PROGRESS BAR MOVEMENT
????
}
Mark your button1 Click() handler with async, then use await and Task.Run:
private async void button1_Click(object sender, EventArgs e)
{
// START PROGRESS BAR MOVEMENT:
button1.Enabled = false;
pb.Style = ProgressBarStyle.Marquee;
pb.Show();
// DO THE WORK ON A DIFFERENT THREAD:
await (Task.Run(() =>
{
System.Threading.Thread.Sleep(5000); // simulated work (remove this and uncomment the two lines below)
//LoadDatabase.Groups();
//ProcessResults.GroupOne();
}));
// END PROGRESS BAR MOVEMENT:
pb.Hide();
button1.Enabled = true;
}
I'm trying to delay an action on a textbox. I want to search a large quantity of text for a word. Now I do this with the "textchanged" event. The problem here is, when he reaches a word of more then 3 letters (I've prevented 0-2 wordsearches) the process becomes intensive.
Question:
What are my possibilities here?
ex: Putting a timer on the textchanged-event? If so, how do I do this?
Code:
private void txtSearch_TextChanged(object sender, EventArgs e)
{
// delay here
dosearch(searchbox.text);
}
(Re)start a dispatcher timer every time a key is pressed, and do the search when the timer elapses. Around 200-300 ms delay is usually pretty good.
private DispatcherTimer _searchTimer;
// Initialize timer in constructor with 200 ms delay and register tick event.
private void txtSearch_TextChanged(object sender, EventArgs e)
{
_searchTimer.Stop();
_searchTimer.Start();
}
private void OnSearchTimerTick(object sender, EventArgs e)
{
_searchTimer.Stop()
Search(searchBox.Text);
}
private void Search(string searchTxt)
{
// Do search
}
UPDATE:
To improve the responsiveness (the above example will lock the UI while searching because the dispatcher timer callback runs on the UI thread), you can execute the search in a separate Task. When the search completes you need to ensure that the result is not stale (that the user has not modified the search text while searching):
private void Search(string searchText)
{
Task.Run(() =>
{
// Execute search
Dispatcher.Invoke(() =>
{
if (searchText == searchBox.Text)
{
// Result is good
}
});
});
}
I have following code. I'm trying to make buttons to main Form which can Pause, Continue and Stop the background thread the downloader is running on (private Thread thread)
Form1.cs
private AutoResetEvent waitHandle = new AutoResetEvent(true);
private Thread thread;
private void ThreadJob()
{
Downloader download = new Downloader();
download.runDownloader();
}
// THREADS button1 is "Download now"-button
private void button1_Click(object sender, EventArgs e)
{
ThreadStart job = new ThreadStart(ThreadJob);
thread = new Thread(job);
thread.IsBackground = true;
thread.Start();
}
This code is ran on Windows Form. I have buttons for all those actions (Pause, Continue, Stop)
Pause and continue button has code on form
private void btnPause_Click(object sender, EventArgs e)
{
waitHandle.WaitOne(); // Need to pause the background thread
}
private void btnContinue_Click(object sender, EventArgs e)
{
waitHandle.Set(); // Need to continue the background thread
}
The problem is pressing Pause button will freeze the main Form not the background thread.
It is runDownloader() that must be able to pause.
It will need to periodically call waitHandle.WaitOne() on the wait handle.
Your WaitHandle must be a ManualResetEvent, not an AutoResetEvent and you should initialise it so that it is signalled (unless you want to start your thread in a "paused" state).
You will also have to change your button handlers as follows:
private void btnPause_Click(object sender, EventArgs e)
{
waitHandle.Reset(); // Need to pause the background thread
}
private void btnContinue_Click(object sender, EventArgs e)
{
waitHandle.Set(); // Need to continue the background thread
}
This means that you must be able to pass waitHandle to the thread so that it can wait on it.
However, there are better ways of managing thread cancellation since .Net 4, namely the use of CancellationTokenSource and CancellationToken.
See this Microsoft article for details.
When a user clicks on Run, the application runs through a lot of code to generate a model and display it in a Chart. The Run takes about 1-2 minutes to run. I also have a Cancel button that gets enabled after the Run button is clicked. I am working with DotSpatial, so my buttons are on a plugin panel in a ribbon UI. The click event on the Run and Cancel start in the plugin, which calls the back-end class's code Run and Click.
When the user hits cancel after the run starts, there is a delay, but the cancel method is invokes and executes, but the run never stops and we eventually see the chart display. So, I'm thinking I need a separate thread for the Run. I'm fairly new to programming, and never worked with Threading. I've looked into it and added the below code, but my thread method isn't running. Here's my code:
The Run button is clicked:
This is at the top:
//check to see if RunModel thread needs to stop or continue
private volatile bool stopRun = false;
private Thread runThread;
Then this is the method that's called from the click event:
public void btnRun_testingThread(object sender, EventArgs e)
{
//create a new thread to run the RunModel
if (runThread == null)
{
//we don't want to stop this thread
stopRun = false;
runThread = new Thread(RunModel);
runThread.Start(); <--this isn't doing anything
}
So, I would think that when the code gets to the runThread.Start(), it would jump into my RunModel method and start running through the code. But it doesn't. Additionally, I'll want to cancel out of this thread (once I have it working correctly), so I have this, which gets called from the cancel click method:
private void StopRunThread()
{
if (runThread != null)
{
//we want to stop the thread
stopRun = true;
//gracefully pause until the thread exits
runThread.Join();
runThread = null;
}
}
Then the this is the RunModel() where I'm checking occasionally to see if the stopRun bool has changed.
public void RunModel()
{
...some code.....
//check to see if cancel was clicked
if (stopRun)
{
....clean up code....
return;
}
....some more code....
//check to see if cancel was clicked
if (stopRun)
{
....clean up code....
return;
}
}
And the cancel button click method:
public void btnCancel_Click(Object sender, EventArgs e)
{
stopRun = true;
StopRunThread();
//the model run has been canceled
....some code.....
}
Any help on getting the thread.start to actually run the Run method? Then do I need to constantly check the volatile bool in the run in order to clean everything up if it's being stopped? Thanks!
I think you'd be best looking at the BackgroundWorker - this essentially runs separately but can watch out for cancellation commands. Make sure you add 'WorkerSupportCancellation' when you initialise it:
BackgroundWorker backgroundWorker1 = new BackgroundWorker();
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork); // This does the job ...
backgroundWorker1.WorkerSupportsCancellation = true; // This allows cancellation.
Then on click you can start your process:
public void btnRun_testingThread(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
Your cancel button can issue a cancellation request:
public void btnCancel_Click(Object sender, EventArgs e)
{
backgroundWorker1.CancelAsync();
}
Then your worker can monitor for this as it's doing it's work ...
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < 100; i++)
{
if (backgroundWorker1.CancellationPending)
{
break;
}
else
{
// Do whatever you're doing.
}
}
e.Result = backgroundWorker1.CancellationPending ? null : orders;
}
You can enhance this further by adding progress bars etc., but that gets a bit more complicated so I won't go into it here.
Considering new info provided in commend I believe you just missed a start of the RunModel() method in debugger because of wrong assumption regarding thread.Start() method behaviour.
Please see a note from MSDN, Thread.Start Method
Once a thread is in the ThreadState.Running state, the operating
system can schedule it for execution. The thread begins executing
at the first line of the method represented by the ThreadStart or
ParameterizedThreadStart delegate supplied to the thread constructor.
Small demonstration that thread start takes some time bits, for me it starts in 38-40 milliseconds:
Stopwatch watch = new Stopwatch();
Thread thread = new Thread((ThreadStart)watch.Stop);
thread.Start();
watch.Start();
Thread.Sleep(5000);
double startedAfter = watch.ElapsedMilliseconds;
Since .NET Framework 4.0 consider using TPL Tasks rather than threads explicitly, some pros:
You can easily synchronize with UI thread by passing in a Task UI Thread synchronization context
You can easily stop a Taks using CancellationToken