Why is the picture box control's visibility property not working here. I have initially set them to false, so that when the screen loads they are not visible. But then I wish to toggle this. I have done the following but does not seem to work. This is a windows forms application.
private void Action()
{
while (true)
{
Random r1 = new Random();
int num = r1.Next(1,3);
switch (num)
{
case 1:
pictureBoxLeft.Visible = true;
pictureBoxRight.Visible = true;
break;
case 2:
pictureBoxLeft.Visible = true;
pictureBoxRight.Visible = false;
break;
case 3:
pictureBoxLeft.Visible = false;
pictureBoxRight.Visible = true;
break;
}
Thread.Sleep(200);
pictureBoxLeft.Visible = false;
pictureBoxRight.Visible = false;
Thread.Sleep(500);
}
}
Also to add, this is working properly with a text box!!! Any Ideas???
Many thanks in advance
Setting the Visible property to true doesn't show the control, it only creates a message that will show it. As long as you are keeping the main thread busy with a Sleep, it will not process any messages, and the controls won't be shown.
You should show the picture boxes and then set up a timer with code that will hide the picture boxes when the timer's tick event is triggered. Then you exit your method so that the main thread can handle the messages that will show the picture boxes.
This is your UI thread. UI thread is so busy that it is not getting time to refresh the display. UI thread is busy in endless while loop, so how can it update UI?
In addition to Thread.Sleep(); call Application.DoEvents() to trigger event handling/ui updating. However ensure you're not calling Action() again somehow. A simple Thread.Sleep() won't allow the UI to update as you're still in the handler and the framework won't be able fire any new events on its own as it won't know if you're finished when waiting (due to the thread still being busy).
Overall your approach might be a bad idea (depending on other code etc.). Consider using timers or a background worker instead.
Whenever the UI changes does not apear after you did some changes, always do Refres(). e.g. pictureBoxLeft.Refresh();. This will always make UI changes appear. Please let me know if it works for you.
Related
I have to show a Window on an application that is not very well thought. The calls from every window are made from the same thread, no background workers. The application is rather yuge, so I can't just go around implementing BW pattern. Problem is, some of those actions take a while (around 5-10 seconds) and the whole app would turn Not Responding while waiting.
My idea was to implement some kind of watchdog on a background thread that would pop a window whenever I set a flag (App.Loading) in order to let the user know that something is going on.
In order to do that, I put this in the main menu
public Menu()
{
ShowInTaskbar = true;
InitializeComponent();
Debug.Ventana = "Menu";
App.Menu = this;
Loading = new Thread(new ThreadStart(CheckLoading));
Loading.SetApartmentState(ApartmentState.STA);
Loading.Start();
}
private void CheckLoading()
{
Loading load = new Andrei.Loading("Cargando datos")
{
ShowInTaskbar = false,
Topmost = true
};
while(true)
{
if (App.Loading && !load.IsVisible)
load.Show();
if (!App.Loading && load.IsVisible)
load.Hide();
}
}
Problem is, sometimes the window does not show up, and when it does, the animation isn't working (it's a small window with a string and an Indeterminate Progress Bar), which must be because the main thread is frozen by the while(true). I've tried putting the loop in yet another thread, but I can't access the window from another thread to hide and show it. I've tried putting a BW on the window to check for progress, but of course, after completing the first cycle, it doesn't go looking for the flag anymore.
Any other suggestions than completely redesigning the application to use BW for any and all time-taking processes?
in my project I need to load "projects".
I am loading all this "projects" in a foreach loop.
In this foreach loop, I want to show a status window with a progressbar, which gets updated everytime a new project got load.
My problem now is, that the status window with the progrssbar wont update.
It seems it is just "freezed" like all other windows in my project (I also let the programm printing what it is doing into a console).
Here is the Code:
Status StatusWd = new Status();
StatusWd.pb_Status.Maximum = animes.Length;
StatusWd.SetStatusText("Animes in AnimeBibliothek laden...");
StatusWd.Show();
bool white = false;
bool black = true;
foreach (string anime in animes)
{
if (white)
{
//Not working..
AB_Output.WriteLine(GetTime() + "Weißes User Control laden...");
AddWhiteUcpToStk(anime);
white = false;
black = true;
}
else if (black)
{
AB_Output.WriteLine(GetTime() + "Schwarzes User Control laden...(" + anime + ")");
AddBlackUCPToStk(anime);
//white = true;
//black = false;
}
StatusWd.pb_Status.Value = Array.IndexOf(animes, anime);
}
StatusWd.Close();
It´s not just the progressbar which wont update. Also the labels in the window, which get updated when the value changes, wont change. I debuged it and the value from the progressbar changed and the label content changes...
Would be nice if you could explain me your solution.
LG Sinmson
Blocking the UI thread will do that....
Any time you are running a long operation, you need to make sure it is on some other thread, otherwise you will be seen as "non-responsive".
So, first thing is to move your loading onto another thread. Thread, BackgroundWorker and Task are all reasonable ways to do this. Then you need to marshal any UI changes back to the UI thread.
If you used async (and Tasks) then the framework does this for you. Similarly, if you use a proper MVVM pattern PropertyChanged events will automatically marshal onto the correct thread.
If you can't do it a "right" way, then marshal such changes yourself using Dispatcher.BeginInvoke.
Dispatcher.BeginInvoke(new Action(() =>
{
//UI code ONLY
}), DispatcherPriority.Normal);
But do so only as a band-aid. Move to asynchronous or MVVM based code (or even better, both!)
Ok, I have a chess board application. The application has 64 panels within a groupbox. These panels are identified with the expression CHessBoardPanels{x,y). I am using this to change the background color of the panels. I want a small delay in between where the chessPanel.BackGround changes to red and when the panels turn back to white.(approximately 1 to 2 second delay)
I have tried the Sleep function but it basically locks the application up till the task have been complete
Here is the code which I have tried:
for (int Row = 7; Row > 3; --Row)
{
chessBoardPanels[ Column ,Row].BackColor = Color.Red;
++Column;
//Add text to Moves TextBox
MovesText.AppendFormat("WhtB {0} {1}{2}", ColumnText, RowText, Environment.NewLine);
MovesTxt.Text = MovesText.ToString();
++ColumnText;
--RowText;
}
//Start White Horizonal Drill
Column = 0;
Thread.Sleep(5000); //This does not delay proerperly
for (int Row = 7; Row > 4; --Row)
{
chessBoardPanels[Column, Row].BackColor = Color.White;
++Column;
//Add text to Moves TextBox
MovesText.AppendFormat("WhtB {0} {1}{2}", ColumnText, RowText, Environment.NewLine);
MovesTxt.Text = MovesText.ToString();
++ColumnText;
--RowText;
}
I am using .Net framework 4.0 because Visual Studio 2010 doesn't support 4.5
That's what Sleep does, it pauses the thread.
What you need is to use a Timer control, and create a queue with color changes, and let the timer control call an event handler periodically, like so:
(in your Form class):
Timer timer = new Timer();
(in your Form's constructor):
timer.Tick += new EventHandler(timer_Tick);
timer.Interval = 500; // every 1/2 second
timer.Enabled = true;
timer.Start();
Then your event handler would do something like this:
void timer_Tick(object sender, EventArgs e)
{
// Read a queue, that contains timings
var nextItem = PeekAtQueue();
if ((nextItem != null) && (nextItem.WhenToChangeColor <= DateTime.Now))
{
var item = TakeFromQueue(); // as opposed to just peeking
ChangeColor(item);
}
}
What does this do? (Of course this code is not 100% complete, you'll have to add the queue-accessing methods yourself, it depends on what you want/can use)
Seeing that Sleep() freezes your application temporarily, you need a
solution that allows you to still interact with your form, while
still having a delay and doing something after that delay.
So you
need to use a timer to execute something at a later date. The timer
in this example gets executed every 1/2 second but you can use any
interval you choose.
Point is, because of this timer and this
configuration, a certain method -- the event handler -- is executed
every 1/2 second, or the interval of your choice.
So what you can
then do is, when you want a certain color change to happen later, to
queue an object that describes the color change, for instance {E5, "red", today at 04:20:30 PM}.
The event handler executed by the
timer peeks every time to see if there is something in the queue, and
to have a look at what it is. It checks whether the "moment to change
the color", as described in the queued object, is now or has already
passed. If so, it changes the color. If not, it leaves the item at
the top of the queue, and the next time the event handler gets
executed again (1/2 second later), it will perform the same check
again.
Once a color change is done, the object is taken off the
queue.
Consider using a Timer class instead. That should allow you to delay your application without locking the thread.
I have tried the Sleep function but it basically locks the application
up till the task have been complete
You need to move the logic of your application our of the main (or UI) thread. Your application will "freeze" if you call a Thread.Sleep in the main (UI) thread as the Windows event-handling loop is blocked.
Things you can use:
New Thread, Task, Background worker to execute logic of the game
Timers
Update the GUI from another thread
Sleep will lock the current thread, meaning if it's the main UI thread then no user input will be processed - and ideally you should set an hourglass cursor at that point.
To do what you want I think you need to start a background timer and then set the colours on the callback, then cancel the timer.
While the timer is ticking down the main UI will still be responsive.
You might also find that over 1 second delay will feel like too long a delay for users, but the timer period is in milliseconds so you can define a shorter delay.
Try following:
Task.Run(() => Thread.Sleep(5000)).Wait();
I have only a little experience with threading in WinForms. I am trying to set a progress bar to 100, sleep for 2 seconds, and then hide the progress bar.
I have:
public void ProgressBarTimerStop()
{
if (!AnyWorkersBusy())
{
if (InvokeRequired)
{
Invoke((MethodInvoker)delegate
{
ProgressBarTimer.Stop();
Thread.Sleep(1000);
Application.DoEvents();
Thread.Sleep(1000);
StatusToolStripProgressBar.Visible = false;
StatusToolStripProgressBar.Value = StatusToolStripProgressBar.Minimum;
});
}
else
{
ProgressBarTimer.Stop();
StatusToolStripProgressBar.Value = StatusToolStripProgressBar.Maximum;
Thread.Sleep(1000);
Application.DoEvents();
Thread.Sleep(1000);
StatusToolStripProgressBar.Visible = false;
StatusToolStripProgressBar.Value = StatusToolStripProgressBar.Minimum;
}
}
}
For the current problem I am experiencing InvokeRequired is false.
When I call the line:
StatusToolStripProgressBar.Value = StatusToolStripProgressBar.Maximum;
my watch window shows the value as set, but the GUI has not updated to reflect this. If I immediately sleep for a full two seconds the GUI does not update before sleeping.
If I call Application.DoEvents() without calling sleep beforehand -- it appears to do nothing.
If I sleep, then call DoEvents -- the GUI updates, and then I go back to sleep. This is correct, but I feel like my code is heinous.
Am I misunderstanding a key concept here?
EDIT: ProgressBarTimerStop is called only through "RunWorkerCompleted" event handlers.
I tried this, but it had no effect:
StatusToolStripProgressBar.GetCurrentParent().Refresh();
The 'key concept' that you are missing is that updating the progress bar's value does not immediately tell the progress bar to redraw itself.
When you update the progress bar, the GUI thread repaints the progress bar on the next window repaint. This only happens when the GUI thread becomes free to do so. Normally this happens when the window receives a paint message from the operating system. This should be picked up by Application.DoEvents, but it could be that the message isn't queued quickly enough to be picked up by DoEvents. You may be able to force it to with a Refresh call.
Call StatusToolStripProgressBar.ProgressBar.Refresh(); on every step. ProgressBar property of ToolStripProgressBar is hidden and it may not be shown in intellisense list.
I have used two threads in my application(WindowsForms). The one thread for getting ThumbnailImages of clients and another thread for getting fullsize Images of Clients...its working but not properly... When i click thumbnail image button its giving thumbnail image properly after that i click that fullsize image button,It came as fullsize image and thumbnail images too... then return back to thumbnail image button it came as thumbnail images and Fullsize images also....
The two threads are crossing Thats why i didnt get proper output....
How can i Solve this Problem? Tell me the solution Of this...
Here is my Code....
{
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
th = new Thread(new ThreadStart(startlooping));
th.Start();
}
void StartLooping()
{
localconnection();
for (int i = 0; i < Num_Picbox; i++)
{
clsImage pcimg = frmDisplay.Serviceobj.ConnectToPcAndGetImage(listBox1.Items[i].ToString(), imgid);
Image img = objConvertByteToStream.byteArrayToImage(pcimg.pcimage);
if (listBox1.Items[i].ToString() == pcimg.IPadd && imgid == 0)
{
shapes[i].Image = img;
}
pcimg = null;
}
}
private void PictureBox_Click(object sender, EventArgs e)
{
pb= sender as PictureBox;
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
thread = new Thread(new ThreadStart(GetImage));
thread.Start();
}
void GetImage()
{
pictureBox1.Visible = true;
btnBack.Visible = true;
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
label1.Visible = true;
pictureBox1.Height = this.flowLayoutPanel1.Height;
pictureBox1.Width = this.flowLayoutPanel1.Width;
btnGetConnectedPcs.Location = new Point(168, 616);
btnGetImageFromSelectedPc.Location = new Point(352, 616);
for (; ; )
{
count++;
int imageid = 1;
localconnection();
string strIpaddress = listBox1.Items[Convert.ToInt32(pb.Name)].ToString();
.........................
.........................
}
}
Do not use CheckForIllegalCrossThreads and use Invoke on the controls you're using.
I think you should use the BackgroundWorker, instead. Don't ever use CheckForIllegalCrossThreadCalls; it's there for a reason.
It deals with "marshalling" (getting calls on one thread to switch to another thread for UI updating purposes).
Here's a good starter: http://bigballofmud.wordpress.com/2009/03/28/thread-marshalling-part-2-using-backgroundworker/
Also, you need to control the UI when the other threads are running. Typically by disabling buttons/menus etc to prevent the user asking for more things like one is already running.
At the very least you should be using Control.Invoke. When your thread has finished downloading images, it should call a method to display them. That method should then check this.InvokeRequired, and if it is true, should call itself via this.Invoke or this.BeginInvoke. This will effectively switch back to the main UI thread and avoid the errors you were probably seeing.
Plz to send me the codez?
Okay, this time you can have a bit more, but you also need to master the skill of taking some directions then finding your own way. If we help you with actual code for this problem you'll just come back when you get stuck next time. We'd prefer to set you going like a wind-up toy than steer you the whole way like a remote-controlled car :)
BackgroundWorker
I'm going to refer you to the BackgroundWorker article on MSDN for this.
The BackgroundWorker is a component you drop on your form from the toolbox. It's not a visual control like a textbox, instead it's more like a Timer or Tooltip.
Using it in it's simplest form means subscribing to the DoWork and RunWorkerCompleted events, as described in the MSDN article. When you want some downloading to happen, you need to do the following:
Disable your UI (to prevent subsequent button presses).
Set some sort of progress/working animation or message.
Call BackgroundWorker.RunWorkerAsync, passing in an object containing parameters that tell it what to do (i.e. download large or small images).
The DoWork event in your case will be raised, and your method will be running in a different thread to your UI, so you are not allowed to update the UI at all in this method. Write your DoWork method to download the images and set the DoWorkEventArgs.Result property to that collection of images once the download is complete.
When the DoWork method completes, the BackgroundWorker will fire the RunWorkerCompleted event, and the method you subscribed to it will be called. This code will now automatically be running on the UI thread again, so you should do the following:
Report on any errors in the RunWorkerCompletedEventArgs.Error property (essentially this is any untrapped errors that occurred in the DoWork method. Deal with them here so you can use the UI to inform the user of the problem).
Create your controls to display the images contained in the RunWorkerCompletedEventArgs.
Hide any progress indicators.
Re-enable your UI (preferably using a finally block so that any exceptions don't result in your UI being permanently and irretrievably locked).
You may want to take a quick look at Control.InvokeRequired(). That is likely to shed some light and give you a clear path to success.
Good luck.