Winform - Show mainform, wait, then modify label - c#

I've been trying to perform the simple task written in the title. I could only think of using timer, thread sleep or background worker, but I'm going to do this task only once.. so I would like to avoid making a lot of functions or such just for one time. I tried thread sleep but it doesn't show the mainform before the sleep... Any suggestions please?

The easiest option is to use await Task.Delay:
private async void Form_Load(object sender, EventArgs e)
{
await Task.Delay(timespan);
label1.Text = "Hello world";
}
If you don't have access to await using the version of .NET that you're using, then your best bet would be to use a Timer. Yes it's a fair bit of code. That's simply reflecting the complexity of asynchronous operations. await does a lot to make this simpler; without it, it's just not a problem that lends itself to terse solutions.

Use a System.Threading.Timer in the Form.Load event:
private const int DelayMilliseconds = 500;
private void Form1_Load(object sender, EventArgs e)
{
new System.Threading.Timer(_ => Invoke(new Action(() => _myLabel.Text = "bla")),
null,
DelayMilliseconds,
Timeout.Infinite);
}
Since you only specify a delay and no period, the timer will run exactly once. However, since the timer callback is executed on a different thread, you need to Invoke the action that modifies the label on the UI thread.

Use a System.Timer instance
make an eventhandler with Timer.Elapsed
set timer interval
start timer as application fires up
-after the timer elapses set your label
-stop timer

Related

Why using async/await to a function takes longer time then calling that same function directly?

I have a function which I need to run in background because it freezes the UI until it completes. I tried to use Async/Await which lets me use the UI no matter the function completes running or not, but I noticed it is much slower. Why using async/await to a function takes longer time then calling that same function directly ? Is there any other alternative ?
private void btnClick(object sender, EventArgs e)
{
Math4OfficeRibbon.CallFunction();
MessageBox.Show("Task Finished");
}
public async void CallFunction()
{
await Task.Run(() => AwaitedFunction());
}
public static void AwaitedFunction()
{
// Do Something
// Takes longer time this way
}
In order to find out why it's much slower you can track events down in visual studio by using Console.WriteLine($"{event name} {DateTime.Now}")
And then seeing where it takes the most time in output window.
However about the alternatives, I suggest you use BackgroundWorker to run your tasks.
note that you need to invoke controls in order to make changes to the ui through the backgroundWorker
BackgroundWorker _worker = new BackgroundWorker();
_worker.DoWork+=(o,args)=>
{
//your code here.
}
_worker.RunWorkerAsync();
You also have RunWorkerCompleted event which you can use to do things after your task is done running.
Backgroundworker also has the IsBusy property which you can use along with a while loop to keep the thread waiting for its completion without freezing the UI by doing :
While(_worker.IsBusy)
{
Application.DoEvents();
}
In order to invoke to do things on the ui thread you need to do the following within BackgroundWorker:
BeginInvoke(new Action(()=>
{
//ui action here for example:
MessageBox.show("test")
}));
However in order to find out why your asynchronous operation takes alot of time you have to trace it using the console because you have all the code and you know what you're doing.

Invoke timer from background thread

