Is there such a function like sleep(seconds) but it wouldn't block UI updates?
I have a code like this and if I put threading sleep after (letters.Children[Words[index].index] as TextBlock).Text = Words[index].LetterCorrect; (I want to sleep after that) it just waits 1 sec and then UI gets updates, but I dont want that.
private void Grid_Click(object sender, RoutedEventArgs e)
{
if (index == Words.Count() - 1) return;
if ((((e.Source as Button).Content as Viewbox).Child as Label).Content.ToString() == Words[index].LetterCorrect)
{
(letters.Children[Words[index].index] as TextBlock).Text = Words[index].LetterCorrect;
letters.Children.Clear();
LoadWord(++index);
this.DataContext = Words[index];
}
}
Try a Timer and have the Elapsed callback execute the code you want to happen after the one second.
Create a working thread that does the work for you and let that thread sleep for the desired time before going to work
e.g.
ThreadPool.QueueUserWorkItem((state) =>
{
Thread.Sleep(1000);
// do your work here
// CAUTION: use Invoke where necessary
});
Put the logic itself in a background thread separate from the UI thread and have that thread wait.
Anything in the UI thread that waits 1 second will lock up the entire UI thread for that second.
Use an async scheduled callback:
private void Grid_Click(object sender, RoutedEventArgs e)
{
if (index == Words.Count() - 1) return;
if ((((e.Source as Button).Content as Viewbox).Child as Label).Content.ToString() == Words[index].LetterCorrect)
{
(letters.Children[Words[index].index] as TextBlock).Text = Words[index].LetterCorrect;
Scheduler.ThreadPool.Schedule(schedule =>
{
letters.Children.Clear();
LoadWord(++index);
this.DataContext = Words[index];
}, TimeSpan.FromSeconds(1));
}
}
Not sure what framework you are using, but if you are using Silverlight or WPF, have you considered playing an animation that reveals the correct letter or does a fade sequence that takes 1000ms?
Related
I have the next code on Windows Forms:
if (control.IsHandleCreated)
{
if (control.InvokeRequired)
{
control.BeginInvoke(action);
}
else
{
action.Invoke();
}
}
Debugging, it enters to InvokeRequired = false and it works perfectly, but on production environment. Somehow it enters to InvokeRequired = true, so it should execute BeginInvoke() method.
It doesn't. It never enters the action. This script belongs to a DataGrid control, but having the same on different DataGrids, Comboboxes, etc on the same Form it does work; so it seems to be something expecific for this DataGrid.
Any idea?
Thanks
I tried to find the true answer , my guess is that when you call begininvoke a message gets put in a queue for that thread. That thread takes items out of this queue and processes them 1 by 1. Let's say that you are calling BeginInvoke faster than the processing thread can handle it ... your queue will get bigger and bigger and take more and more time to process. then the main thread can become blocked doing other things. While your thread is doing these other things it will not be processing items out of the queue, then the thread can not access the control.
I tested your code, the code can not repeat in case of lack of access, then i changed the code and it works after repeat one or two times:
int i = 0;
public delegate void AsyncMethodCaller();
private void proc2()
{
Action action = () => control1.Text = (i += 1).ToString();
if (control1.IsHandleCreated)
{
if (control1.InvokeRequired)
{
control1.BeginInvoke(new AsyncMethodCaller(proc2));
}
else
{
action.Invoke();
}
}
else
{
MessageBox.Show("Handle creation error");
}
}
private void proc1()
{
for (int i=0; i<1000; i++)
{
//do something
}
}
private void button1_Click(object sender, EventArgs e)
{
Thread thread1 = new Thread(proc1);
thread1.Start();
Thread thread2 = new Thread(proc2);
thread2.Start();
}
This is what I just used:
<your control>.Invoke(new MethodInvoker(delegate () {
… do your work here
}));
-Gina
I have a button that on click event I get some information from the network.
When I get information I parse it and add items to ListBox. All is fine, but when I do a fast double-click on button, it seems that two background workers are running and after finishing all work, items in the list are dublicated.
I want to do so that if you click button and the proccess of getting information is in work, this thread is stopping and only after first work is completed the second one is beginning.
Yes, I know about AutoResetEvent, but when I used it it helped me only one time and never more. I can't implement this situation and hope that you will help me!
Now I even try to make easier but no success :( : I added a flag field(RefreshDialogs)(default false), when the user clicks on button, if flag is true(it means that work is doing), nothing is doing, but when flag field is set to false, all is fine and we start a new proccess.
When Backgroundwork completes, I change field flag to false(it means that user can run a new proccess).
private void Message_Refresh_Click(object sender, EventArgs e)
{
if (!RefreshDialogs)
{
RefreshDialogs = true;
if (threadBackgroundDialogs.WorkerSupportsCancellation)
{
threadBackgroundDialogs.CancelAsync();
}
if (!threadBackgroundDialogs.IsBusy)
{
downloadedDialogs = 0;
threadBackgroundDialogs = new BackgroundWorker();
threadBackgroundDialogs.WorkerSupportsCancellation = true;
threadBackgroundDialogs.DoWork += LoadDialogs;
threadBackgroundDialogs.RunWorkerCompleted += ProcessCompleted;
threadBackgroundDialogs.RunWorkerAsync();
}
}
}
void ProcessCompleted(object sender, RunWorkerCompletedEventArgs e)
{
RefreshDialogs = false;
}
So you want to keep the second process running while the first works, but they shouldn't disturb each other? And after the first one finishes the second one continues?
Crude way: While loop:
if (!RefreshDialogs)
{
RefreshDialogs = true;
this becomes:
while(RefreshDialogs)
{
}
RefreshDialogs = true;
After you set it false the second process wwill jump out of the while. (Note this is extremly inefficent since both processes will be running all the time, i'm pretty sure the second one will block the first one, but with multitasking now it shouldn't, if it block use a Dispatcher.Thread)
Elegant way: Use A Semaphore
http://msdn.microsoft.com/de-de/library/system.threading.semaphore%28v=vs.80%29.aspx
If you find it impossible to have both processes running at the same time, or want another way:
Add an Array/List/int and when the second process notices there is the first process running, like with your bool, increase your Added variable, and at the end of the process, restart the new process and decrese the variable:
int number;
if (!RefreshDialogs)
{
RefreshDialogs = true;
your code;
if(number > 0)
{
number--;
restart process
}
}
else
{
number++;
}
I have to admit, i like my last proposal the most, since its highly efficent.
Make your thread blocking. That is easy;
lock(someSharedGlobalObject)
{
Do Work, Exit early if cancelled
}
This way other threads will wait until the first thread releases the lock. They will never execute simultaneously and silently wait until they can continue.
As for other options; why not disable the button when clicked and re-enable it when the backgroundworker completes. Only problem is this does not allow for cancelling the current thread. The user has to wait for it to finish. It does make any concurrency go away very easily.
How about this approach?
Create a request queue or counter which will be incremented on every button click. Every time that count is > 0. Start the background worker. When the information comes, decrement the count and check for 0. If its still > 0 restart the worker. In that your request handler becomes sequential.
In this approach you may face the problem of continuous reference of the count by two threads, for that you may use a lock unlock condition.
I hav followed this approach for my app and it works well, hope it does the same for you.
I'm not an Windows Phone expert, but as I see it has support for TPL, so following code would read nicely:
private object syncRoot =new object();
private Task latestTask;
public void EnqueueAction(System.Action action)
{
lock (syncRoot)
{
if (latestTask == null)
latestTask = Task.Factory.StartNew(action);
else
latestTask = latestTask.ContinueWith(tsk => action());
}
}
Use can use semaphores
class TheClass
{
static SemaphoreSlim _sem = new SemaphoreSlim (3);
static void Main()
{
for (int i = 1; i <= 5; i++)
new Thread (Enter).Start (i);
}
static void Enter (object name)
{
Console.WriteLine (name + " wants to enter");
_sem.Wait();
Console.WriteLine (name + " has entered!");
Thread.Sleep (1000 * (int) name );
Console.WriteLine (name + " is leaving");
_sem.Release(); }
}
}
I found the solution and thanks to #Giedrius. Flag RefreshingDialogs is set to true only when proccess is at the end, when I added items to Listbox. The reason why I'am using this flag is that state of process changes to complete when the asynchronous operation of getting content from network(HttpWebRequest, method BeginGetRequestStream) begins, but after network operaion is complete I need to make UI operations and not only them(parse content and add it to Listbox)My solution is:
private object syncRoot = new object();
private Task latestTask;
public void EnqueueAction(System.Action action)
{
lock (syncRoot)
{
if (latestTask == null)
{
downloadedDialogs = 0;
latestTask = Task.Factory.StartNew(action);
}
else if(latestTask.IsCompleted && !RefreshingDialogs)
{
RefreshingDialogs = true;
downloadedDialogs = 0;
latestTask = Task.Factory.StartNew(action);
}
}
}
private void Message_Refresh_Click(object sender, EventArgs e)
{
Action ac = new Action(LoadDialogs2);
EnqueueAction(ac);
}
I am currently writing my first program on C# and I am extremely new to the language (used to only work with C so far). I have done a lot of research, but all answers were too general and I simply couldn't get it t work.
So here my (very common) problem:
I have a WPF application which takes inputs from a few textboxes filled by the user and then uses that to do a lot of calculations with them. They should take around 2-3 minutes, so I would like to update a progress bar and a textblock telling me what the current status is.
Also I need to store the UI inputs from the user and give them to the thread, so I have a third class, which I use to create an object and would like to pass this object to the background thread.
Obviously I would run the calculations in another thread, so the UI doesn't freeze, but I don't know how to update the UI, since all the calculation methods are part of another class.
After a lot of reasearch I think the best method to go with would be using dispatchers and TPL and not a backgroundworker, but honestly I am not sure how they work and after around 20 hours of trial and error with other answers, I decided to ask a question myself.
Here a very simple structure of my program:
public partial class MainWindow : Window
{
public MainWindow()
{
Initialize Component();
}
private void startCalc(object sender, RoutedEventArgs e)
{
inputValues input = new inputValues();
calcClass calculations = new calcClass();
try
{
input.pota = Convert.ToDouble(aVar.Text);
input.potb = Convert.ToDouble(bVar.Text);
input.potc = Convert.ToDouble(cVar.Text);
input.potd = Convert.ToDouble(dVar.Text);
input.potf = Convert.ToDouble(fVar.Text);
input.potA = Convert.ToDouble(AVar.Text);
input.potB = Convert.ToDouble(BVar.Text);
input.initStart = Convert.ToDouble(initStart.Text);
input.initEnd = Convert.ToDouble(initEnd.Text);
input.inita = Convert.ToDouble(inita.Text);
input.initb = Convert.ToDouble(initb.Text);
input.initc = Convert.ToDouble(initb.Text);
}
catch
{
MessageBox.Show("Some input values are not of the expected Type.", "Wrong Input", MessageBoxButton.OK, MessageBoxImage.Error);
}
Thread calcthread = new Thread(new ParameterizedThreadStart(calculations.testMethod);
calcthread.Start(input);
}
public class inputValues
{
public double pota, potb, potc, potd, potf, potA, potB;
public double initStart, initEnd, inita, initb, initc;
}
public class calcClass
{
public void testmethod(inputValues input)
{
Thread.CurrentThread.Priority = ThreadPriority.Lowest;
int i;
//the input object will be used somehow, but that doesn't matter for my problem
for (i = 0; i < 1000; i++)
{
Thread.Sleep(10);
}
}
}
I would be very grateful if someone had a simple explanation how to update the UI from inside the testmethod. Since I am new to C# and object oriented programming, too complicated answers I will very likely not understand, I'll do my best though.
Also if someone has a better idea in general (maybe using backgroundworker or anything else) I am open to see it.
First you need to use Dispatcher.Invoke to change the UI from another thread and to do that from another class, you can use events.
Then you can register to that event(s) in the main class and Dispatch the changes to the UI and in the calculation class you throw the event when you want to notify the UI:
class MainWindow : Window
{
private void startCalc()
{
//your code
CalcClass calc = new CalcClass();
calc.ProgressUpdate += (s, e) => {
Dispatcher.Invoke((Action)delegate() { /* update UI */ });
};
Thread calcthread = new Thread(new ParameterizedThreadStart(calc.testMethod));
calcthread.Start(input);
}
}
class CalcClass
{
public event EventHandler ProgressUpdate;
public void testMethod(object input)
{
//part 1
if(ProgressUpdate != null)
ProgressUpdate(this, new YourEventArgs(status));
//part 2
}
}
UPDATE:
As it seems this is still an often visited question and answer I want to update this answer with how I would do it now (with .NET 4.5) - this is a little longer as I will show some different possibilities:
class MainWindow : Window
{
Task calcTask = null;
void buttonStartCalc_Clicked(object sender, EventArgs e) { StartCalc(); } // #1
async void buttonDoCalc_Clicked(object sender, EventArgs e) // #2
{
await CalcAsync(); // #2
}
void StartCalc()
{
var calc = PrepareCalc();
calcTask = Task.Run(() => calc.TestMethod(input)); // #3
}
Task CalcAsync()
{
var calc = PrepareCalc();
return Task.Run(() => calc.TestMethod(input)); // #4
}
CalcClass PrepareCalc()
{
//your code
var calc = new CalcClass();
calc.ProgressUpdate += (s, e) => Dispatcher.Invoke((Action)delegate()
{
// update UI
});
return calc;
}
}
class CalcClass
{
public event EventHandler<EventArgs<YourStatus>> ProgressUpdate; // #5
public TestMethod(InputValues input)
{
//part 1
ProgressUpdate.Raise(this, status); // #6 - status is of type YourStatus
// alternative version to the extension for C# 6+:
ProgressUpdate?.Invoke(this, new EventArgs<YourStatus>(status));
//part 2
}
}
static class EventExtensions
{
public static void Raise<T>(this EventHandler<EventArgs<T>> theEvent,
object sender, T args)
{
if (theEvent != null)
theEvent(sender, new EventArgs<T>(args));
}
}
#1) How to start the "synchronous" calculations and run them in the background
#2) How to start it "asynchronous" and "await it": Here the calculation is executed and completed before the method returns, but because of the async/await the UI is not blocked (BTW: such event handlers are the only valid usages of async void as the event handler must return void - use async Task in all other cases)
#3) Instead of a new Thread we now use a Task. To later be able to check its (successfull) completion we save it in the global calcTask member. In the background this also starts a new thread and runs the action there, but it is much easier to handle and has some other benefits.
#4) Here we also start the action, but this time we return the task, so the "async event handler" can "await it". We could also create async Task CalcAsync() and then await Task.Run(() => calc.TestMethod(input)).ConfigureAwait(false); (FYI: the ConfigureAwait(false) is to avoid deadlocks, you should read up on this if you use async/await as it would be to much to explain here) which would result in the same workflow, but as the Task.Run is the only "awaitable operation" and is the last one we can simply return the task and save one context switch, which saves some execution time.
#5) Here I now use a "strongly typed generic event" so we can pass and receive our "status object" easily
#6) Here I use the extension defined below, which (aside from ease of use) solve the possible race condition in the old example. There it could have happened that the event got null after the if-check, but before the call if the event handler was removed in another thread at just that moment. This can't happen here, as the extensions gets a "copy" of the event delegate and in the same situation the handler is still registered inside the Raise method.
I am going to throw you a curve ball here. If I have said it once I have said it a hundred times. Marshaling operations like Invoke or BeginInvoke are not always the best methods for updating the UI with worker thread progress.
In this case it usually works better to have the worker thread publish its progress information to a shared data structure that the UI thread then polls at regular intervals. This has several advantages.
It breaks the tight coupling between the UI and worker thread that Invoke imposes.
The UI thread gets to dictate when the UI controls get updated...the way it should be anyway when you really think about it.
There is no risk of overrunning the UI message queue as would be the case if BeginInvoke were used from the worker thread.
The worker thread does not have to wait for a response from the UI thread as would be the case with Invoke.
You get more throughput on both the UI and worker threads.
Invoke and BeginInvoke are expensive operations.
So in your calcClass create a data structure that will hold the progress information.
public class calcClass
{
private double percentComplete = 0;
public double PercentComplete
{
get
{
// Do a thread-safe read here.
return Interlocked.CompareExchange(ref percentComplete, 0, 0);
}
}
public testMethod(object input)
{
int count = 1000;
for (int i = 0; i < count; i++)
{
Thread.Sleep(10);
double newvalue = ((double)i + 1) / (double)count;
Interlocked.Exchange(ref percentComplete, newvalue);
}
}
}
Then in your MainWindow class use a DispatcherTimer to periodically poll the progress information. Configure the DispatcherTimer to raise the Tick event on whatever interval is most appropriate for your situation.
public partial class MainWindow : Window
{
public void YourDispatcherTimer_Tick(object sender, EventArgs args)
{
YourProgressBar.Value = calculation.PercentComplete;
}
}
You're right that you should use the Dispatcher to update controls on the UI thread, and also right that long-running processes should not run on the UI thread. Even if you run the long-running process asynchronously on the UI thread, it can still cause performance issues.
It should be noted that Dispatcher.CurrentDispatcher will return the dispatcher for the current thread, not necessarily the UI thread. I think you can use Application.Current.Dispatcher to get a reference to the UI thread's dispatcher if that's available to you, but if not you'll have to pass the UI dispatcher in to your background thread.
Typically I use the Task Parallel Library for threading operations instead of a BackgroundWorker. I just find it easier to use.
For example,
Task.Factory.StartNew(() =>
SomeObject.RunLongProcess(someDataObject));
where
void RunLongProcess(SomeViewModel someDataObject)
{
for (int i = 0; i <= 1000; i++)
{
Thread.Sleep(10);
// Update every 10 executions
if (i % 10 == 0)
{
// Send message to UI thread
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Normal,
(Action)(() => someDataObject.ProgressValue = (i / 1000)));
}
}
}
Everything that interacts with the UI must be called in the UI thread (unless it is a frozen object). To do that, you can use the dispatcher.
var disp = /* Get the UI dispatcher, each WPF object has a dispatcher which you can query*/
disp.BeginInvoke(DispatcherPriority.Normal,
(Action)(() => /*Do your UI Stuff here*/));
I use BeginInvoke here, usually a backgroundworker doesn't need to wait that the UI updates. If you want to wait, you can use Invoke. But you should be careful not to call BeginInvoke to fast to often, this can get really nasty.
By the way, The BackgroundWorker class helps with this kind of taks. It allows Reporting changes, like a percentage and dispatches this automatically from the Background thread into the ui thread. For the most thread <> update ui tasks the BackgroundWorker is a great tool.
If this is a long calculation then I would go background worker. It has progress support. It also has support for cancel.
http://msdn.microsoft.com/en-us/library/cc221403(v=VS.95).aspx
Here I have a TextBox bound to contents.
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Debug.Write("backgroundWorker_RunWorkerCompleted");
if (e.Cancelled)
{
contents = "Cancelled get contents.";
NotifyPropertyChanged("Contents");
}
else if (e.Error != null)
{
contents = "An Error Occured in get contents";
NotifyPropertyChanged("Contents");
}
else
{
contents = (string)e.Result;
if (contentTabSelectd) NotifyPropertyChanged("Contents");
}
}
You are going to have to come back to your main thread (also called UI thread) in order to update the UI.
Any other thread trying to update your UI will just cause exceptions to be thrown all over the place.
So because you are in WPF, you can use the Dispatcher and more specifically a beginInvoke on this dispatcher. This will allow you to execute what needs done (typically Update the UI) in the UI thread.
You migh also want to "register" the UI in your business, by maintaining a reference to a control/form, so you can use its dispatcher.
Thank God, Microsoft got that figured out in WPF :)
Every Control, like a progress bar, button, form, etc. has a Dispatcher on it. You can give the Dispatcher an Action that needs to be performed, and it will automatically call it on the correct thread (an Action is like a function delegate).
You can find an example here.
Of course, you'll have to have the control accessible from other classes, e.g. by making it public and handing a reference to the Window to your other class, or maybe by passing a reference only to the progress bar.
Felt the need to add this better answer, as nothing except BackgroundWorker seemed to help me, and the answer dealing with that thus far was woefully incomplete. This is how you would update a XAML page called MainWindow that has an Image tag like this:
<Image Name="imgNtwkInd" Source="Images/network_on.jpg" Width="50" />
with a BackgroundWorker process to show if you are connected to the network or not:
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
public partial class MainWindow : Window
{
private BackgroundWorker bw = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
// Set up background worker to allow progress reporting and cancellation
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
// This is your main work process that records progress
bw.DoWork += new DoWorkEventHandler(SomeClass.DoWork);
// This will update your page based on that progress
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
// This starts your background worker and "DoWork()"
bw.RunWorkerAsync();
// When this page closes, this will run and cancel your background worker
this.Closing += new CancelEventHandler(Page_Unload);
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
BitmapImage bImg = new BitmapImage();
bool connected = false;
string response = e.ProgressPercentage.ToString(); // will either be 1 or 0 for true/false -- this is the result recorded in DoWork()
if (response == "1")
connected = true;
// Do something with the result we got
if (!connected)
{
bImg.BeginInit();
bImg.UriSource = new Uri("Images/network_off.jpg", UriKind.Relative);
bImg.EndInit();
imgNtwkInd.Source = bImg;
}
else
{
bImg.BeginInit();
bImg.UriSource = new Uri("Images/network_on.jpg", UriKind.Relative);
bImg.EndInit();
imgNtwkInd.Source = bImg;
}
}
private void Page_Unload(object sender, CancelEventArgs e)
{
bw.CancelAsync(); // stops the background worker when unloading the page
}
}
public class SomeClass
{
public static bool connected = false;
public void DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = sender as BackgroundWorker;
int i = 0;
do
{
connected = CheckConn(); // do some task and get the result
if (bw.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
Thread.Sleep(1000);
// Record your result here
if (connected)
bw.ReportProgress(1);
else
bw.ReportProgress(0);
}
}
while (i == 0);
}
private static bool CheckConn()
{
bool conn = false;
Ping png = new Ping();
string host = "SomeComputerNameHere";
try
{
PingReply pngReply = png.Send(host);
if (pngReply.Status == IPStatus.Success)
conn = true;
}
catch (PingException ex)
{
// write exception to log
}
return conn;
}
}
For more information: https://msdn.microsoft.com/en-us/library/cc221403(v=VS.95).aspx
I am working on a winform application, and my goal is to make a label on my form visible to the user, and three seconds later make the label invisible. The issue here is timing out three seconds. I honestly do not know if this was the correct solution to my problem, but I was able to make this work by creating a new thread, and having the new thread Sleep for three seconds (System.Threading.Thread.Sleep(3000)).
I can't use System.Threading.Thread.Sleep(3000) because this freezes my GUI for 3 seconds!
private void someVoid()
{
lbl_authenticationProcess.Text = "Credentials have been verified authentic...";
Thread sleepThreadStart = new Thread(new ThreadStart(newThread_restProgram));
sleepThreadStart.Start();
// Once three seconds has passed / thread has finished: lbl_authenticationProcess.Visible = false;
}
private void newThread_restProgram()
{
System.Threading.Thread.Sleep(3000);
}
So, back to my original question. How can I determine (from my main thread) when the new thread has completed, meaning three seconds has passed?
I am open to new ideas as well as I'm sure there are many.
Right now, you are blocking the entire UI thread in order to hide a label after 3 seconds. If that's what you want, then just user Thread.Sleep(3000) from within the form. If not, though, then you're best off using a Timer:
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
timer.Interval = 3000;
timer.Tick += (s, e) => { this.lbl_authenticationProcess.Visible = false; timer.Stop(); }
timer.Start();
After 3 seconds, the label will disappear. While you're waiting for that, though, a user can still interact with your application.
Note that you must use the Forms version of Timer, since its Tick event is raised on the UI thread, allowing direct access to the control. Other timers can work, but interaction with the control would have to be Invoke/BeginInvoked.
Did you try to use Timer
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
t.Interval = 3000;
t.Start();
t.Tick += new EventHandler(t_Tick);
void t_Tick(object sender, EventArgs e)
{
label.Visible = false;
}
You really don't need to synchronize anything. You just need a new thread, with a reference to your label. Your code is actually pretty close:
private void someVoid()
{
lbl_authenticationProcess.Text = "Credentials have been verified authentic...";
lbl_authenticationProcess.Visible = true;
Thread sleepThreadStart = new Thread(new ThreadStart(newThread_restProgram));
sleepThreadStart.Start();
}
private void newThread_restProgram()
{
System.Threading.Thread.Sleep(3000);
if (lbl_authenticationProcess.InvokeRequired) {
lbl_authenticationProcess.Invoke(new SimpleCallBack(makeInvisible));
} else {
makeInvisible();
}
}
private void makeInvisible()
{
lbl_authenticationProcess.Visible = false;
}
So, when someVoid() is called, the message on the label is set, the label is made visible. Then a new thread is started with the newThread_restProgram() as the body. The new thread will sleep for 3 seconds (allowing other parts of the program to run), then the sleep ends and the label is made invisible. The new thread ends automatically because it's body method returns.
You can make a method like so:
public void SetLbl(string txt)
{
Invoke((Action)(lbl_authenticationProcess.Text = txt));
}
And you would be able to call it from the second thread, but it invokes on the main thread.
If you're using .NET 3.5 or older, it's kinda a pain:
private void YourMethod()
{
someLabel.BeginInvoke(() =>
{
someLabel.Text = "Something Else";
Thread thread = new Thread(() =>
{
Thread.Sleep(3000);
someLabel.BeginInvoke(() => { someLabel.Visible = false; });
});
thread.Start();
});
}
That should stop you from blocking the UI.
If you're using .NET 4+:
Task.Factory.StartNew(() =>
{
someLabel.BeginInvoke(() => { someLabel.Text = "Something" });
}).ContinueWith(() =>
{
Thread.Sleep(3000);
someLabel.BeginInvoke(() => { someLabel.Visible = false; });
});
If you are willing to download the Async CTP then you could use this really elegant solution which requires the new async and await keywords.1
private void async YourButton_Click(object sender, EventArgs args)
{
// Do authentication stuff here.
lbl_authenticationProcess.Text = "Credentials have been verified authentic...";
await Task.Delay(3000); // TaskEx.Delay in CTP
lbl_authenticationProcess.Visible = false;
}
1Note that the Async CTP uses TaskEx instead of Task.
You can use an AutoResetEvent for your thread synchronization. You set the event to signalled when your secondary thread has woken from it's sleep, so that it can notify your main thread.
That means though that your main thread waits for the other thread to complete.
On that note, you can use SecondThread.Join() to wait for it to complete in your main thread.
You do either of the above, but you don't need to do both.
As suggested in the comments, having a UI thread sleep is not generally a good idea, as it causes unresponsiveness for the user.
However if you do that, you might as well just sleep your main thread and get rid of the extraneous need of the second thread.
I'm not exactly sure this is the right way to do it, but to answer your question, you have to use the Join() function.
public void CallingThread()
{
Thread t = new Thread(myWorkerThread);
t.Join();
}
public void WorkerThread()
{
//Do some stuff
}
You can also add a timeout as parameter to the function, but you don't need that here.
I'm just trying to run a new thread each time a button click even occurs which should create a new form. I tried this in the button click event in the MainForm:
private void button1_Click(object sender, EventArgs e)
{
worker1 = new Thread(new ThreadStart(thread1));
worker2 = new Thread(new ThreadStart(thread2));
worker1.Start();
worker2.Start();
}
private void thread1()
{
SubForm s = new SubForm();
s.Show();
}
private void thread2()
{
SubForm s = new SubForm();
s.Show();
}
The code in the Subform button click event goes like this:
private void button1_Click(object sender, EventArgs e)
{
int max;
try
{
max = Convert.ToInt32(textBox1.Text);
}
catch
{
MessageBox.Show("Enter numbers", "ERROR");
return;
}
progressBar1.Maximum = max;
for ( long i = 0; i < max; i++)
{
progressBar1.Value = Convert.ToInt32(i);
}
}
Is this the right way? Because I'm trying to open two independent forms, operations in one thread should not affect the other thread.
Or is BackGroundworker the solution to implement this? If yes, can anyone please help me with that?
You do not need to run forms in separate threads. You can just call s.Show() on multiple forms normally. They will not block each other.
Of course, if you’re doing something else, like some sort of calculation or other task that takes a long while, then you should run that in a separate thread, but not the form.
Here is a bit of code that will let you create a progress bar that shows progress for a long process. Notice that every time to access the form from inside the thread, you have to use .Invoke(), which actually schedules that invocation to run on the GUI thread when it’s ready.
public void StartLongProcess()
{
// Create and show the form with the progress bar
var progressForm = new Subform();
progressForm.Show();
bool interrupt = false;
// Run the calculation in a separate thread
var thread = new Thread(() =>
{
// Do some calculation, presumably in some sort of loop...
while ( ... )
{
// Every time you want to update the progress bar:
progressForm.Invoke(new Action(
() => { progressForm.ProgressBar.Value = ...; }));
// If you’re ready to cancel the calculation:
if (interrupt)
break;
}
// The calculation is finished — close the progress form
progressForm.Invoke(new Action(() => { progressForm.Close(); }));
});
thread.Start();
// Allow the user to cancel the calculation with a Cancel button
progressForm.CancelButton.Click += (s, e) => { interrupt = true; };
}
Although I'm not 100% aware of anything that says running completely seperate forms doing completely isolated operations in their own threads is dangerous in any way, running all UI operations on a single thread is generally regarded as good practice.
You can support this simply by having your Subform class use BackgroundWorker. When the form is shown, kick off the BackgroundWorker so that it processes whatever you need it to.
Then you can simply create new instances of your Subform on your GUI thread and show them. The form will show and start its operation on another thread.
This way the UI will be running on the GUI thread, but the operations the forms are running will be running on ThreadPool threads.
Update
Here's an example of what your background worker handlers might look like - note that (as usual) this is just off the top of my head, but I think you can get your head around the basic principles.
Add a BackgroundWorker to your form named worker. Hook it up to the following event handlers:
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Executed on GUI thread.
if (e.Error != null)
{
// Background thread errored - report it in a messagebox.
MessageBox.Show(e.Error.ToString());
return;
}
// Worker succeeded.
}
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Executed on GUI thread.
progressBar1.Value = e.ProgressPercentage;
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
// Executed on ThreadPool thread.
int max = (int)e.Argument;
for (long i = 0; i < max; i++)
{
worker.ReportProgress(Convert.ToInt32(i));
}
}
Your click handler would look something like:
void button1_Click(object sender, EventArgs e)
{
int max;
try
{
// This is what you have in your click handler,
// Int32.TryParse is a much better alternative.
max = Convert.ToInt32(textBox1.Text);
}
catch
{
MessageBox.Show("Enter numbers", "ERROR");
return;
}
progressBar1.Maximum = max;
worker.RunWorkerAsync(max);
}
I hope that helps.
Try this. It runs the new Form on its own thread with its own message queues and what not.
Run this code:
new Thread(new ThreadStart(delegate
{
Application.Run(new Form());
})).Start();
Use Thread.CurrentThread.GetHashCode() to test that is runs on different thread.
It's possible to run different forms on different threads. There are two caveats I'm aware of:
Neither form may be an MDI client of the other. Attempting to make a form an MDI client of another when the forms have different threads will fail.
If an object will be sending events to multiple forms and all forms use the same thread, it's possible to synchronize the events to the main thread before raising it. Otherwise, the event must be raised asynchronously and each form must perform its own synchronization mechanism for incoming events.
Obviously it's desirable not to have any window's UI thread get blocked, but using separate threads for separate windows may be a nice alternative.