Wait for x seconds in while loop c# - c#

Im trying to make a simple application to learn some things in c# (Visual Studio).
For now i am building a music player, and one of the actions is fading out the music at the button click event.
I've got no problem with building a fade-out part, i made a while loop and put the volume down with 1% eacht time the loop is running. Also i update a label with the fade value.
Only problem is, for slowing down the fading i'm using the Thread.Sleep event, and that part is freezing my application, and also is blocking any updates to my text label with the fade value.
The fading is working fine, so the only part I have to work on is another option to build some delay in. On some topics over here i did read about the timer, and i added a timer component in Visual Studio. Only problem, I am new to c# and don't know how to use it correctly in this while loop.
Can anybody give me some help?
The current code is:
private void BtnPodiumtune1Fadeout_Click(object sender, EventArgs e)
{
PlayerPodiumtune1.settings.volume = 100;
fade1 = 100;
while (fade1 != -1)
{
PlayerPodiumtune1.settings.volume = fade1;
Fadelevel1.Text = fade1.ToString();
System.Threading.Thread.Sleep(30);
fade1 = fade1 - 1;
}
PlayerPodiumtune1.Ctlcontrols.stop();
}

You could use a pattern like this instead of a timer. A timer is a fine way to go, just throwing this option out there:
private async void button_Click(object sender, EventArgs e)
{
if (Monitor.TryEnter(sender))
{
int fade1 = 1000;
while (fade1 != -1)
{
await Task.Delay(30);
fade1--;
}
}
}
So sender is the button, and Monitor.TryEnter prevents the function from being run again until the function is done. async tells the framework that this function can be executed asynchronously and is necessary for await. await returns control of the thread to the UI until the task is done.
PS--You're going to need something like Monitor.TryEnter to prevent re-entrancy in a timer-based solution as well, by the way.

This is a Console Application in C#:
using System;
namespace WaitAsync
{
class Program
{
static void Main(string[] args)
{
bool ok = false;
Console.Write("EnterTime (Seconds): ");
int time = Convert.ToInt32(Console.ReadLine()) * 1000;
while (ok != true)
{
System.Threading.Thread.Sleep(time);
ok = true;
Console.WriteLine("Waiting Time Just Finished");
}
Console.ReadLine();
}
}
}

Related

Need to click button twice to have an effect

