I am writing activity recognition software in realtime. But i can't setText in textbox with infinite loop. I try to search Google but no answer. When, i using "textbox.Text += "ZZZZ", it working but I using "textbox.Text = "ZZZ" ", it not working. I hope someone can point me how to solve
private void button1_Click(object sender, EventArgs e)
{
for (; ; ){
Thread.Sleep(20);
........process....
tb_activity = "AAA";
}
}
You can use the new await and async feature in .Net:
private void button1_Click(object sender, EventArgs e)
{
EndlessTask();
}
async Task EndlessTask()
{
for(int i = 0; true; i++)
{
textBox1.Text = i.ToString();
await Task.Delay(500);
}
}
[Edit] Note, if you want to get rid of the async warning:
#pragma warning disable 4014
EndlessTask();
#pragma warning restore 4014
i can't setText in textbox with infinite loop
you can never confirm that un till unless you debug your application while using the Thread.Sleep() in infinite loop.
Reason: when you use Thread.Sleep() it makes your Main thread to sleep so it is not a good practice to use Thread.Sleep() . it hangs your UI therefore you can not see the Control Updates on the UI like Label Text update ,TextBox Text Update things like that.
ofcourse you call Application.DoEvents() to refresh the UI but it is not a good practice as there are many other problems.
Solution: i suggest you to use Timer instead of using Thread.Sleep() as it runs in the background so it doesnot hang your UI and also you can see the updates on UI.
Simple Example to show you how to use Timer for updating the Text on Textbox # certain intervals
public partial class Form1 : Form
{
int count = 0;
string text1 = "this is a scrolling text";
System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
textBox1.ReadOnly = true;
SetTimer(500);
}
private void SetTimer(int milliseconds)
{
timer1.Tick+=new EventHandler(timer1_Tick);
timer1.Interval = milliseconds;
timer1.Start();
}
private void timer1_Tick(Object o, EventArgs e)
{
if (count < text1.Length)
{
textBox1.Text += text1[count];
count++;
}
else
{
timer1.Stop();
button1.Enabled = true;
textBox1.ReadOnly = false;
}
}
}
Related
In my program i'm starting for loop using button, I want to break this for loop using another button.
For example:
private void button1_Click(object sender, EventArgs e)
{
for( int i = 0; i < var; i++)
{
//doing something
}
}
And using second button break loop,
private void button2_Click(object sender, EventArgs e)
{
//breaking loop;
}
Need help :)
Set a flag in button2_Click() method and check it in the button1_Click()'s loop.
In order to process Windows events and allow button2_Click() handle to run while iterating, add Application.DoEvents() in your loop:
bool breakLoop = false;
private void button1_Click(object sender, EventArgs e)
{
breakLoop = false;
for( int i = 0; i < var && !breakLoop; i++)
{
//doing something
Application.DoEvents();
}
}
private void button2_Click(object sender, EventArgs e)
{
breakLoop = true;
}
You cannot do that, because the loop in button1_Click event handler will be holding the UI thread. Your user interface will not respond to any event, showing hourglass icon, until the loop is over. This means that button2_Click cannot be entered until button1_Click has completed.
You need to replace the long-running loop from the event handler with something that runs outside the UI thread. For example, you can use Tasks, which can be cancelled using CancellationToken (related Q&A).
Arguably it would be better to use threads and cancellation tokens in some form, rather than the Application.DoEvents(). Something like this:
private CancellationTokenSource loopCanceller = new CancellationTokenSource();
private void button1_Click(object sender, EventArgs e)
{
Task.Factory.StartNew(() =>
{
try
{
for (int i = 0; i < 100; i++)
{
this.loopCanceller.Token.ThrowIfCancellationRequested(); // exit, if cancelled
// simulating half a second of work
Thread.Sleep(500);
// UI update, Invoke needed because we are in another thread
Invoke((Action)(() => this.Text = "Iteration " + i));
}
}
catch (OperationCanceledException ex)
{
loopCanceller = new CancellationTokenSource(); // resetting the canceller
Invoke((Action)(() => this.Text = "Thread cancelled"));
}
}, loopCanceller.Token);
}
private void button2_Click(object sender, EventArgs e)
{
loopCanceller.Cancel();
}
This is my code:
private void _1_Load(object sender, EventArgs e)
{
FillA();
FillB();
// Tried these lines too but they show listbox values but not textbox value
// var t2 = Task.Run(() => FillA());
// FillB();
}
private void FillA()
{
this.Invoke(new MethodInvoker(delegate()
{
for (int i = 1; i > 0; i++)
{
listBox1.Items.Add(i.ToString());
listBox1.Update();
Thread.Sleep(25);
}
}));
}
private void FillB()
{
Thread.Sleep(3000); //1 seconds delay
textBox1.Text = "Hello World!";
}
When the page loads the listbox should starts showing the number 1, 2, 3... and then after few seconds of delay the textbox should show the Hello World! value but the listbox should keep growing. How do I ensure that first the listbox should start filling and then the textbox should fill. I don't want to wait for the filling of the listbox and then textbox to be filled.
Any advice would be appreciated.
Edit:
This is just a sample code. In actual production there would be two processes and the second process will start once the first process is started fetching data and storing in listbox.
The first process should keep on going. I can't stop it in middle as it would create inconsistency in the data.
Don't use Sleep. Instead use Timer-class:
https://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.110).aspx
Configure a timeout of 1s.
Hook up the Elapsed event for the timer:
aTimer.Elapsed += OnTimedEvent;
In method OnTimedEvent you can increment a integer-variable i.
Depending on value of i you fill first listbox and if value is higher fill the other Listbox.
You cannot add all items at once to the listbox and update the textbox in between as these operations are done synchronously in WindowsForms.
Instead you should add only a subset of items to the listbox, update the textbox and then continue adding items to the listbox.
To not freeze the GUI in between waiting for operations, you can use async\await combination instead of Thread.Sleep().
private async void _1_Load(object sender, EventArgs e)
{
await AddInitialListBoxItems();
await FillTextBox();
await AddRemainingListBoxItems();
}
private async Task AddInitialListBoxItems()
{
for (int i = 1; i < 10; i++)
{
listBox1.Items.Add(i.ToString());
listBox1.Update();
await Task.Delay(25);
}
}
private async Task FillTextBox()
{
await Task.Delay(3000); //1 seconds delay
textBox1.Text = "Hello World!";
}
private async Task AddRemainingListBoxItems()
{
for (int i = 11; i < 100; i++)
{
listBox1.Items.Add(i.ToString());
listBox1.Update();
await Task.Delay(25);
}
}
If you can use Timers instead of direct threading, this might help you. It worked on my pc:
Edit since you need the textbox to get written after some delay, you need to use a timer for it as well. I have edited the code below. Textbox is written after 1 seconds of listbox population starting.
public partial class Form1 : Form
{
int counter = 0;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
timer.Interval = 25;
timer.Tick += Timer_Tick;
timer.Start();
System.Windows.Forms.Timer timerTextbox = new System.Windows.Forms.Timer();
timerTextbox.Interval = 1000;
timerTextbox.Tick += TimerTextbox_Tick; ;
timerTextbox.Start();
}
private void TimerTextbox_Tick(object sender, EventArgs e)
{
FillB();
(sender as System.Windows.Forms.Timer).Stop();
}
private void Timer_Tick(object sender, EventArgs e)
{
listBox1.Items.Add(counter.ToString());
counter++;
listBox1.Update();
}
private void FillB()
{
textBox1.Text = "Hello World!";
}
}
Of course when you call Thread.Sleep(3000); //1 seconds delay on Load event (3000 ms is 3 seconds btw), your form will be shown 3 seconds late.
i have a strange situation.
please see the backgroundWorker5_RunWorkerCompleted event:
private void backgroundWorker5_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
btnStartAdventures.Text = "Start Adventure";
btnStartAdventures.Enabled = true;
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
return;
}
if (e.Cancelled)
{
lblStatusValueInAdventures.Text = "Cancelled...";
}
else
{
lblStatusValueInAdventures.Text = "Completed";
timer1.Enabled = true;
timer1.Start();
// MessageBox.Show("start timer");
Thread.Sleep((int.Parse(txtDelayInAdventures.Text)) * 60000);
//MessageBox.Show("end timer");
timer1.Enabled = false;
timer1.Stop();
lblTimer.Text = "0";
btnStartAdventures.PerformClick();
}
}
and that Timer is :
private void timer1_Tick(object sender, EventArgs e)
{
this.Invoke(new MethodInvoker(delegate { lblTimer.Text = (int.Parse(lblTimer.Text) + 1).ToString(); }));
}
but this timer can not change lblTimer's Text.
how can i fix this problem?
EDIT:
that Thread.Sleep is necessary and i can not remove it.
i want a loop that never ends and those codes are for that.
thanks in advance
As requested;
What do you mean by "a loop that never ends"? A Thread.Sleep on the UI thread (RunWorkerCompleted event executes on the UI thread) will effectively freeze the UI thread, which means that no interaction with the UI thread will be shown.
Comments:
What are you trying to achieve? As far as I can guess, you are doing
some work in a background thread - backgroundWorker5 - (the UI thread
is responsive). When backgroundWorker5 is finished you want to start a
timer and display a counter in a label while the UI is still
responsive (for somebody to stop the timer maybe?). Something like
that? – Mario 3 mins ago edit
yes you are right. i want a loop and it never stops until a user click
cancel button. – MoonLight 1 min ago
So, try something like this:
int time = 0;
private void backgroundWorker5_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
btnStartAdventures.Text = "Start Adventure";
btnStartAdventures.Enabled = true;
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
return;
}
if (e.Cancelled)
{
lblStatusValueInAdventures.Text = "Cancelled...";
}
else
{
lblStatusValueInAdventures.Text = "Completed";
timer1.Interval = 1000; //<--- Tick each second, you can change this.
timer1.Enabled = true;
timer1.Start();
// MessageBox.Show("start timer");
}
}
private void timer1_Tick(object sender, EventArgs e)
{
lblTimer.Text = (time + 1).ToString();
}
private void button_Cancel_Click(object sender, EventArgs e)
{
//MessageBox.Show("end timer");
timer1.Enabled = false;
timer1.Stop();
lblTimer.Text = "0";
btnStartAdventures.PerformClick();
}
Thread.Sleep
There's your problem.
Never call Thread.Sleep in a UI thread; it will freeze the UI.
Get rid of that, and it will work fine.
You can put the rest of the work in the timer callback.
You can also use C# 5 async to make this much simpler.
You have to refresh item.
lblTimer.Refresh()
and also you could refresh form
frmName.Refresh();
and make thread to sleep 0 milliseconds that gives space for other processes.
I was wondering if there was a way of adding a sort of animation to text displayed on a form.
What I had in mind when I thought of this was kind of similar to what you can do with text in PowerPoint (i.e. a typewriter-like animation where the text is typed one at a time, have the whole textbox appear with a certain effect etc), I'm just looking to find out what you can do using Windows Forms.
Currently I'm using a textbox to display information on my form application, though in hindsight I realise labels would have worked just as well.
EDIT: Turns out I was using labels after all, I just gave it a name with 'textbox' inside for lack of a better description.
public partial class Form1 : Form
{
int _charIndex = 0;
string _text = "Hello World!!";
public Form1()
{
InitializeComponent();
}
private void button_TypewriteText_Click(object sender, EventArgs e)
{
_charIndex = 0;
label1.Text = string.Empty;
Thread t = new Thread(new ThreadStart(this.TypewriteText));
t.Start();
}
private void TypewriteText()
{
while (_charIndex < _text.Length)
{
Thread.Sleep(500);
label1.Invoke(new Action(() =>
{
label1.Text += _text[_charIndex];
}));
_charIndex++;
}
}
}
Now, I personally wouldn't do this because gratuitous animations tend to annoy users. I'd only use animation sparingly - when it really makes sense.
That said, you can certainly do something like:
string stuff = "This is some text that looks like it is being typed.";
int pos = 0;
Timer t;
public Form1()
{
InitializeComponent();
t = new Timer();
t.Interval = 500;
t.Tick += new EventHandler(t_Tick);
}
void t_Tick(object sender, EventArgs e)
{
if (pos < stuff.Length)
{
textBox1.AppendText(stuff.Substring(pos, 1));
++pos;
}
else
{
t.Stop();
}
}
private void button1_Click(object sender, EventArgs e)
{
pos = 0;
textBox1.Clear();
t.Start();
}
or something like that. It'll tick off ever half second and add another character to the multi-line text box. Just an example of what someone could do.
I wanted to make a simple Countdown-Application with C# to show as an example.
For the very first and basic version I use a Label to display the current time left in seconds and a Button to start the countdown. The Button's Click-Event is implemented like this:
private void ButtonStart_Click(object sender, RoutedEventArgs e)
{
_time = 60;
while (_time > 0)
{
_time--;
this.labelTime.Content = _time + "s";
System.Threading.Thread.Sleep(1000);
}
}
Now when the user clicks the Button the time is actually counted down (as the application freezes (due to Sleep())) for the chosen amount of time but the Label's context is not refreshed.
Am I doing something generally wrong (when it comes to Threads) or is it just a problem with the UI?
Thank you for your answers!
I now use a System.Windows.Threading.DispatcherTimer to do as you told me. Everything works fine so this question is officially answered ;)
For those who are interested: Here is my code (the essential parts)
public partial class WindowCountdown : Window
{
private int _time;
private DispatcherTimer _countdownTimer;
public WindowCountdown()
{
InitializeComponent();
_countdownTimer = new DispatcherTimer();
_countdownTimer.Interval = new TimeSpan(0,0,1);
_countdownTimer.Tick += new EventHandler(CountdownTimerStep);
}
private void ButtonStart_Click(object sender, RoutedEventArgs e)
{
_time = 10;
_countdownTimer.Start();
}
private void CountdownTimerStep(object sender, EventArgs e)
{
if (_time > 0)
{
_time--;
this.labelTime.Content = _time + "s";
}
else
_countdownTimer.Stop();
}
}
Yes, event handlers should not block - they should return immediately.
You should implement this by a Timer, BackgroundWorker or Thread (in this order of preference).
What you are seeing is the effect of a long-running message blocking the windows message queue/pump - which you more commonly associate with the white application screen and "not responding". Basically, if your thread is sleeping, it isn't responding to messages like "paint yourself". You need to make your change and yield control to the pump.
There are various ways of doing this (ripper234 does a good job of listing them). The bad way you'll often see is:
{ // your count/sleep loop
// bad code - don't do this:
Application.DoEvents();
System.Threading.Thread.Sleep(1000);
}
I mention this only to highlight what not to do; this causes a lot of problems with "re-entrancy" and general code management. A better way is simply to use a Timer, or for more complex code, a BackgroundWorker. Something like:
using System;
using System.Windows.Forms;
class MyForm : Form {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.Run(new MyForm());
}
Timer timer;
MyForm() {
timer = new Timer();
count = 10;
timer.Interval = 1000;
timer.Tick += timer_Tick;
timer.Start();
}
protected override void Dispose(bool disposing) {
if (disposing) {
timer.Dispose();
}
base.Dispose(disposing);
}
int count;
void timer_Tick(object sender, EventArgs e) {
Text = "Wait for " + count + " seconds...";
count--;
if (count == 0)
{
timer.Stop();
}
}
}