What I want to do. I want to SomeMethod will be called periodically. Therefore, I want to timer will be started from backgroung thread after body of background thread method is passed. _timer.Start() was invoked, but TickHandler doesn't;
code:
using Timer = System.Windows.Forms.Timer;
class TestTimer
{
private Timer _timer;
private Thread _thread;
public TestTimer()
{
// create and initializing timer. but not started!
_timer = new Timer();
_timer.Tick += TickHandler;
_timer.Interval = 60000; // 1 minute
// create and start new thread
_thread = new Thread(SomeMethod);
_thread.Start();
}
private void TickHandler(object sender, EventArgs e)
{
// stop timer
_timer.stop();
//some handling
// run background thread again
_thread = new Thread(SomeMethod);
_thread.Start();
}
private void SomeMethod()
{
// some operations
// start timer!
TimerStart();
}
private void TimerStart()
{
_timer.Start();
}
}
By monkey method I found if add Delegate like this
internal delegate void TimerDelegate();
And replace string
TimerStart();
with
Application.Current.Dispatcher.Invoke(new TimerDelegate(TimerStart), null);
all works fine. Somebody can explain me what is the trick?
You've got things mixed up a bit.
If you want a timer that fires on a background thread, you don't have to create a thread to start it (it doesn't matter which thread calls the Start method). Just use System.Timers.Timer, and each Elapsed event will occur on a thread-pool thread.
If you want a timer that fires on the UI thread, since it looks like you're using WPF, you should use System.Windows.Threading.DispatcherTimer, and not the Windows Forms timer you've been using. You should create the timer (i.e. call new) on a particular UI thread, and every Tick event will occur on that thread. Again, it doesn't matter from which thread you call Start.
Here's an explanation of what's happening in your code: You're starting a Windows Forms timer on a non-UI thread. This kind of timer requires a message pump to be running on that thread so it can receive messages. Because it's a non-UI thread, there's no message pump. When you used the Dispatcher.Invoke method, you marshaled the creation of the timer back to the application's main UI thread, which made it work. But it is all quite redundant. If you want to keep the code as is, just replace the timer with a DispatcherTimer, and then you'll be able to remove the Invoke call.
Alternatively, if you're using .NET 4.5 you could use await/async to make this all much easier (be sure to call SomeMethod from the UI thread):
async Task SomeMethod(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
await Task.Run(() => DoAsyncStuff(), ct);
DoUIStuff();
await Task.Delay(TimeSpan.FromMinutes(1), ct);
}
}
MSDN can explain it for you:
Note The Windows Forms Timer component is single-threaded, and is
limited to an accuracy of 55 milliseconds. If you require a
multithreaded timer with greater accuracy, use the Timer class in the
System.Timers namespace.

Creating a background timer to run asynchronously

I'm really struggling with this. I'm creating a winforms application in visual studio and need a background timer that ticks once every half hour - the purpose of this is to pull down updates from a server.
I have tried a couple of different approaches but they have failed, either due to poor tutorial/examples, or to my own shortcomings in C#. I think it would be a waste of time to show you what I have tried so far as it seems what I tried was pretty far off the mark.
Does anyone know of a clear and simple way of implementing an asynchronous background timer that is easily understandable by a C# newbie?
// Create a 30 min timer
timer = new System.Timers.Timer(1800000);
// Hook up the Elapsed event for the timer.
timer.Elapsed += OnTimedEvent;
timer.Enabled = true;
...
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
// do stuff
}
with the usual caveats of: timer won't be hugely accurate and might need to GC.KeepAlive(timer)
See also: Why does a System.Timers.Timer survive GC but not System.Threading.Timer?
Declare member variable in your form:
System.Timers.Timer theTimer;
On form load (or whatever other time you need to start update polling), do:
theTimer = new System.Timers.Timer(1800000);
theTimer.Elapsed += PollUpdates;
theTimer.Start();
Declare your PollUpdates member function like this:
private void PollUpdates(object sender, EventArgs e)
{
}
I think you need to know about all timer classes. See Jon's answer below.
What kind of timer are you using?
System.Windows.Forms.Timer will execute in the UI thread
System.Timers.Timer executes in a thread-pool thread unless you
specify a SynchronizingObject
System.Threading.Timer executes its callback in a thread-pool thread
In all cases, the timer itself will be asynchronous - it won't "take up" a thread until it fires.
Source: Do .NET Timers Run Asynchronously?

How to use signalling mechanism for performing intensive work (that do not overlap) with a thread and manualresetevent in C#?