The application is a machine control, so it needs access to ui to show status etc. (I know, goes against the recommendation to separate UI and work code, but it is what it is, at least for now). The issue boils down to this: When one button event handler is not finished, another button needs to be clicked twice. First click gives the focus to the button, next click fires the event.
Here is the issue simplified to extreme. There are two buttons and a label. Stop button needs two clicks to stop the machine:
bool Stop = true;
private void Start_button_Click(object sender, EventArgs e)
{
RunMachine();
}
private void Stop_button_Click(object sender, EventArgs e)
{
Stop = true;
}
private void RunMachine()
{
Stop = false;
Status_label.Text = "Running";
do
{
Application.DoEvents();
Thread.Sleep(50);
}
while (!Stop);
Status_label.Text = "Stopped";
}
How can I make the button to react to the first click?
DoEvents() is bad. Don't use it.
If you have to use it (e.g. as workaround), then you are adding technical debt and likely to pay in the future, similar to your case.
A better approach is to run work inside the task and use cancellation token, but in your case the minimum modification required is this (add async modifier to a method):
while (!Stop)
{
await Task.Delay(50);
// or
await Task.Run(() => Thread.Sleep(50));
}
The UI should be responsive now.
The latter is simulating synchronous code, put it instead of Sleep, don't forget to invoke if there you have to modify UI.
Thank you! I wasn't aware of the implications of Doevents, and using async and await is just as simple. I added a counter to show myself that the toy example is doing what I think it is. To make the answer complete and to help other noobs like me that might search answers for the same issue, here is the full example again. This works as wanted (stops with one click) and doesn't leave the RunMachine() running if the main form is closed without clicking stop. (My real application has enough code in the form closing event to prevent that, but I certainly wasn't aware of the trap.)
bool Stop = true;
private async void Start_button_Click(object sender, EventArgs e)
{
await RunMachine();
}
private void Stop_button_Click(object sender, EventArgs e)
{
Stop = true;
}
internal async Task RunMachine()
{
Status_label.Text = "started";
Stop = false;
int i=0;
do
{
await Task.Delay(500);
Status_label.Text = i.ToString();
i++;
} while (!Stop);
Status_label.Text = "Stopped";
}

(WPF) How to ping from a class in c#?

I'm creating a WPF tool to use on my HelpDesk team using XAML and C#, but I'd like to improve upon what I've done. I've got a textbox to enter a hostname, a button to start a ping, and a textbox that will keep pinging that hostname until I press the button again.
I'd like to keep the functionality the same, but I know there's a better way to write this code.
Currently, I have a class that pings the server and returns a response ONE single time. My main form calls this class, the logic is not written in the main form. When I tried to make this loop, it just kills the function after the first run through rather than looping. The way I got it to work was by using a timer to call the function/ping class every 500 MS or so, and stopping the timer by clicking the button again.
Here's my current way of doing this, t stands for "timer":
private void onTick(object sender, EventArgs e)
{
PingClass pingClass = new PingClass();
_richtext.AppendText(pingClass.PingHost(_textBox.Text));
_richtext.ScrollToEnd();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if ((string)_pingBtn.Content == "Ping")
{
_richtext.Visibility = Visibility.Visible;
_pingBtn.Content = "Stop Ping";
t.Interval = 500;
t.Tick += onTick;
t.Start();
}
else if ((string)_pingBtn.Content == "Stop Ping")
{
_richtext.Visibility = Visibility.Hidden;
_pingBtn.Content = "Ping";
t.Stop();
}
The class itself is pretty simple, it just returns a string of whatever the response from the host is. Unfortunately, it doesn't allow me to loop through inside the class because it stops at the first return. I'd like to gather an "average ping" and some other stats, but can't with the way it's currently set up. I don't want to have a timer, I want to be able to loop in the class itself until the button in the main form is pressed. Is this possible?

Delay function in C#

I need to understand how can I create delays between a set of commands. My background is with C (DOS) and now reviving the concepts using C# in Visual Studio 2015. This is the code I am struggling with:
using System.Threading;
private void button1_Click(object sender, EventArgs e) // Button
{
int i;
for (i = 0; i < 10; i++)
{
textBox1.BackColor = Color.Red;
Thread.Sleep(100);
textBox1.BackColor = Color.Yellow;
Thread.Sleep(100);
}
}
I was expecting the background color of the textbox will change alternatively 10 times but I could see only yellow color after the loop finishes. If I increase delay I do notice that program takes time to finish. I went through some related articles but couldn't get the point. Any help will be appreciated. Thanks
Use an async method to create a delay using the built-in Task.Delay method. This will cause execution to be paused and then resumed after the specified time without blocking the current thread.
async Task UseDelay()
{
await Task.Delay(1000); // wait for 1 second
}
In your specific case
async void button1_Click(object sender, EventArgs e)
{
for (var i = 0; i < 10; i++)
{
textBox1.BackColor = Color.Red;
await Task.Delay(100);
textBox1.BackColor = Color.Yellow;
await Task.Delay(100);
}
}
The problem isn't with the delaying, it's with the threading model of UI applications. In a UI application, any event handlers happen on the "UI thread". While that code is running, the UI is essentially frozen, so nothing you do there matters.
That means if you "Sleep" in there, the entire application will lock up and be unresponsive until it returns.
But you can make your event handlers "async void" instead of just "void" if they need to do long running work. Then if you await Task.Delay(someTime) instead of Thread.Sleep(someTime), it will release the UI thread while that's happening. And you should see what you expect without the UI locking up.
Also, that time is in milliseconds, meaning wait "one tenth of a second". Which is really, really fast. You might want to slow it down a bit to get the effect you want.

C# BackgroundWorker

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);
}

Automatically call a task every 5 seconds

i have an Infragistics carousel control which i want to call "next" on every 5 seconds. However im not sure how to do this without a while true.
Any help would be great, thanks!
Currently its kicked off from a click, starting a task within a while true. Obviously this i what i want to avoid.
private void GoToNext(object sender, MouseButtonEventArgs e)
{
while (true)
{
Task task = new Task(() => MyCarousel.Dispatcher.BeginInvoke(new next(goToNext), null));
task.Start();
}
}
private bool goToNext()
{
Thread.Sleep(15);
MyCarousel.ExecuteCommand(Infragistics.Windows.Controls.XamCarouselPanelCommands.NavigateToNextItem);
return true;
}
Timers are used for this in general, sitting in the background and triggering every so often. There are a number in .NET (in System.Timers and elsewhere) and which one is best depends on your particular scenario.

Categories