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 some words simultaneously
public string[] words = new string[]{"add", "ado", "age", "ago", "aid", "ail", "aim", "air", "and", "any", "ape", "apt", "arc", "are", "ark", "arm",
"art", "ash", "ask", "auk", "awe", "awl", "aye", "bad", "bag", "ban", "bat", "bee", "boa", "ear", "eel", "eft",
"far", "fat", "fit", "lee", "oaf", "rat", "tar", "tie"};
private async void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i <= 39; i++)
{
label1.Text = words[i];
Thread.Sleep(100);
}
}
The label just show "eft" and won't show anything before "for" is complete.
Ideally you should be using a System.Windows.Forms.Timer to update - otherwise you are blocking the main thread. However, you can call Form.Refresh to force an update in your loop.
You may use Task.Delay that would not block the UI thread:
private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
for (var i = 0; i <= 100; i++)
{
((Button) sender).Content = i.ToString();
await Task.Delay(100);
}
}
Using this solution would not require any extra threads to be created, so it should be more efficient.
Try this
private async void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 100; i++)
{
label1.Text = i.ToString();
await Task.Run(() => { Thread.Sleep(100); });
}
}
This will work
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i <= 100; i++)
{
Application.DoEvents();
label1.Text = i.ToString();
Thread.Sleep(100);
}
}
call Application.DoEvents() in your code, so your app can handle the other events
You can use System.Threading.Timer:
System.Threading.Timer timer;
int i=-1;
public string[] words = new string[]{"add", "ado", "age", "ago", "aid", "ail", "aim", "air", "and", "any", "ape", "apt", "arc", "are", "ark", "arm",
"art", "ash", "ask", "auk", "awe", "awl", "aye", "bad", "bag", "ban", "bat", "bee", "boa", "ear", "eel", "eft",
"far", "fat", "fit", "lee", "oaf", "rat", "tar", "tie"};
private async void button1_Click(object sender, EventArgs e)
{
timer = new System.Threading.Timer(timer_Tick, null, 0, 100); //Time delay 100
}
private void timer_Tick(Object state)
{
try
{
i++;
this.Invoke((MethodInvoker)delegate
{
label1.Text = words[i];
if (i==words.Length )
timer.Change(Timeout.Infinite, Timeout.Infinite);
});
}
catch (Exception ex)
{
}
finally
{
}
}
ThreadStart safir ;
Thread Nakh;
delegate void kar(string p);
private void button1_Click(object sender, EventArgs e)
{
safir = new ThreadStart(NeveshtanDarBarchasb);
Nakh = Thread(safir);
Nakh.Start();
}
public void NeveshtanDarBarchasb()
{
for (int i = 0; i <= 39; i++)
{
Benevis(I.ToString());
Thread.Sleep(100);
}
}
public void Benevis(string p)
{
if( lbl.InvokeRequired)
{
kar k= new kar(Benevis);
Invoke(k,new object[]{p};
}
else
{
label1.Text = p;
}
}
Related
Is it bad practice to write code like this. What I want to accomplish is that a user can press a button on a control. The button starts some kind of analyzing process and for each item done it shows a result to the user.
private IEnumerable<int> AnalyzeItems() {
for(int i = 0; i < 1000; i++) {
Thread.Sleep(500);
yield return i;
}
}
private void PerformTask_Click(object sender, EventArgs e) {
Task.Run(() => {
foreach (var item in AnalyzeItems()) {
ResultLog.Invoke((Action)delegate() { ResultLog.Text += item.ToString(); });
}
});
}
why do not use Backgroundworker?
First setup the backgroundworker properties to:
WorkerReportsProgress = true
WorkerSupportsCancellation = true
This is the code:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
for (int i = 0; i < 1000; i++) {
Thread.Sleep(500);
if (backgroundWorker1.CancellationPending) {
e.Cancel = true;
break;
}
backgroundWorker1.ReportProgress(i / 10, "step " + i);
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) {
label1.Text = e.UserState.ToString();
progressBar1.Value = e.ProgressPercentage;
}
private void button1_Click(object sender, EventArgs e) {
cancelButton.Focus();
button1.Enabled = false;
backgroundWorker1.RunWorkerAsync();
}
private void cancelButton_Click(object sender, EventArgs e) {
backgroundWorker1.CancelAsync();
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
button1.Enabled = true;
if (e.Error != null) {
MessageBox.Show(e.Error.Message, "Unexpected error");
}
if (e.Cancelled) {
MessageBox.Show("Process stopped by the user", "Cancelled");
}
label1.Text = "Press start";
progressBar1.Value = progressBar1.Minimum;
}
}
Is your approach bad practice? It depends.
If you don't expect your code inside Task.Run to throw any exceptions and you want to continue doing something else, then your code is ok. However, if you want to capture any possible exceptions and wait for the process to finish without freezing UI, then you might want to consider using async/await.
private async void PerformTask_Click(object sender, EventArgs e) {
try
{
await Task.Run(() => {
foreach (var item in AnalyzeItems()) {
ResultLog.Invoke((Action)delegate() { ResultLog.Text += item.ToString(); });
}
});
}
catch(Exception ex)
{
// handle...
}
}
Alternative approach would be to use IProgress<T>. This allows for easy separation of long running work and updating UI. Please note that you shouldn't call this method too often, because
This will put too much work on UI thread resulting in UI freeze.
If you pass any valuetype to IProgress<T>.Report method, then it gets copied. If you call this too often, you risk running garbage collector very often resulting in even bigger freezes.
All of this means that you should utilize IProgress only for truly long running work.
Now that we have it all out of the way, here is a sample of how you could notify users about progress of analyzed items:
private double _currentProgress;
public double CurrentProgress {
get => _currentProgress;
set
{
_currentProgress = value;
NotifyPropertyChanged();
}
}
private async void PerformTask_Click(object sender, EventArgs e)
{
var progress = new Progress<double>();
progress.ProgressChanged += (sender, p) => CurrentProgress = p;
await Task.Run(() => AnalyzeItems(Enumerable.Range(0, 5000).ToList(), progress));
}
private void AnalyzeItems(List<int> items, IProgress<double> progress)
{
for (int itemIndex = 0; itemIndex < items.Count; itemIndex++)
{
// Very long running CPU work.
// ...
progress.Report((double)itemIndex * 100 / items.Count);
}
}
If AnalyzeItems takes less than 100 ms for individual item, then you don't want to report after every finished item (see why above). You can decide how often you want to update status like this:
private void AnalyzeItems(List<int> items, IProgress<double> progress)
{
var lastReport = DateTime.UtcNow;
for (int itemIndex = 0; itemIndex < items.Count; itemIndex++)
{
// Very long running work.
Thread.Sleep(10);
// Tell the user what the current status is every 500 milliseconds.
if (DateTime.UtcNow - lastReport > TimeSpan.FromMilliseconds(500))
{
progress.Report((double)itemIndex * 100 / items.Count);
lastReport = DateTime.UtcNow;
}
}
}
If you have really a lot of very fast iterations, you may want to consider changing DateTime.Now to something else.
private void _btnOK_Click(object sender, EventArgs e)
{
_label1.Hide();
_label2.Hide();
_label3.Hide();
for(int i = 1; i <= 100; i++)
{
Thread.Sleep(5);
_circularprogressbar.Value = i;
_circularprogressbar.Update();
}
}
private void LoadingScreen_Load(object sender, EventArgs e)
{
_circularprogressbar.Value = 0;
_circularprogressbar.Minimum = 0;
_circularprogressbar.Maximum = 100;
}
}
}
This is my code. What i want to do is, i want to have a text inside the progress bar that shows the percentage of the progress from 1 to 100 percent.
what can i add to my code?
thank you
Here is what i would do:
private void _btnOK_Click(object sender, EventArgs e)
{
_label1.Hide();
_label2.Hide();
_label3.Hide();
for(int i = 1; i <= 100; i++)
{
_circularprogressbar.Value = i;
_percent_lable_name.Text = string.Format("{0}%", _circularprogressbar.Value);
_circularprogressbar.Update();
}
}
private void LoadingScreen_Load(object sender, EventArgs e)
{
_circularprogressbar.Value = 0;
_circularprogressbar.Minimum = 0;
_circularprogressbar.Maximum = 100;
}
}
See if that helps you!
Thanks
Techcraft7 :)
That Thread.Sleep(5) is blocking your entire UI thread. If you want to have your UI responsive, while the progress takes place, you need to make a separate thread for it. Something like this:
private void _btnOK_Click(object sender, EventArgs e)
{
_label1.Hide();
_label2.Hide();
_label3.Hide();
Task.Factory.StartNew(() =>
{
for (int i = 1; i <= 100; i++)
{
Thread.Sleep(5);
Invoke((Action)(() =>
{
_circularprogressbar.Value = i;
_circularprogressbar.Update();
}));
}
});
}
Note that you will need t use Invoke to BeginInvoke to access UI components from inside that thread.
hey after long research i come up with a way to cancel thread but i face a problem when i cancel thread here is my code first.so for example when i click on button3 while form working its killing the process but it gives me an error (chrome unrechable)
public void test1()
{
var dr = new chromdriver();
dr.navigate().GoToUrl("http://google.com");
if(xx != null)
{
IWebElement emal = dr.FindElement(By.XPath("//[#id=\"Email\"]"));
emal.Sendkeys(email)
}
else{
IWebElement emal = dr.FindElement(By.XPath("//[#id=\"Email\"]"));
emal.Sendkeys(email)
}
}
private void button2_Click(object sender, EventArgs e)
{
thread thr = new thread(test1);
thr.Start();}
private void button3_Click(object sender, EventArgs e)
{
Process[] processes = Process.GetProcessesByName("chrome");
Process[] array = processes;
for (int i = 0; i < array.Length; i++)
{
Process process = array[i];
process.Kill();
}
Thread thr = new Thread(review);
thr.Abort();
}
You variables are declared in wrong location
private Thread thr = null;
public void test1()
{
var dr = new chromdriver();
dr.navigate().GoToUrl("http://google.com");
if(xx != null)
{
IWebElement emal = dr.FindElement(By.XPath("//[#id=\"Email\"]"));
emal.Sendkeys(email);
}
else
{
IWebElement emal = dr.FindElement(By.XPath("//[#id=\"Email\"]"));
emal.Sendkeys(email);
}
}
private void button2_Click(object sender, EventArgs e)
{
thr = new Thread(test1);
thr.Start();
}
private void button3_Click(object sender, EventArgs e)
{
Process[] processes = Process.GetProcessesByName("chrome");
Process[] array = processes;
for (int i = 0; i < array.Length; i++)
{
Process process = array[i];
process.Kill();
}
thr.Abort();
}
" int ans = 2;
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i <21; i++)
{
ans = 2;
label1.Text += i.ToString();
while (true)
{
if (ans == 1)
{
break;
}
}
}
}
private void button1_Click(object sender, EventArgs e)
{
ans = 1;
} "
this is a simple app
I want to print a number & then wait to the button to be clicked to break the while loop
but when I run the application , the form doesn't show .
"T think that the problem is the while (true)".
what to do?
Use a timer. Start the timer when the form loads. Each time it ticks, increment the number and display it. On button click, you just need to stop the timer.
private Timer _myTimer;
private int number = 0;
private void Form1_Load(object sender, EventArgs e)
{
_myTimer = new Timer();
_myTimer.Interval = 1; // 1 millisecond
_myTimer.Tick += new EventHandler(MyTimer_Tick);
_myTimer.Start();
}
// increments the number at timer tick
private void MyTimer_Tick(object sender, EventArgs e)
{
number ++;
// TODO: update UI here
}
// Stops the timer
private void button1_Click(object sender, EventArgs e)
{
_myTimer.Stop();
}
It's best to not use a loop here. Since this loop won't end you won't ever leave Form_Load and it won't display the form. If you were trying to do some task when the user clicks a button, why not move that logic to button1_Click?
The correct way to implement such a task as you describe would be as such:
private EventWaitHandle ewh = new EventWaitHandle(false, EventResetMode.AutoReset);
private void Form1_Load(object sender, EventArgs e)
{
Task.Factory.StartNew(() =>
{
for (int i = 0; i < 26; i++)
{
ewh.WaitOne();
Action updateLable = () => label1.Text = "" + i;
label1.BeginInvoke(updateLable);
}
});
}
private void button1_Click(object sender, EventArgs e)
{
ewh.Set();
}
As you can see I've replaced your busy wait (while(true)) with a .Net wait handle.
One of the answers describes a timer that acts every millisecond - that is a busy wait of sorts.
This is what async/await is for. Mark your Load() event with "async", then "await" a Task that continues when a ManualResetEvent is triggered in the Button click handler:
private System.Threading.ManualResetEvent mre = new System.Threading.ManualResetEvent(false);
private async void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i < 21; i++)
{
label1.Text = i.ToString();
mre.Reset();
await Task.Factory.StartNew(() => { mre.WaitOne(); });
}
button1.Enabled = false;
label1.Text = "Done!";
}
private void button1_Click(object sender, EventArgs e)
{
mre.Set();
}
I am calling this code inside a for loop and I need to do this since progress depends on this for loop value.
bgworker1.ReportProgress(k * count);
But I receive an exception:
this operation has already had operation completed called on it and further calls are illegal
How can I solve this??
Edit:
private void bgworker1_DoWork(object sender, DoWorkEventArgs e)
{
for (k = 1; k <= tcount; k++)
{
bgworker1.ReportProgress(k * count);
}
}
private void bgworker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
}
private void bgworker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
bgworker1.ReportProgress(k * count);
}
One way you can tackle this is reporting progress in a exclusive for-loop for this only task, like this
private void bgworker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 100; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
//Insert your logic HERE
worker.ReportProgress(i * 1);
}
}
}