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.
Related
I am writing up a C# application using Winforms, and I need to collect some data based on my selection from a comboBox. I also have a start button that enables data collection, and a stop button that halts the data collection.
This is what I am capable of doing right now:
Measure all data from all channels by switching my selection on the comboBox (one channel at a time). The process goes like: select a channel- start button click - wait for data collection - stop button click
But here is what I want to do in code:
Select a channel - start button click - wait for data collection - stop button click
switch to next channel - start button click -wait for data collection - stop button click
................
repeat this process until done.
My question is: what should I adopt to achieve this?
I have been trying to use startButton.PerformClick( ) to enabling the buttons, however, I need to stop for a few seconds in between starting and stopping to wait for data collection.
You may ask why because this is very inefficient, but for some reason the DLL from the third party cannot collect data from all channels at the same time. So i have to manually switch my channel selection from the comboBox in order to collect all data at one go.
Please let me know if you have any suggestions.
private void timer_Tick(object sender, EventArgs e)
{
startButton.PerformClick();
}
private void timer2_Tick(object sender, EventArgs e)
{
stopButton.PerformClick();
}
private void checkAll_CheckedChanged(object sender, EventArgs e)
{
int i = 0;
while (i != 40) //there are a total of 40 channels
{
System.Windows.Forms.Timer mytimer = new System.Windows.Forms.Timer();
mytimer.Interval = 5000;
System.Windows.Forms.Timer mytimer2 = new System.Windows.Forms.Timer();
mytimer2.Interval = 7000;
mytimer.Start();
mytimer.Tick += new EventHandler(timer_Tick);
mytimer2.Start();
mytimer2.Tick += new EventHandler(timer2_Tick);
physicalChannelComboBox.SelectedIndex = i;
i++;
Thread.Sleep(5000);
}
}
Here is a simple routine shell that should help you. This uses a timer to poll if the data is complete (checking a boolean, which is currently set to true for testing). In your case you could probably just set the timers tick value to be the delay you want. If you have a way of knowing when the data is done being collected for the channel, that would be more preferable. This code runs standalone so you can test and configure it before starting to integrate it into your existing code. All it requires is a a listbox for viewing the logs.
public partial class DataCollectorForm : Form
{
private Timer timer = new Timer();
private int numberOfChannels = 40;
private int currentChannelNumber = 0;
private DateTime routineStartTime;
private DateTime routineStopTime;
private DateTime channelStartTime;
private DateTime channelStopTime;
public DataCollectorForm()
{
InitializeComponent();
timer.Interval = 250;
timer.Tick += Timer_Tick;
DataCollectionRoutineStart();
}
private void Timer_Tick(object sender, EventArgs e)
{
// Need to check if data collection for this channel is complete..
//
var isDoneCollectingData = true;
if (isDoneCollectingData)
{
ChannelDataCollectionStop();
currentChannelNumber++;
if (currentChannelNumber >= numberOfChannels)
{
DataCollectionRoutineComplete();
}
else
{
ChannelDataCollectionStart();
}
}
}
public void DataCollectionRoutineStart()
{
routineStartTime = DateTime.Now;
Log("Data Collection Routine Start");
currentChannelNumber = 0;
ChannelDataCollectionStart();
timer.Start();
}
private void ChannelDataCollectionStart()
{
channelStartTime = DateTime.Now;
Log("Data Collection Start : channel " + currentChannelNumber);
}
private void ChannelDataCollectionStop()
{
channelStopTime = DateTime.Now;
Log("Data Collection Stop : channel " + currentChannelNumber + " : elapsed " + (channelStopTime - channelStartTime));
}
private void DataCollectionRoutineComplete()
{
routineStopTime = DateTime.Now;
timer.Stop();
Log("Data Collection Routine Complete : elapsed " + (routineStopTime - routineStartTime));
}
private void Log(string msg)
{
loggingListBox.Items.Add(msg);
}
}
This is my requirement I have to use while loop inside timer, after launch application after click on button UI is locked not able to move and text is not diplaying at textbox too
below is the code
using System;
using System.Windows.Forms;
namespace WinScreenLocked
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
int Number = 0;
private void timer1_Tick(object sender, EventArgs e)
{
while (true)
{
textBox1.Text = Number.ToString();
Number++;
}
}
private void button1_Click(object sender, EventArgs e)
{
timer1.Start();
}
}
}
// 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?
you can stop the thread to block the ui i.e using
System.Threading.Thread.Sleep(2000);
it takes miliseconds in above 2000 miliseconds is equal to 2 seconds.
Seeing as this is winforms you can use Application.DoEvents() to process the UI refresh.
See this : https://social.msdn.microsoft.com/Forums/en-US/b1b1969d-8a51-496c-9274-a0ac1708a8b4/what-does-applicationdoevents-actually-do?forum=csharplanguage
I want to use the ProgressBar and run it from 100% to 0% within 2 seconds. I have written the following function but it does not seem to run properly. Please help! Thank you!
private async void progessbar()
{
for (iValue = 100; iValue >= 0; iValue--)
{
pbTime.Value = iValue;
await Task.Delay(20);
}
}
If you want to animate your progress bar smoothly, you should use a storyboard:
private void AnimateProgressBar()
{
var storyboard = new Storyboard();
var animation = new DoubleAnimation { Duration = TimeSpan.FromSeconds(2), From = 100, To = 0, EnableDependentAnimation = true };
Storyboard.SetTarget(animation, this.ProgressBar);
Storyboard.SetTargetProperty(animation, "Value");
storyboard.Children.Add(animation);
storyboard.Begin();
}
You are changing toolbar multiple times in the same Windows event. Windows updates GUI later when it is idle. Thus you probably see your toolbar jump from 0 to 100% after 2 second wait.
Just add timer to your control, set it when ready to start and do incremental updates.
// In your designer:
this.timer.Enabled = false;
this.timer.Interval = 200;
this.timer.Tick += new System.EventHandler(this.timer_Tick);
// when starting the progress:
pbTime.Value = 0
this.timer.Enabled = true;
private void timer_Tick(object sender, EventArgs e)
{
if (pbTime.Value < 100)
pbTime.Value += 10;
}
I hope this helps
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, System.EventArgs e)
{
// Start the BackgroundWorker.
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
/*Your main code*/
for (int i = 1; i <= 100; i++)
{
// Wait 20 milliseconds.
Thread.Sleep(20);
// Report progress.
backgroundWorker1.ReportProgress(i);
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// Change the value of the ProgressBar to the BackgroundWorker progress.
progressBar1.Value = e.ProgressPercentage;
// Set the text.
this.Text = e.ProgressPercentage.ToString();
}
}
}
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;
}
}
}
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();
}
}
}