I have an existing application with 1 thread running some intensive work in the background every numOfMinutesInterval. This was previously done using Thread.Sleep (sleeping for the entire interval period) but I've read that Thread.Sleep is evil and it's sloppy design, so I wanna change to a signalling mechanism. Below is the code I just wrote (using dispatcher timer from wpf, but I think in this small scenario it's the same for winforms timer as well).
The dispatcher (running in the UI thread) ticks every second, and inside the tick function it checks whether interval has passed, and if so, it will signal the manualresetevent Set(). I'm wondering if this is bad design if the intensive work extends pass the interval period? If I set the numOfMinutesInterval = 1, but the work took 1 minute and 1 second, does that mean we'll skip 1 set() call, since the tick is attempting to set() the event while work is still being done and the worker thread is not yet blocking.
Please notice also that I've set lastWorkDoneTime = DateTime.Now; after calling Set(), should I move it to the worker thread instead (calling lastWorkDoneTime = DateTime.Now; just before manualResetEvent.WaitOne();)?
If this is bad design, what should I do to change it? Thanks for reading!
//thread work done here
private void MyDoWork_ThreadStart()
{
while(FlagApplicationStillRunning == true)
{
//do the intensive work here
manualResetEvent.WaitOne();
}
}
// tick every second
private int numOfMinutesInterval = 1;
private DateTime lastWorkDoneTime = DateTime.Now;
private void DispatcherTimer_Tick(object sender, EventArgs e)
{
if((DateTime.Now - lastWorkDoneTime).Minutes > numOfMinutesInterval)
{
manualResetEvent.Set();
lastWorkDoneTime = DateTime.Now;
}
}
You could just start a task and have that perform the intensive work.
private void DispatcherTimer_Tick(object sender, EventArgs e)
{
if ((DateTime.Now - lastWorkDoneTime).Minutes > numOfMinutesInterval)
{
Task.Factory.StartNew(DoIntensiveWork());
lastWorkDoneTime = DateTime.Now;
}
}
As far as setting the lastWorkDoneTime that is up to you. If you set it in what fires off the task, you have the possibility of two or more tasks running at the same time performing the work. If you set it at the end of the function performing the work you introduce a delay that is based on how long it takes to complete the work.
I would actually look into using one of the timer objects and let that handle the timing for you instead of using the DispatcherTimer_Tick event. There is System.Timers.Timer, System.Threading.Timers, and others.
To help determine what timer option would work best for you:
Comparing the Timer Classes in the .NET Framework Class Library

Awaken a task while sleeping

I have a task that runs periodically 10 second. I do some picturebox refreshing processes by reading database. What i want is to invoke or awaken the thread and do the refresh operation when i click a button immidiately. In short, i want the refresh task to be driven by not only time but also event together. Is this possible? If yes, how? The code block for the task is shown below.
while (true)
{
// do some refresh operation
Thread.Sleep(10000);
}
void button1_Click(object sender, EventArgs e)
{
// invoke or awaken thread
}
First off I'd advise you to drop the Thread + Sleep + Invoke combo for timed operations. It's very ugly. There are timer classes for both WinForms and WPF to do these three things automatically (update the GUI periodically from the dispatcher thread). Check out System.Windows.Forms.Timer and System.Windows.Threading.DispatcherTimer.
Now for your specific question, you could simply define a common method for updating the GUI with what you need and call it both from the timer code and from a button handler.
Create an AutoResetEvent:
protected AutoResetEvent _threadCycle;
_threadCycle = new AutoResetEvent(false);
when you want to wait do:
_threadCycle.WaitOne(delay, false);
and when you want to set the event, effectually letting the thread to continue:
_threadCycle.Set();
BONUS:
when you do _threadCycle.WaitOne(delay, false); you will get a return value, true or false, that you can check to see if the timeout did expire or you are continuing because of the manually set event.
BTW:
that will ONLY work if you are doing your task in an alternate thread. If you use main thread, you will get stuck with waiting for the timeout completion anyway. Maybe it will be the best to use #Tudors answer, and get this option only as 'through the thorns' way.
You should use a AutoResetEvent for this.
What you do is something like (assuming your AutoResetEvent is called 'signal'):
while (true)
{
signal.WaitOne(10000);
...
}
And in your button handler, just do:
signal.Set();

Categories

Resources