I basically need to show a wait window to the user. For this i have put two seperate window forms in the application. the first form is the main form with a button. The second one is a empty one with just a label text. On click of the button in Form1 i do the below
Form2 f = new Form2();
f.Show();
Thread.Sleep(2000);
f.Close();
My idea here is to show the wait window to the user for 2 second. But when i do this the Form 2 is not completely loaded because of which the label in it is blank. Please let me know your inputs on this.
That's because you probably do some lengthy operation in the same thread (UI thread). You should execute your code in a new thread (see Thread class) or at least call Application.DoEvents periodically from inside your lengthy operation to update the UI.
Here is a Waiting Box class I use. Here is how you use it:
using WaitingBox;
ShowWaitingBox waiting = new ShowWaitingBox("Title Text","Some Text so the user knows whats going on..");
waiting.Start();
//do something that takes a while
waiting.Stop();
Here is the code for WaitingBox:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace WaitingBox
{
public class ShowWaitingBox
{
private class WaitingForm:Form
{
public WaitingForm()
{
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.label1 = new System.Windows.Forms.Label();
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.tableLayoutPanel1.SuspendLayout();
this.SuspendLayout();
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 1;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.Controls.Add(this.progressBar1, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.label1, 0, 2);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 3;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 29F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(492, 155);
this.tableLayoutPanel1.TabIndex = 0;
//
// label1
//
this.label1.Anchor = System.Windows.Forms.AnchorStyles.Top;
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(209, 92);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(73, 13);
this.label1.TabIndex = 3;
this.label1.Text = "Please Wait...";
//
// progressBar1
//
this.progressBar1.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
this.progressBar1.Location = new System.Drawing.Point(22, 37);
this.progressBar1.Name = "progressBar1";
this.progressBar1.Size = new System.Drawing.Size(447, 23);
this.progressBar1.TabIndex = 2;
//
// WaitingForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(492, 155);
this.Controls.Add(this.tableLayoutPanel1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
this.Name = "WaitingForm";
this.Text = "Working in the background";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.WaitingForm_FormClosing);
this.Load += new System.EventHandler(this.WaitingForm_Load);
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
this.ResumeLayout(false);
}
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.ProgressBar progressBar1;
private System.Windows.Forms.Label label1;
private void WaitingForm_Load(object sender, EventArgs e)
{
progressBar1.Style = ProgressBarStyle.Marquee;
this.BringToFront();
this.CenterToScreen();
}
private void WaitingForm_FormClosing(object sender, FormClosingEventArgs e)
{
}
internal void SetLabel(string p)
{
label1.Text = p;
}
}
private WaitingForm wf = new WaitingForm();
private string title, text;
private Thread waiting;
public bool IsAlive
{
get
{
return waiting.IsAlive;
}
set { }
}
public ShowWaitingBox(string Title, string Text)
{
this.title = string.IsNullOrEmpty(Title) ? "Working in the Background..": Title;
this.text = string.IsNullOrEmpty(Text) ? "Please wait..." : Text;
waiting = new Thread(new ThreadStart(Show));
}
public ShowWaitingBox()
{
waiting = new Thread(new ThreadStart(Show));
}
private void Show()
{
wf.Show();
wf.Text = this.title;
wf.SetLabel(this.text);
while (true) {
wf.Refresh();
System.Threading.Thread.Sleep(50);
}
}
public void Start()
{
waiting.Start();
}
public void Stop()
{
waiting.Abort();
}
}
}
When yo use Thread.Sleep you will disable the windows message loop and prevent the window from painting itself.
You could force a repaint:
f.Refresh();
Or better yet use a timer with a callback.
Timer t = new Timer();
t.Interval = 2000;
t.Tick += delegate { Close(); t.Stop();};
t.Start();
To prevent users from clicking in the original window you can open the new form as a dialog:
f.ShowDialog();
You're basically blocking the UI thread.
I suggest that instead, you make your Form2 constructor (or possibly Load event handler) start a timer which will fire two seconds later. When the timer fires, close the form. During those two seconds, the UI thread will be free, so everything will display properly and the user will be able to move the window etc.
I think you should just use
f.ShowDialog(this);
Then control is returned when f is closed.
By using the sleep, you are blocking the UI thread from updating for 2 seconds. (The thread is asleep).
You can (an always should for UI threads) use Thread.Current.Join(2000) instead of Thread.Sleep(2000).
Related
I've been working on a bit of software in c# and it was going nicely but as of yesterday evening I noticed that it was throwing a memory exception error at the point when it loads an image.
I tried to decrease the image size but then realised that 'declaring rats' was being printed repeatedly to the console, where it should only occur once.
Digging a little deeper with some break points I found that it enters the drawing constructor at allRats = new Drawing(HousePicBox, DekuPicBox, BakuPicBox); //THIS HAS BECOME RECURSIVE, WTF
yet it doesn't seem to run the code within the constructor, but jumps back to the start of form1().
I have included all of the code within the files which the Program Counter touches.
//---------------------------------------------------FORM1.CS-------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
// This is the code for your desktop app.
// Press Ctrl+F5 (or go to Debug > Start Without Debugging) to run your app.
namespace XMLRats5
{
public partial class Form1 : Form
{
// These are here as they are referred to by various functions for different reasons
string MazakSourceURL = "http://mtconnect.mazakcorp.com:5609"; // Gives us a human friendly reference to the HTML
string NISTSourceURL = "https://smstestbed.nist.gov/vds/current"; // Gives us a human friendly reference to the HTML
public PollTimer statusPoller;
public static Drawing allRats;
ImageRat Deku;
ImageRat Bakugo;
NISTDataSet CurrentNIST;
MazakDataSet CurrentMazak;
public Form1()
{
Console.WriteLine("Declaring Rats..."); // Is being called recursively :( ?????????????
ImageRat.Deku = new Rat(false, 0, 0, true, 0); // Declares Deku
ImageRat.Bakugo = new Rat(false, 800, 0, true, 0); // Declares Bakugo
Console.WriteLine("Initialising");
InitializeComponent(); // Constructs the graphics which make up the 'state 0'
Console.WriteLine("Declaring image");
allRats = new Drawing(HousePicBox, DekuPicBox, BakuPicBox); //THIS HAS BECOME RECURSIVE, WTF
Console.WriteLine("Clearing Image");
allRats.ClearRats();
Console.WriteLine("Displaying House");
HousePicBox.Show();
//allRats.DrawRats(ImageRat.deku.Awake, ImageRat.bakugo.Awake);
Console.WriteLine("Form 1 Initiated, please proceed.");
}
private void NISTDataLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
// This link takes you to the 'current' NIST testbed data feed page
System.Diagnostics.Process.Start(NISTSourceURL);
}
private void MAZAKDataLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
// This link takes you to the raw XML published by Mazaks HCN6800 labelled 5609
System.Diagnostics.Process.Start(MazakSourceURL);
}
public void StatusCheckButton_Click(object sender, EventArgs e) // Here we should check that the machine tools are feeding live data
{
// Clear the rat picture boxes as they 'stick' when already shown
DekuPicBox.Hide();
BakuPicBox.Hide();
string MazakStatus = "Unchecked";
string NISTStatus = "Unchecked";
try
{
CurrentMazak = MTFunctions.PollMazak();
MazakStatus = CurrentMazak.Status;
if (MazakStatus == "AVAILABLE") { ImageRat.Deku.Awake = true; }
}
catch (Exception MazakLookupFailed)
{
Console.WriteLine("Could not retrieve Mazak Data", MazakLookupFailed);
MazakStatus = "Lookup Failed"; // This will later refer to the xml path for running status
}
try
{
CurrentNIST = MTFunctions.PollNIST();
NISTStatus = CurrentNIST.Status;
if (NISTStatus == "AVAILABLE") { ImageRat.Bakugo.Awake = true; }
}
catch (Exception NISTLookupFailed)
{
Console.WriteLine("Could not Retrieve NIST Data: ", NISTLookupFailed);
NISTStatus = "Lookup Failed";
ImageRat.Bakugo.Awake = false;
}
string MessageString = " Mazak : " + MazakStatus + "\n NIST : " + NISTStatus;
if ((ImageRat.Deku.Awake == true) & (ImageRat.Bakugo.Awake == true)) // Both Online
{
HousePicBox.Image = XMLRats5.Properties.Resources.bothsleep; // SLeeping rat shows machine online but not feeding data
} // Empty Box
if ((ImageRat.Deku.Awake == true) & (ImageRat.Bakugo.Awake == false)) // NIST offline
{
HousePicBox.Image = XMLRats5.Properties.Resources.bakusleep;
DekuPicBox.Show(); // Not neccessary but prevents bugs
} // Put Bakug in box, deku out
if ((ImageRat.Deku.Awake == false) & (ImageRat.Bakugo.Awake == true)) // Mazak Offline
{
HousePicBox.Image = XMLRats5.Properties.Resources.dekuSleep;
BakuPicBox.Show(); // Not neccessary but prevents bugs
} // Put deku in box, bakugo out
if ((ImageRat.Deku.Awake == false) & (ImageRat.Bakugo.Awake == false)) // Both Offline
{
HousePicBox.Image = XMLRats5.Properties.Resources.nosleep;
} // Put rats in box
MessageBox.Show(MessageString, "Machine Status"); // We need to pass information gained through XPath to first argument
}
public void WakeRatsButton_Click(object sender, EventArgs e)
{
MessageBox.Show("This 'wakes the rats' (Begins data stream)");
// We need to poll Mazak and NIST here to determine which images to draw.
MazakDataSet checkM = MTFunctions.PollMazak();
NISTDataSet checkN = MTFunctions.PollNIST();
if (checkM.Status == "AVAILABLE")
{
ImageRat.Deku.Awake = true;
DekuPicBox.Show();
}
else { ImageRat.Deku.Awake = false; }
if (checkN.Status == "AVAILABLE")
{
BakuPicBox.Show();
ImageRat.Bakugo.Awake = true;
}
else { ImageRat.Bakugo.Awake = false; }
allRats.DrawRats(ImageRat.Deku.Awake, ImageRat.Bakugo.Awake); // Should move the boys out of the box
// Here the draw function successfully relocates the rats, so why does this not work from the timer?
statusPoller = new PollTimer(2000, true); //Initiate a timer driven function which polls the data sets
// Timer Driven function draws rats
}
public void DebugInstructionsLabel_Click(object sender, EventArgs e)
{ }
public void titleLabel_Click(object sender, EventArgs e) { }
public void SleepRatsButton_Click(object sender, EventArgs e)
{
MessageBox.Show("This 'puts the rats to bed' (Closes data stream)");
try // Stop Polling timer function
{
statusPoller.Stop();
statusPoller.Dispose();
Console.Write("Stream closed successfully");
}
catch { Console.WriteLine("Could not stop polling. Were the rats actually 'awake'?"); }
// Draw rats in house
DekuPicBox.Hide(); // Rat is no longer active
BakuPicBox.Hide(); // Rat is no longer active
HousePicBox.Image = XMLRats5.Properties.Resources.nosleep; // Show empty box
//allRats.Paint();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void HousePicBox_Click(object sender, EventArgs e)
{
}
private void DekuPicBox_Click(object sender, EventArgs e)
{
// Proves that problem with movement is because DekuPicBox needs to be changed, not allRats.dekuPic....
System.Drawing.Point DekuCoord = new System.Drawing.Point(ImageRat.Deku.PosX, ImageRat.Deku.PosY); // Create a 'System Point' for Deku
DekuPicBox.Location = DekuCoord;
Console.WriteLine("~~~~~~~~Deku moved to " + DekuCoord + " ~~~~~~~~");
}
private void BakuPicBox_Click(object sender, EventArgs e)
{
System.Drawing.Point BakuCoord = new System.Drawing.Point(ImageRat.Bakugo.PosX, ImageRat.Bakugo.PosY); // Create a 'System Point' for Deku
BakuPicBox.Location = BakuCoord;
Console.WriteLine("~~~~~~~~Bakugo moved to " + BakuCoord + " ~~~~~~~~");
}
public void Refresh(int boi) // Better bloody relocate those pics boii
{
if (boi == 0)
{
System.Drawing.Point BakuCoord = new System.Drawing.Point(ImageRat.Bakugo.PosX, ImageRat.Bakugo.PosY); // Create a 'System Point' for Deku
DekuPicBox.Location = BakuCoord;
}
else
{
System.Drawing.Point DekuCoord = new System.Drawing.Point(ImageRat.Deku.PosX, ImageRat.Deku.PosY); // Create a 'System Point' for Deku
DekuPicBox.Location = DekuCoord;
}
}
}
}
//----------------------------------------------FORM1.Designer.CS--------------------------------------------------------
namespace XMLRats5
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.MAZAKDataLinkLabel = new System.Windows.Forms.LinkLabel();
this.DebugInstructionsLabel = new System.Windows.Forms.Label();
this.StatusCheckButton = new System.Windows.Forms.Button();
this.TitleLabel = new System.Windows.Forms.Label();
this.WakeRatsButton = new System.Windows.Forms.Button();
this.SleepRatsButton = new System.Windows.Forms.Button();
this.NISTDataLinkLabel = new System.Windows.Forms.LinkLabel();
this.BakuPicBox = new System.Windows.Forms.PictureBox();
this.HousePicBox = new System.Windows.Forms.PictureBox();
this.DekuPicBox = new System.Windows.Forms.PictureBox();
((System.ComponentModel.ISupportInitialize)(this.BakuPicBox)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.HousePicBox)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.DekuPicBox)).BeginInit();
this.SuspendLayout();
//
// MAZAKDataLinkLabel
//
this.MAZAKDataLinkLabel.AutoSize = true;
this.MAZAKDataLinkLabel.Location = new System.Drawing.Point(1287, 985);
this.MAZAKDataLinkLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.MAZAKDataLinkLabel.Name = "MAZAKDataLinkLabel";
this.MAZAKDataLinkLabel.Size = new System.Drawing.Size(179, 25);
this.MAZAKDataLinkLabel.TabIndex = 0;
this.MAZAKDataLinkLabel.TabStop = true;
this.MAZAKDataLinkLabel.Text = "View Mazak Data";
this.MAZAKDataLinkLabel.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.MAZAKDataLinkLabel_LinkClicked);
//
// DebugInstructionsLabel
//
this.DebugInstructionsLabel.AutoSize = true;
this.DebugInstructionsLabel.Location = new System.Drawing.Point(1066, 524);
this.DebugInstructionsLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.DebugInstructionsLabel.Name = "DebugInstructionsLabel";
this.DebugInstructionsLabel.Size = new System.Drawing.Size(623, 50);
this.DebugInstructionsLabel.TabIndex = 1;
this.DebugInstructionsLabel.Text = "Press \'Check Machine\' to ensure a device is running, otherwise \n don\'t expect muc" +
"h activity from the rats!";
this.DebugInstructionsLabel.Click += new System.EventHandler(this.DebugInstructionsLabel_Click);
//
// StatusCheckButton
//
this.StatusCheckButton.Location = new System.Drawing.Point(1271, 658);
this.StatusCheckButton.Margin = new System.Windows.Forms.Padding(4);
this.StatusCheckButton.Name = "StatusCheckButton";
this.StatusCheckButton.Size = new System.Drawing.Size(195, 54);
this.StatusCheckButton.TabIndex = 2;
this.StatusCheckButton.Text = "Check Machine Status";
this.StatusCheckButton.UseVisualStyleBackColor = true;
this.StatusCheckButton.Click += new System.EventHandler(this.StatusCheckButton_Click);
//
// TitleLabel
//
this.TitleLabel.AutoSize = true;
this.TitleLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 16F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.TitleLabel.Location = new System.Drawing.Point(1255, 382);
this.TitleLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.TitleLabel.Name = "TitleLabel";
this.TitleLabel.Size = new System.Drawing.Size(211, 51);
this.TitleLabel.TabIndex = 3;
this.TitleLabel.Text = "XML Rats";
this.TitleLabel.Click += new System.EventHandler(this.titleLabel_Click);
//
// WakeRatsButton
//
this.WakeRatsButton.Location = new System.Drawing.Point(1271, 775);
this.WakeRatsButton.Margin = new System.Windows.Forms.Padding(4);
this.WakeRatsButton.Name = "WakeRatsButton";
this.WakeRatsButton.Size = new System.Drawing.Size(195, 54);
this.WakeRatsButton.TabIndex = 4;
this.WakeRatsButton.Text = "Wake Rats";
this.WakeRatsButton.UseVisualStyleBackColor = true;
//
// SleepRatsButton
//
this.SleepRatsButton.Location = new System.Drawing.Point(1271, 885);
this.SleepRatsButton.Margin = new System.Windows.Forms.Padding(4);
this.SleepRatsButton.Name = "SleepRatsButton";
this.SleepRatsButton.Size = new System.Drawing.Size(195, 54);
this.SleepRatsButton.TabIndex = 5;
this.SleepRatsButton.Text = "Sleep Rats";
this.SleepRatsButton.UseVisualStyleBackColor = true;
//
// NISTDataLinkLabel
//
this.NISTDataLinkLabel.AutoSize = true;
this.NISTDataLinkLabel.Location = new System.Drawing.Point(1287, 1054);
this.NISTDataLinkLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
this.NISTDataLinkLabel.Name = "NISTDataLinkLabel";
this.NISTDataLinkLabel.Size = new System.Drawing.Size(162, 25);
this.NISTDataLinkLabel.TabIndex = 6;
this.NISTDataLinkLabel.TabStop = true;
this.NISTDataLinkLabel.Text = "View NIST Data";
//
// BakuPicBox
//
this.BakuPicBox.Image = global::XMLRats5.Properties.Resources.bakuTransSmall;
this.BakuPicBox.Location = new System.Drawing.Point(2092, 1388);
this.BakuPicBox.Name = "BakuPicBox";
this.BakuPicBox.Size = new System.Drawing.Size(632, 424);
this.BakuPicBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
this.BakuPicBox.TabIndex = 9;
this.BakuPicBox.TabStop = false;
//
// HousePicBox
//
this.HousePicBox.Image = global::XMLRats5.Properties.Resources.nosleep;
this.HousePicBox.Location = new System.Drawing.Point(1057, 1388);
this.HousePicBox.Name = "HousePicBox";
this.HousePicBox.Size = new System.Drawing.Size(632, 424);
this.HousePicBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
this.HousePicBox.TabIndex = 8;
this.HousePicBox.TabStop = false;
//
// DekuPicBox
//
this.DekuPicBox.Image = global::XMLRats5.Properties.Resources.DekuBackgroundTransparent;
this.DekuPicBox.Location = new System.Drawing.Point(12, 1388);
this.DekuPicBox.Name = "DekuPicBox";
this.DekuPicBox.Size = new System.Drawing.Size(632, 424);
this.DekuPicBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
this.DekuPicBox.TabIndex = 7;
this.DekuPicBox.TabStop = false;
this.DekuPicBox.Click += new System.EventHandler(this.DekuPicBox_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(12F, 25F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(2736, 1824);
this.Controls.Add(this.BakuPicBox);
this.Controls.Add(this.HousePicBox);
this.Controls.Add(this.DekuPicBox);
this.Controls.Add(this.NISTDataLinkLabel);
this.Controls.Add(this.SleepRatsButton);
this.Controls.Add(this.WakeRatsButton);
this.Controls.Add(this.TitleLabel);
this.Controls.Add(this.StatusCheckButton);
this.Controls.Add(this.DebugInstructionsLabel);
this.Controls.Add(this.MAZAKDataLinkLabel);
this.Margin = new System.Windows.Forms.Padding(4);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.BakuPicBox)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.HousePicBox)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.DekuPicBox)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.LinkLabel MAZAKDataLinkLabel;
private System.Windows.Forms.Label DebugInstructionsLabel;
private System.Windows.Forms.Button StatusCheckButton;
private System.Windows.Forms.Label TitleLabel;
private System.Windows.Forms.Button WakeRatsButton;
private System.Windows.Forms.Button SleepRatsButton;
private System.Windows.Forms.LinkLabel NISTDataLinkLabel;
public System.Windows.Forms.PictureBox DekuPicBox;
public System.Windows.Forms.PictureBox HousePicBox;
public System.Windows.Forms.PictureBox BakuPicBox;
}
}
//-------------------------------------------------------------DRAWING.CS----------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Reflection;
using System.Drawing;
using System.Windows.Forms;
namespace XMLRats5
{
public class Drawing : Form1
{
private PictureBox HouseImage;
private PictureBox DekuImage;
private PictureBox BakuImage;
public Drawing(PictureBox house, PictureBox deku, PictureBox baku)
{
HouseImage = house;
DekuImage = deku;
BakuImage = baku;
} // Code is jumping back to form1 call :S
public void ClearRats()
{
//DekuImage.Image.Dispose();
//BakuImage.Image.Dispose();
//HouseImage.Image.Dispose();
HouseImage.Hide();
DekuImage.Hide();
BakuImage.Hide();
}
public void RePaint()
{
//BakuImage.Paint();
//DekuImage.Paint();
//HouseImage.Paint();
}
public void DrawRats(bool DekuWake, bool BakuWake) // Call this function using active status of 2 machines
{
this.ClearRats();
DekuPicBox.SuspendLayout();
BakuPicBox.SuspendLayout();
HousePicBox.SuspendLayout();
System.Drawing.Point DekuCoord = new System.Drawing.Point(ImageRat.Deku.PosX, ImageRat.Deku.PosY); // Create a 'System Point' for Deku
System.Drawing.Point BakuCoord = new System.Drawing.Point(ImageRat.Bakugo.PosX, ImageRat.Bakugo.PosY); // Create a 'System Point' for Bakugo
Console.WriteLine("Randomly Generated Point Assigned (Deku):" + DekuCoord);
Console.WriteLine("Randomly Generated Point Assigned (Baku):" + BakuCoord);
if (DekuWake == false)
{
DekuImage.Hide();
if (BakuWake == false)
{
BakuPicBox.Hide();
HousePicBox.Image = XMLRats5.Properties.Resources.bothsleep;// set HouseImage to both sleep
}
else
{
BakuPicBox.Location = BakuCoord;
BakuPicBox.Show();
HousePicBox.Image = XMLRats5.Properties.Resources.dekuSleep; //Set HouseImage to DekuSleep
}
}
else //DekuWake == true
{
DekuImage.Show();
if (BakuWake == true)
{
HousePicBox.Image = XMLRats5.Properties.Resources.nosleep;//Set House image to nosleep
DekuPicBox.Location = DekuCoord;
DekuPicBox.Show();
BakuPicBox.Location = BakuCoord;
BakuPicBox.Show();
}
else
{
BakuPicBox.Hide();
HousePicBox.Image = XMLRats5.Properties.Resources.bakusleep;// Set house image to bakusleep
DekuPicBox.Location = DekuCoord;
DekuPicBox.Show();
}
}
HousePicBox.Show(); // Out here as it should always happen
}
}
}
Honestly I'm baffled as to why it keeps jumping back to the start of form1.
What have I broken?
As Drawing is derived from Form1 & you create an instance of Drawing in the Form1 constructor - this is going to cause the Form1 constructor to be invoked again which causes the creation of another instance of Drawing which causes ........... -
Note the base class constructor is called before the code in the derived class constructor - which is why you don't get to the code in the Drawing constructor.
Similar to
MessageBox.Show("Test", "Test")
I have made a ProgressWindow, which is shown before a long-running action, and hidden thereafter:
ProgressWindow.Show("Test","Test")
Thread.Sleep(20000);
ProgressWindow.Hide();
using the following code:
class ProgressWindow : Form
{
private Label label1;
private static ProgressWindow window;
internal static void Show(string Message, string Caption)
{
window = new ProgressWindow(Message, Caption);
window.Show();
}
internal new static void Hide()
{
(ProgressWindow.window as Control).Hide();
}
private ProgressWindow(string Message, string Caption)
{
InitializeComponent(Message, Caption);
}
private void InitializeComponent(string Message, string Caption)
{
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// label1
//
this.label1.Location = new System.Drawing.Point(50, 40);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(300, 120);
this.label1.TabIndex = 0;
this.label1.Text = Message;
//
// ProgressWindow
//
this.ClientSize = new System.Drawing.Size(400, 200);
this.ShowIcon = false;
this.MinimizeBox = false;
this.MaximizeBox = false;
this.ControlBox = false;
this.FormBorderStyle = FormBorderStyle.FixedDialog;
this.StartPosition = FormStartPosition.CenterScreen;
this.Controls.Add(this.label1);
this.Name = "ProgressWindow";
this.Text = Caption;
this.TopMost = true;
this.ResumeLayout(false);
}
}
The problem now is that my progress window is shown, but in the position of the label, there is a white box only, and no text. Furthermore, if I try to click the window, the title changes from "Test" to "Test (not responding...)".
Why is that, and how would I change that?
I suspected an issue with thread blocking (but why? shouldn't the label be rendered?) and tried
internal static void Show(string Message, string Caption)
{
window = new ProgressWindow(Message, Caption);
new Thread(t => {
window.Show();
}).Start();
}
but this doesn't show the ProgressWindow form at all.
Yes, the problem is due to thread blocking. When Thread.Sleep() is called, the current thread is doing nothing, which means that no Windows messages are processed. This prevents your progress dialog from completely displaying its UI.
I'm not exactly sure why calling the Show() method on a background thread doesn't work, but I believe that WinForms requires the UI thread to be a Single Threaded Apartment, and by default threads are Multi-Threaded Apartment.
To implement this properly, I would suggested using the BackgroundWorker class. It automatically creates a background thread to perform the long running work on, and will fire an even once the work completes. You can use it something like this:
ProgressWindow.Show("Test","Test");
var worker = new BackgroundWorker();
worker.DoWork += (sender, args) => {
// perform your long running task here, this is a background thread
Thread.Sleep(2000);
};
worker.RunWorkerCompleted += (sender, args) => {
// update the UI here, this is running on the UI thread
ProgressWindow.Hide();
}
worker.RunWorkerAsync();
Note that RunWorkerAsync() will return right away, so your UI will need to handle the fact that the user can interact with the UI before the background task has finished.
I'm experiencing a strange deadlock in the code that I've written.
The idea is to implement an asynchronous operation whose Stop is synchronous -- the caller has to wait until it completes. I've simplified the part where real work is done to a simple property increment (++Value, see below); in reality though, a heavy COM component is invoked which is very sensitive to threads.
The deadlock I'm experiencing is in the Stop() method where I explicitly wait for a manual-reset event that identifies a completed operation.
Any ideas what I could have done wrong? The code should be self-contained and compilable on its own.
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
using ThreadingTimer = System.Threading.Timer;
namespace CS_ManualResetEvent
{
class AsyncOperation
{
ThreadingTimer myTimer; //!< Receives periodic ticks on a ThreadPool thread and dispatches background worker.
ManualResetEvent myBgWorkerShouldIterate; //!< Fired when background worker must run a subsequent iteration of its processing loop.
ManualResetEvent myBgWorkerCompleted; //!< Fired before the background worker routine exits.
BackgroundWorker myBg; //!< Executes a background tasks
int myIsRunning; //!< Nonzero if operation is active; otherwise, zero.
public AsyncOperation()
{
var aTimerCallbac = new TimerCallback(Handler_Timer_Tick);
myTimer = new ThreadingTimer(aTimerCallbac, null, Timeout.Infinite, 100);
myBg = new BackgroundWorker();
myBg.DoWork += new DoWorkEventHandler(Handler_BgWorker_DoWork);
myBgWorkerShouldIterate = new ManualResetEvent(false);
myBgWorkerCompleted = new ManualResetEvent(false);
}
public int Value { get; set; }
/// <summary>Begins an asynchronous operation.</summary>
public void Start()
{
Interlocked.Exchange(ref myIsRunning, 1);
myTimer.Change(0, 100);
myBg.RunWorkerAsync(null);
}
/// <summary>Stops the worker thread and waits until it finishes.</summary>
public void Stop()
{
Interlocked.Exchange(ref myIsRunning, 0);
myTimer.Change(-1, Timeout.Infinite);
// fire the event once more so that the background worker can finish
myBgWorkerShouldIterate.Set();
// Wait until the operation completes; DEADLOCK occurs HERE!!!
myBgWorkerCompleted.WaitOne();
// Restore the state of events so that we could possibly re-run an existing component.
myBgWorkerCompleted.Reset();
myBgWorkerShouldIterate.Reset();
}
void Handler_BgWorker_DoWork(object sender, EventArgs theArgs)
{
while (true)
{
myBgWorkerShouldIterate.WaitOne();
if (myIsRunning == 0)
{
//Thread.Sleep(5000); //What if it takes some noticeable time to finish?
myBgWorkerCompleted.Set();
break;
}
// pretend we're doing some valuable work
++Value;
// The event will be set back in Handler_Timer_Tick or when the background worker should finish
myBgWorkerShouldIterate.Reset();
}
// exit
}
/// <summary>Processes tick events from a timer on a dedicated (thread pool) thread.</summary>
void Handler_Timer_Tick(object state)
{
// Let the asynchronous operation run its course.
myBgWorkerShouldIterate.Set();
}
}
public partial class Form1 : Form
{
private AsyncOperation myRec;
private Button btnStart;
private Button btnStop;
public Form1()
{
InitializeComponent();
}
private void Handler_StartButton_Click(object sender, EventArgs e)
{
myRec = new AsyncOperation();
myRec.Start();
btnStart.Enabled = false;
btnStop.Enabled = true;
}
private void Handler_StopButton_Click(object sender, EventArgs e)
{
myRec.Stop();
// Display the result of the asynchronous operation.
MessageBox.Show (myRec.Value.ToString() );
btnStart.Enabled = true;
btnStop.Enabled = false;
}
private void InitializeComponent()
{
btnStart = new Button();
btnStop = new Button();
SuspendLayout();
// btnStart
btnStart.Location = new System.Drawing.Point(35, 16);
btnStart.Size = new System.Drawing.Size(97, 63);
btnStart.Text = "Start";
btnStart.Click += new System.EventHandler(Handler_StartButton_Click);
// btnStop
btnStop.Enabled = false;
btnStop.Location = new System.Drawing.Point(138, 16);
btnStop.Size = new System.Drawing.Size(103, 63);
btnStop.Text = "Stop";
btnStop.Click += new System.EventHandler(Handler_StopButton_Click);
// Form1
ClientSize = new System.Drawing.Size(284, 94);
Controls.Add(this.btnStop);
Controls.Add(this.btnStart);
Text = "Form1";
ResumeLayout(false);
}
}
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
It seems like all you're trying to do is have an asynchronous task that starts with the press of a button and stops when another button is pressed. Given that, you seem to be over-complicating the task. Consider using something designed for cancelling an asynchronous operation, such as a CancellationToken. The async task simply needs to check the cancellation token's status in the while loop (as opposed to while(true)) and the stop method becomes as simple as calling cancel on the CancellationTokenSource.
private CancellationTokenSource cancellationSource;
private Task asyncOperationCompleted;
private void button1_Click(object sender, EventArgs e)
{
//cancel previously running operation before starting a new one
if (cancellationSource != null)
{
cancellationSource.Cancel();
}
else //take out else if you want to restart here when `start` is pressed twice.
{
cancellationSource = new CancellationTokenSource();
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
asyncOperationCompleted = tcs.Task;
BackgroundWorker bgw = new BackgroundWorker();
bgw.DoWork += (_, args) => DoWork(bgw, cancellationSource);
bgw.ProgressChanged += (_, args) => label1.Text = args.ProgressPercentage.ToString();
bgw.WorkerReportsProgress = true;
bgw.RunWorkerCompleted += (_, args) => tcs.SetResult(true);
bgw.RunWorkerAsync();
}
}
private void DoWork(BackgroundWorker bgw, CancellationTokenSource cancellationSource)
{
int i = 0;
while (!cancellationSource.IsCancellationRequested)
{
Thread.Sleep(1000);//placeholder for real work
bgw.ReportProgress(i++);
}
}
private void StopAndWaitOnBackgroundTask()
{
if (cancellationSource != null)
{
cancellationSource.Cancel();
cancellationSource = null;
asyncOperationCompleted.Wait();
}
}
put this code under ++Value; in Handler_BgWorker_DoWork. Then press the button when you see the output in debug window. Deadlock occurs then.
int i = 0;
while (i++ < 100) {
System.Diagnostics.Debug.Print("Press the button now");
Thread.Sleep(300);
Application.DoEvents();
}
I know little about C#.
I am trying to display a progressbar with the status of the background command line program.
After google examples of progressbar and run process in c#, so I'm trying to start a BackgroundWorker in the Windows Form, and run the command line program in the BackgroundWorker. I want to parse the command line's output to get the progress
percentage and display it to the progress bar.
The command line program is a console program, it will output periodically its current status of progress.
But it seems it did not work. I can't readline any lines of the process's standard output.
Is there anything I missed?
Here is the raw code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;
using System.Diagnostics;
using System.IO;
public class DemoForm : Form
{
private BackgroundWorker backgroundWorker1;
private Button loadButton;
private ProgressBar progressBar1;
public DemoForm()
{
InitializeComponent();
backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(
this.backgroundWorker1_DoWork);
backgroundWorker1.RunWorkerCompleted +=
new System.ComponentModel.RunWorkerCompletedEventHandler(
this.backgroundWorker1_RunWorkerCompleted);
backgroundWorker1.ProgressChanged +=
new System.ComponentModel.ProgressChangedEventHandler(
this.backgroundWorker1_ProgressChanged);
}
private void loadButton_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
this.loadButton.Enabled = false;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
string status;
Process p = new Process();
p.StartInfo.FileName = "xx.exe";
p.StartInfo.Arguments = "-q -r test.cap -p";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.CreateNoWindow = true;
p.OutputDataReceived += this.p_OutputDataReceived;
p.EnableRaisingEvents = true;
p.Start();
p.BeginOutputReadLine();
/*
while((status = p.StandardOutput.ReadLine()) != null)
{
Console.WriteLine(status);
string[] words = status.Split(' ');
int offset = Convert.ToInt32(words[0]);
int size = Convert.ToInt32(words[1]);
int percentComplete = 100 * offset / size;
MessageBox.Show(words[0], words[1]);
backgroundWorker1.ReportProgress(percentComplete);
}
Console.WriteLine("wait for exit!");
StreamReader myStreamReader = p.StandardOutput;
status = myStreamReader.ReadLine();
Console.WriteLine(status);
Console.WriteLine("wait for exit!");
*/
p.WaitForExit();
}
void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
string status = e.Data;
Console.WriteLine("get events");
Console.WriteLine(status);
string[] words = status.Split(' ');
int offset = Convert.ToInt32(words[0]);
int size = Convert.ToInt32(words[1]);
int percentComplete = 100 * offset / size;
MessageBox.Show(words[0], words[1]);
backgroundWorker1.ReportProgress(percentComplete);
}
private void backgroundWorker1_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
progressBar1.Value = 100;
if (e.Error == null) {
MessageBox.Show ("Demo", "Loading completed");
}
}
private void backgroundWorker1_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
this.progressBar1.Value = e.ProgressPercentage;
}
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.loadButton = new System.Windows.Forms.Button();
this.progressBar1 = new System.Windows.Forms.ProgressBar();
/* load button */
this.loadButton.Location = new System.Drawing.Point(12, 12);
this.loadButton.Name = "loadButton";
this.loadButton.Size = new System.Drawing.Size(100, 23);
this.loadButton.TabIndex = 0;
this.loadButton.Text = "Load file";
this.loadButton.UseVisualStyleBackColor = true;
this.loadButton.Click += new System.EventHandler(this.loadButton_Click);
/* progress bar */
this.progressBar1.Location = new System.Drawing.Point(12, 50);
this.progressBar1.Name = "progressBar1";
this.progressBar1.Size = new System.Drawing.Size(100, 26);
this.progressBar1.TabIndex = 1;
/* Form */
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(133, 104);
this.Controls.Add(this.progressBar1);
this.Controls.Add(this.loadButton);
this.Name = "DemoForm";
this.Text = "DemoForm";
this.ResumeLayout (false);
}
}
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new DemoForm());
}
}
Or is there any better way to get a command line program's progress?
You have to set the WorkerReportsProgress property of your backgroundWorker to true in order to be able to report while your backgroundWorker is running:
backgroundWorker1.WorkerReportsProgress = true;
After manually flush the output of the command line program, problem solved.
fflush(stdout);
It's not clear why it's buffered even a line ended.
Building on what Kamyar was stating, you would need to then code a delegate to capture the progress of your backgroundWorker object using a UserState object. This could be any object really, but you use it to update other aspects of the GUI, in this case a status label...
this.backgroundWorker1.WorkerReportsProgress = true;
this.backgroundWorker1.WorkerSupportsCancellation = true;
this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
this.backgroundWorker1.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.backgroundWorker1_ProgressChanged);
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
private class Progress
{
public string Status { get; set; }
public Progress(string status)
{
Status = status;
}
}
//...
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
while(myWork)
{
if(backgroundWorker1.CancellationPending)
{
e.Cancel = true;
break;
}
int p = //...percentage calc
backgroundWorker1.ReportProgress(p, new Progress("My message...")));
}
e.Cancel = false;
}
void backgroundWorker1_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
Progress p = (Progress)e.UserState;
lStatus.Text = p.Status;
progressBar.Value = e.ProgressPercentage;
}
This is just one method of implementing it though.
Thanks.
This is in C#
So I'm trying to create an event for ProgressChanged for multiple webBrowser Controls. These are all dynamically created as well as the progress bar. So i can't call upon it prior. What i'm doing is passing the progress bar through object arrays that are ran. It finally gets to the final method in which i create the browser and need to create the Browser.ProgressChanged event.
Here's the code....
private object[] runTests(string banText, object tabControlName,
object progressBar, int runThisTest, string testName)
{
object[] theReturn = null;
if (stopTests == false)
{
var tabPageBrowser = new TabPage();
var Browser = new WebBrowser();
(tabControlName as TabControl).TabPages.Add(tabPageBrowser);
tabPageBrowser.Name = tabControlName.ToString();
if (banText == "999999999")
{
tabPageBrowser.Text = "History";
}
else
{
tabPageBrowser.Text = testName;
}
tabPageBrowser.Font = new System.Drawing.Font("Trebuchet MS", 8.25F,
System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
Browser.Dock = DockStyle.Fill;
Browser.Url = new Uri(testStrings(runThisTest, banText));
Browser.Name = tabControlName.ToString();
Browser.ScriptErrorsSuppressed = true;
tabPageBrowser.Controls.Add(Browser);
Browser.ProgressChanged += new WebBrowserProgressChangedEventHandler(Browser_ProgressChanged);
try
{
while (Browser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
}
catch
{
return null;
}
IntPtr pHandle = GetCurrentProcess();
SetProcessWorkingSetSize(pHandle, -1, -1);
object[] browserObjects = new object[2];
browserObjects[0] = tabPageBrowser;
browserObjects[1] = Browser;
if(browserObjects != null)
{
theReturn = browserObjects;
}
}
return theReturn;
}
Now my question is, how can I add the "progressBar" object when i create the event so i can call upon it when the event has been fired. I'm basically creating a single progress bar for 5+ WebBrowser controls and linking the progress of them together. So for some reason i tried to add the object to the method and it fails out on me. Please assist and Thanks!.
Browser.ProgressChanged += Browser_ProgressChanged;
...
void Browser_ProgressChanged(object sender, WebBrowserProgressChangedEventArgs e) {
if (e.MaximumProgress > 0) {
int prog = (int)(100 * e.CurrentProgress / e.MaximumProgress);
progressBar1.Value = prog;
}
}
private ProgressBar progressBar1;