I am using a loop in a timer and trying to add the delay in it.But it not working
.And I don't want to use Thread.sleep() because my UI will freeze
My code :
private void Button1_Click(object sender, EventArgs e)
{
timer1.Start();
}
private void Timer1_Tick(object sender, EventArgs e)
{
DoStuff();
}
private void DoStuff()
{
foreach (ListViewItem item in ListView1.Items)
{
if(item.subitem[1].Text == 0)
{
MessageBox.Show("Hello")
//Trying to add the delay here!!
}
}
}
I am trying to use private async void DoStuff()
and add await Task.Delay(milliseconds); to the loop too.But its not working because Timer1 will call DoStuff every Tick by ignoring the delay.(Tested Already)
The test code (Not Working) :
private void Button1_Click(object sender, EventArgs e)
{
timer1.Start();
}
private void Timer1_Tick(object sender, EventArgs e)
{
DoStuff();
}
private async void DoStuff()
{
foreach (ListViewItem item in ListView1.Items)
{
if(item.subitem[1].Text == 0)
{
MessageBox.Show("Hello")
await Task.Delay(1000);
}
}
}
My question is how can I add the delay in this loop by not moving all DoStuff Code to be in timer (Just add the delay by not changing the code position).
As I wrote. You need to define your methods as tasks. The button code has a Task called DoStuff1. Also that means the button has to do be defined as async. Bascailly your entire issue is asynchronous programming(google that - there are many good examples out there). This way your UI wont freeze. And you can still use other buttons or texts in the UI.
public partial class Form1 : Form
{
List<string> strings = new List<String>() { "Hello", "world", "!" };
public Form1()
{
InitializeComponent();
}
private async void button1_Click(object sender, EventArgs e)
{
string returnString = await DoStuff1();
}
private async Task<string> DoStuff1()
{
foreach (string s in strings)
{
MessageBox.Show(s);
await Task.Yield();
await Task.Delay(1000);
}
return "ASYNC DONE";
}
}
[EDIT]Like this?
public partial class Form1 : Form
{
System.Timers.Timer t = new System.Timers.Timer(1000);
List<string> strings = new List<String>() { "Hello", "world", "!" };
public Form1()
{
InitializeComponent();
}
private async void button1_Click_1(object sender, EventArgs e)
{
System.Timers.Timer t = new System.Timers.Timer(1000);
t.Elapsed += async (s, ev) => await DoStuff1();
t.Start();
//t.Stop(); //Stop immediately after and then you can add delays in DoStuff1() if you want to.
}
private async Task<string> DoStuff1()
{
foreach (string s in strings)
{
MessageBox.Show(s);
}
return "ASYNC DONE";
}
}
Related
I want to know the the task status runnning in A button event from the other button click.
Like this.
private void button1_Click(object sender, EventArgs e)
{
Task.Run(()=>{
//The method to take long time
//For example
Thread.Sleep(5000)
;});
}
private coid button2_Click(object sender, EventArgs e)
{
//until 5000ms
//the method to know the above task status (Runnning....)
//after 5000ms
//the method to know the above task status (Conpleted....)
}
It's not entirely clear what you're trying to achieve, but if you want to check the status of the task, you can get its reference when calling Task.Run()
private Task _task;
private void button1_Click(object sender, EventArgs e)
{
_task = Task.Run(() => Thread.Sleep(5000));
}
private void button2_Click(object sender, EventArgs e)
{
if (_task?.Status == TaskStatus.RanToCompletion)
//do something
}
The answer is as vague as the question, so if you could give me a bit more details, I could come up with a better more tailored answer.
Again, it's very unclear what you're looking for here...but this is an expanded version of Faylit's example:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private Task T = null;
private void Form1_Load(object sender, EventArgs e)
{
updateStatus();
}
private async void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
await (T = Task.Run(() =>
{
updateStatus();
System.Threading.Thread.Sleep(5000);
}));
button1.Enabled = true;
updateStatus();
}
private void button2_Click(object sender, EventArgs e)
{
updateStatus();
}
private void updateStatus()
{
if (label1.InvokeRequired)
{
label1.Invoke((MethodInvoker)delegate
{
updateStatus();
});
}
else
{
if (T == null)
{
label1.Text = "Task not started.";
}
else if (!T.IsCompleted)
{
label1.Text = "Task running...";
}
else
{
label1.Text = "Task completed.";
}
}
}
}
It might give you some more ideas.
This question already has answers here:
Using BackgroundWorker to complete two methods one after the other WPF/C#
(2 answers)
Closed 5 years ago.
I want to call backgroundWorker1.RunWorkerAsync() function for two functions one after other but I got this error :
"This BackgroundWorker is currently busy and cannot run multiple tasks concurrently."
I know what's problem. Is there any way to do this? This is a sample from what I want to do, in fact there is many strings and many functions that one come after other.
If it's not possible how can I create a windowsForm to show me my first String[] elements one by one in a label and when it's done start again and show my second string[] elements in same label?
public Form1() {
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
looking();
}
public void looking()
{
a();
b();
}
public void a()
{
string[] stringArray = { "Ali", "Hasan", "Morad", "Javad" };
backgroundWorker1.RunWorkerAsync(stringArray);
}
public void b()
{
string[] stringArray2 = { "Ali2", "Hasan2", "Morad2", "Javad2", "Mahmood", "Shaparak" };
backgroundWorker1.RunWorkerAsync(stringArray2);
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
...
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
...
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
...
}
using Backgroundworker is no more considered a good practice today. Take a look at async and await
in your case, you can try this
based on your update you can achieve this
private async void button1_Click(object sender, EventArgs e)
{
await lookingAsync();
}
public async Task lookingAsync()
{
string[] stringArray = { "Ali", "Hasan", "Morad", "Javad" };
foreach (var item in stringArray)
{
label1.Text = item;
await Task.Delay(1000);
}
string[] stringArray2 = { "Ali2", "Hasan2", "Morad2", "Javad2", "Mahmood", "Shaparak" };
foreach (var item in stringArray2)
{
label1.Text = item;
await Task.Delay(1000);
}
//if you want it in a loop just uncomment this
// await lookingAsync();
}
I don't think the following question is rarely seen. But since I don't know how to search for the right answer, so I'm still stuck on it.
I have a label in the form and I want to show something before another job is invoked:
private void btnLoadEvent_Click(object sender, EventArgs e)
{
lbStatus.Text = "Loading... ";
load();
}
private void load()
{
Thread.Sleep(5000);
lbStatus.Text = "Done";
}
The label won't show anything before load() is complete.
Then I changed my program usnig async/await:
private async void btnLoadEvent_Click(object sender, EventArgs e)
{
lbStatus.Text = "Loading... ";
await load();
}
private async Task load()
{
Thread.Sleep(5000);
lbStatus.Text = "Done";
}
It doesn't change anything. Does anyone have any idea?
2014/4/3:
As a note, I think I've figured out how async/await works. And to avoid misleading any possible reader, I list my final solution as follows:
private async void btnLoadEvent_Click(object sender, EventArgs e)
{
lbStatus.Text = "Loading... ";
string content = await loadAsync();
}
private async Task<string> loadAsync()
{
using (WebClient webClient = new WebClient())
{
string json = await webClient.DownloadStringTaskAsync(
"http://api.openweathermap.org/data/2.5/weather?q=Taipei,tw");
lbStatus.Text = "Done";
return json;
}
}
In practice, to meet the Decoupling Principle, "lbStatus.Text = ... " could be better moved from loadAsync() to btnLoadEvent_Click() although it works fine.
And thanks everyone who helped.
You didn't really go async. Thread.Sleep is blocking and because your async function never yields it will still block the call site. Use await Task.Delay(... instead.
private void btnLoadEvent_Click(object sender, EventArgs e)
{
lbStatus.Text = "Loading... ";
load();
}
private async Task load()
{
await Task.Delay(5000);
lbStatus.Text = "Done";
}
Try using a BackgroundWorker . Set your label.Text to Loading before executing the BackgroundWorker's RunWorkerAsync method. Do your stuff (like your Thread.Sleep(5000)) in the Do_Work event and change the status of your label in the RunWorkerCompleted event. Visit this link to see an example.
You need to use BackgroundWorker. Something like that.
private void button1_Click(object sender, EventArgs e)
{
label1.Text = "Loading";
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
load();
}
private void load()
{
System.Threading.Thread.Sleep(1000);
if(InvokeRequired)
this.Invoke(new Action(()=>label1.Text = "Done"));
}
I want this part of my program (I showed in code by "//" sign before the line) to wait until button3 is clicked to resume.
private void button2_Click(object sender, EventArgs e)
{
if (this.textBox3.Text != "")
{
this.listView1.Items.Clear();
//this.listView1.Items.Add(this.textBox3.text);
}
}
Seems like you want something like this:
private void button2_Click(object sender, EventArgs e)
{
if (this.textBox3.Text != "")
{
this.listView1.Items.Clear();
button3.Click += Function;
}
}
private void Function(object sender, EventArgs e)
{
this.listView1.Items.Add(this.textBox3.text);
button3.Click -= Function;
}
So we'll start out with this helper method that produces a task that will be completed when a button is clicked:
public static Task WhenClicked(this Button button)
{
var tcs = new TaskCompletionSource<bool>();
EventHandler handler = null;
handler = (sender , args) =>
{
tcs.SetResult(true);
button.Click -= handler;
};
button.Click += handler;
return tcs.Task;
}
Using this, along with await from C# 5.0, we can create code that reads just like what you requested, even though it produced code similar to what the other answers have (thus maintaining asynchrony and not blocking the UI thread).
private async void button2_Click(object sender, EventArgs e)
{
if (this.textBox3.Text != "")
{
this.listView1.Items.Clear();
await button3.WhenClicked();
this.listView1.Items.Add(this.textBox3.text);
}
}
hey i am new to c# plz help.
i am writing a program that sorts data in a file and it is a time consuming process so i thought that i should run it in a separate thread and since it has alot of step so i made a new class for it. the problem is that i want to show the progress in the main GUI and i know for that i have to use Invoke function but the problem is that the form control variables are not accessible it this class. what should i do ??????
sample code:
public class Sorter
{
private string _path;
public Sorter(string path)
{
_path = path;
}
public void StartSort()
{
try
{
processFiles(_path, "h4x0r"); // Just kidding
}
catch (Exception e)
{
MessageBox.Show("Error: " + e.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void processFiles(string Dir, string[] key)
{
/* sorting program */
}
and it is used as
public partial class Form1 : Form
{
Sorter sort;
public Form1()
{
InitializeComponent();
}
private void browseBtn_Click(object sender, EventArgs e)
{
if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
textBox1.Text = folderBrowserDialog1.SelectedPath;
}
private void startBtn_Click(object sender, EventArgs e)
{
if (startBtn.Text == "Start Sorting")
{
Thread worker = new Thread(new ThreadStart(delegate() {
sort = new Sorter(textBox1.Text);
sort.StartSort(); }));
worker.start();
}
else
MessageBox.Show("Cancel");//TODO: add cancelling code here
}
}
plz help..
Add an Event to your class that is doing the multi-threaded work, that triggers when the progress changes. Have your form subscribe to this event and update the progress bar.
Note ProgressEventArgs is a little class that inherits EventArgs and has an Integer for the progress.
// delegate to update progress
public delegate void ProgressChangedEventHandler(Object sender, ProgressEventArgs e);
// Event added to your worker class.
public event ProgressChangedEventHandler ProgressUpdateEvent
// Method to raise the event
public void UpdateProgress(object sender, ProgressEventArgs e)
{
ProgressChangedEventHandler handler;
lock (progressUpdateEventLock)
{
handler = progressUpdateEvent;
}
if (handler != null)
handler(sender, e);
}
I would recommend you read up on the BackgroundWorker class. It is exactly for the problem you are trying to solve and makes things a lot easier than doing manual threading yourself.
Brief Example
public Form1()
{
InitializeComponent();
backgroundWorker.WorkerReportsProgress = true;
backgroundWorker.WorkerSupportsCancellation = true;
backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
}
void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
private void btnStart_Click(object sender, EventArgs e)
{
if (!backgroundWorker.IsBusy)
backgroundWorker.RunWorkerAsync();
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 1; i < 101; ++i)
{
if (backgroundWorker.CancellationPending)
{
e.Cancel = true;
break;
}
else
{
//Sort Logic is in here.
Thread.Sleep(250);
backgroundWorker.ReportProgress(i);
}
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
if (backgroundWorker.IsBusy && backgroundWorker.WorkerSupportsCancellation)
backgroundWorker.CancelAsync();
}
You could do something like this:
public delegate void StatusReporter(double progressPercentage);
public class MainClass
{
public void MainMethod()
{
Worker worker = new Worker(ReportProgress);
ThreadStart start = worker.DoWork;
Thread workThread = new Thread(start);
workThread.Start();
}
private void ReportProgress(double progressPercentage)
{
//Report here!!!
}
}
public class Worker
{
private readonly StatusReporter _reportProgress;
public Worker(StatusReporter reportProgress)
{
_reportProgress = reportProgress;
}
public void DoWork()
{
for (int i = 0; i < 100; i++ )
{
// WORK, WORK, WORK
_reportProgress(i);
}
}
}
There are a few option available to solve this sort of issue. In any case, you will have to fiddle with Invoke to get the UI to update.
You could...
...add an event that fires on your new class which your UI can listen to, and Invoke as applicable - you'd still need to pass the data to your worker class (by constructor, properties, method call, etc)
...keep the method as a method on your form, and pas that to start your new thread from (after all, a new thread doesn't have to be starting in a different class)
...change the access modifiers on your controls to be (say) internal such that any class within the same assembly can Invoke changes to the controls, or read from them.
...make your worker class a child of the form it needs to access - it can then see the privates of its parent, as long as it is passed a reference to the instance.