I am new to C# and I am having a problem. I have a Form that runs a thread which receives input from a serial port. However when the window is closed the thread keeps running. I tried overriding virtual void OnClosing(object sender, CancelEventArgs e) but the MessageBox keeps popping up which means the thread is still running. What am I doing wrong? Which is the best lifecycle method to override to do cleanup before the window is closed?
DisplayForm.cs
using System;
using System.ComponentModel;
using System.Drawing;
using System.IO.Ports;
using System.Threading;
using System.Windows.Forms;
namespace project
{
public partial class DisplayForm : Form
{
private Thread readThread;
private SerialPort port;
private bool running;
public DisplayForm(String portName)
{
InitializeComponent();
port = new SerialPort(portName);
port.Open();
readThread = new Thread(Read);
running = true;
readThread.Start();
}
public void Read()
{
while (running)
{
try
{
string message = port.ReadLine();
Console.Write(message);
MessageBox.Show(message);
}
catch (TimeoutException)
{
}
}
}
protected virtual void OnClosing(object sender, CancelEventArgs e)
{
running = false;
readThread.Join();
port.Close();
}
}
}
You need to use Abort() and not Join().
protected virtual void OnClosing(object sender, CancelEventArgs e)
{
running = false;
readThread.Abort();
port.Close();
}
OnClosing or OnClosed event call try to see any child thread running and abort them all...in your code first call port.close and then runThread which you already have access to it in Oncl
Related
I'm new to c# and have a simple project where I have one Form1, which has a button to open Form2 (Diagnostics page to be password protected later on).
I have created a SerialPortClass which as you can guess handles all the serial port methods, such as openport, sendline, isPortOpen etc.
What I want to do is receive a serial string from the serial port in the SerialPortClass, then display this string in a text box in Form2. I have tried to achieve this in several ways after reading many posts on this site and others.
From what I read, using the BackGroundWorker is the best way of doing this. So I copied the example Microsoft Thread safe example, and have a button on Form2 to use the BackGroundWorker, to display text in the TextBox successfully. However when I try to run the BackGroundWorker from SerialPortClass I get a:
Exception thrown: 'System.NullReferenceException' in SerialTest.exe
Additional information: Object reference not set to an instance of an object.
Can anyone point me in the right direction please?
I know I'm actually passing the string yet, but just trying to start the background working in the other class as a test
Full SerialPortClass:
using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Windows.Forms;
using System.Collections;
using System.Threading;
using System.Reflection;
using UsbLibrary;
namespace SerialTest
{
public class SerialPortClass : Form
{
private static SerialPortClass instance;
private System.IO.Ports.SerialPort serialPort1 = new SerialPort(); // Initilises an instance of COM port
private System.IO.Ports.SerialPort serialPort2 = new SerialPort(); // and another
Form1 form1;
Form2 form2;
internal delegate void SerialDataReceivedEventHandlerDelegate(
object sender, SerialDataReceivedEventArgs e);
delegate void SetTextCallback(string text);
string InputData = String.Empty;
private static SerialPort port;
public SerialPortClass()
{
serialPort1.DataReceived +=
new System.IO.Ports.SerialDataReceivedEventHandler(port_DataReceived_1);
}
public static readonly SerialPortClass _instance = new SerialPortClass();
public ThreadStart ThreadProcSafe { get; private set; }
public bool serialOpen(int port)
{
if (port == 1)
{
if (serialPort1.IsOpen) return true;
else return false;
}
else if (port == 2)
{
if (serialPort2.IsOpen) return true;
else return false;
}
else return false;
}
public void serialSendString(int port, string command)
{
if (port == 1)
{
// If the port is closed, don't try to send a character.
if (!serialPort1.IsOpen) return;
serialPort1.WriteLine(command);
}
else if (port == 2)
{
if (!serialPort2.IsOpen) return;
serialPort2.WriteLine(command);
}
else
{
MessageBox.Show("Invalid port no");
}
}
public void serialSendString1(string command)
{
// If the port is closed, don't try to send a character.
if (serialPort1.IsOpen)
{
serialPort1.WriteLine(command);
}
else
{
MessageBox.Show("port not opening at connect..");
return;
}
}
public void serialSendString2(string command)
{
// If the port is closed, don't try to send a character.
if (serialPort2.IsOpen)
{
serialPort2.WriteLine(command);
}
else
{
MessageBox.Show("port not opening at connect..");
return;
}
}
public void Connect() //SerialTest.Form1 form) //string comPortNo, int baud)
{
serialPort1.PortName = "COM38"; // comPortNo;
serialPort1.BaudRate = 9600; // baud;
if (serialOpen(1))
{
MessageBox.Show("Serial port already open");
return;
}
try
{
serialPort1.Open();
serialPort1.NewLine = "\r";
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
if (serialOpen(1))
{
Console.WriteLine("port open");
}
else
{
MessageBox.Show("port not opening at connect..");
}
}
private void port_DataReceived_1(object sender, SerialDataReceivedEventArgs e)
{
Console.WriteLine("Data recieved");
InputData = serialPort1.ReadExisting();
if (InputData != String.Empty)
{
SetText(InputData);
}
}
public void SetText(string text)
{
Console.WriteLine("set text");
form2.backgroundWorker1.RunWorkerAsync();
}
public void disconnect()
{
//serialPort1.PortName = "COM38";
//serialPort1.BaudRate = 9600;
if (serialOpen(1))
{
serialPort1.Close();
Console.WriteLine("Port closed");
}
else
{
MessageBox.Show("Port not open to close");
}
}
public class SerialErrorReceivedEventArgs : EventArgs
{
//Data to pass to the event
public string LineData { get; private set; }
public SerialErrorReceivedEventArgs(string lineData)
{
this.LineData = lineData;
}
}
}
}
and Form2:
using System;
using System.Threading;
using UsbLibrary;
using log4net;
using SensorTestApp;
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;
using SerialTest;
using System.IO.Ports;
namespace SerialTest
{
public partial class Form2 : Form
{
string comPortNo;
// This delegate enables asynchronous calls for setting
// the text property on a TextBox control.
delegate void SetTextCallback(string text);
// This thread is used to demonstrate both thread-safe and
// unsafe ways to call a Windows Forms control.
public Thread demoThread = null;
// This BackgroundWorker is used to demonstrate the
// preferred way of performing asynchronous operations.
public BackgroundWorker backgroundWorker1;
//private TextBox tBQuery;
private Button setTextUnsafeBtn;
private Button setTextSafeBtn;
private Button setTextBackgroundWorkerBtn;
private System.ComponentModel.IContainer components1 = null;
public static Form2 _instance = new Form2();
public Form2()
{
InitializeComponent();
this.backgroundWorker1 = new BackgroundWorker();
// here you have also to implement the necessary events
// this event will define what the worker is actually supposed to do
this.backgroundWorker1.DoWork += backgroundWorker1_DoWork;
//this.backgroundWorker1.RunWorkerAsync += backgroundWorker1_RunWorkerAsync;
// this event will define what the worker will do when finished
this.backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
btnRelay1On.Enabled = false;
btnRelay2On.Enabled = false;
btnRelay3On.Enabled = false;
btnRelay4On.Enabled = false;
btnRelay5On.Enabled = false;
btnRelay1Off.Enabled = false;
btnRelay2Off.Enabled = false;
btnRelay3Off.Enabled = false;
btnRelay4Off.Enabled = false;
btnRelay5Off.Enabled = false;
}
// This event handler creates a thread that calls a
// Windows Forms control in a thread-safe way.
private void button2_Click(
object sender,
EventArgs e)
{
this.demoThread =
new Thread(new ThreadStart(this.ThreadProcSafe));
this.demoThread.Start();
}
// This method is executed on the worker thread and makes
// a thread-safe call on the TextBox control.
public void ThreadProcSafe()
{
this.SetText("This text was set safely.");
}
// This method demonstrates a pattern for making thread-safe
// calls on a Windows Forms control.
//
// If the calling thread is different from the thread that
// created the TextBox control, this method creates a
// SetTextCallback and calls itself asynchronously using the
// Invoke method.
//
// If the calling thread is the same as the thread that created
// the TextBox control, the Text property is set directly.
public void AppendText(String text)
{
if (this.InvokeRequired)
{
this.Invoke(new Action<string>(AppendText), new object[] { text });
return;
}
this.richTextBox1.Text += text;
}
public void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.tBQuery.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
Console.WriteLine("different thread, text callback");
}
else
{
Console.WriteLine("same thread, string: %s", text);
this.tBQuery.Text = text;
}
}
// This event handler starts the form's
// BackgroundWorker by calling RunWorkerAsync.
//
// The Text property of the TextBox control is set
// when the BackgroundWorker raises the RunWorkerCompleted
// event.
public void button1_Click(
object sender,
EventArgs e)
{
this.backgroundWorker1.RunWorkerAsync();
}
public void backgroundWorker1_DoWork(object sender,
DoWorkEventArgs e)
{
Console.WriteLine("BackgroundWorker1_Do Work");
}
// This event handler sets the Text property of the TextBox
// control. It is called on the thread that created the
// TextBox control, so the call is thread-safe.
//
// BackgroundWorker is the preferred way to perform asynchronous
// operations.
public void backgroundWorker1_RunWorkerCompleted(
object sender,
RunWorkerCompletedEventArgs e)
{
this.tBQuery.Text =
"This text was set safely by BackgroundWorker.";
}
private void cbComPort_SelectedIndexChanged(object sender, EventArgs e)
{
comPortNo = cbComPort.Text.ToString();
btnOpenCom.Enabled = true;
}
private void btnOpenCom_Click(object sender, EventArgs e)
{
//SerialPortClass.GetInstance().Connect(comPortNo, 9600);
try
{
SerialPortClass._instance.Connect();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
if (SerialPortClass._instance.serialOpen(1))
{
btnOpenCom.Enabled = false;
btnCloseCom.Enabled = true;
btnRelay1On.Enabled = true;
btnRelay2On.Enabled = true;
btnRelay3On.Enabled = true;
btnRelay4On.Enabled = true;
btnRelay5On.Enabled = true;
btnRelay1Off.Enabled = true;
btnRelay2Off.Enabled = true;
btnRelay3Off.Enabled = true;
btnRelay4Off.Enabled = true;
btnRelay5Off.Enabled = true;
}
else MessageBox.Show("port not open btnOpenCom");
}
private void btnCloseCom_Click(object sender, EventArgs e)
{
try
{
SerialPortClass._instance.disconnect();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
if (!SerialPortClass._instance.serialOpen(1))
{
btnOpenCom.Enabled = true;
btnCloseCom.Enabled = false;
btnRelay1On.Enabled = false;
btnRelay2On.Enabled = false;
btnRelay3On.Enabled = false;
btnRelay4On.Enabled = false;
btnRelay5On.Enabled = false;
btnRelay1Off.Enabled = false;
btnRelay2Off.Enabled = false;
btnRelay3Off.Enabled = false;
btnRelay4Off.Enabled = false;
btnRelay5Off.Enabled = false;
}
}
private void btnRelay1On_Click(object sender, EventArgs e)
{
SerialPortClass._instance.serialSendString(1, "OH1");
}
private void btnRelay1Off_Click(object sender, EventArgs e)
{
SerialPortClass._instance.serialSendString(1, "OL1");
}
private void btnRelay2On_Click(object sender, EventArgs e)
{
SerialPortClass._instance.serialSendString(1, "OH2");
}
private void btnRelay2Off_Click(object sender, EventArgs e)
{
SerialPortClass._instance.serialSendString(1, "OL2");
}
private void btnRelay3On_Click(object sender, EventArgs e)
{
SerialPortClass._instance.serialSendString(1, "OH3");
}
private void btnRelay3Off_Click(object sender, EventArgs e)
{
SerialPortClass._instance.serialSendString(1, "OL3");
}
private void btnRelay4On_Click(object sender, EventArgs e)
{
SerialPortClass._instance.serialSendString(1, "OH4");
}
private void btnRelay4Off_Click(object sender, EventArgs e)
{
SerialPortClass._instance.serialSendString(1, "OL4");
}
private void btnRelay5On_Click(object sender, EventArgs e)
{
SerialPortClass._instance.serialSendString(1, "OH5");
}
private void btnRelay5Off_Click(object sender, EventArgs e)
{
SerialPortClass._instance.serialSendString(1, "OL5");
}
private void btnQuery_Click(object sender, EventArgs e)
{
//this.BeginInvoke(new SetTextCallback(SetText), new object[] { "hjdfdsfj" });
SerialPortClass._instance.serialSendString(1, "?");
Console.WriteLine("?");
}
}
}
Also there's references to BackgroundWorker in the Designer file, so I've included it here too:
this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
//
// backgroundWorker1
//
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
//private System.ComponentModel.BackgroundWorker backgroundWorker1;
What you are missing is the initialization of the BackGroundWorker. You should do this in the constructor:
public Form2()
{
InitializeComponent();
this.backgroundWorker1 = new BackGroundWorker();
// here you have also to implement the necessary events
// this event will define what the worker is actually supposed to do
this.backgroundWorker1 .DoWork += backgroundWorker1r_DoWork;
// this event will define what the worker will do when finished
this.backgroundWorker1 .RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
}
EDIT:
As I read your post a little more clearly. If you want to:
I try to run the BackGroundWorker from SerialPortClass
You have to make sure that you have an instance of the Form2 in your SerialPortClass. Note that if you just use the new keyword it might not be the same instance as is already shown on your monitor.
EDIT 2:
Ok there seems to be a pattern emerging. Please correct me if I am wrong
As I understand you open Form1 where you have a field SerialPortClass sp_class. In Form1 you press a button and this button calls the method:
sp_class.SetText();
Now you have a problem because apparently when you come to the line:
form2.backgroundWorker1.RunWorkerAsync();
form2 is null because it has never been instantiated! Please do the following: Create an instance and open the form from the SerialPortClass like this:
form2 = new Form2();
form2.backgroundWorker1.RunWorkerAsync();
form2.Show();
Now, the event registration of the backgroundWorker1 still belongs into the Form2 class , because this is where you actually let it run! The instance is still in Form2 please don't get mixed up in this triangle of Form1, Form2 and SerialPortClass
EDIT 3:
Since your SerialPort triggers the backgroundWorker1 you should already in the constructor of the SeralPortClass make an instance of the Form2 like this:
public SerialPortClass()
{
form2 = new Form2();
serialPort1.DataReceived +=
new System.IO.Ports.SerialDataReceivedEventHandler(port_DataReceived_1);
}
But what you really should do to unwind the knot that you created between your 3 classes which seem to depend on each other, is to pass the instance of the Form2 to the constructor of the SerialPortClass like this:
public SerialPortClass(Form2 f2)
{
form2 = f2
serialPort1.DataReceived +=
new System.IO.Ports.SerialDataReceivedEventHandler(port_DataReceived_1);
}
and I guess in Form1 you make an instance of Form2 which you call and the SerialPortClass which you use to call SetText. And exactly there you need to pass the instance into the contructor call:
SerialPortClass my_sp_class = new SerialPortClass(form2);
This will make sure that you get the display of text on the desired form
The issue is here.
form2.backgroundWorker1.RunWorkerAsync();
You have created a backgroundwoker but not registered any methods/delegates to it.
Assign it by adding this in constructor of form2,
this.backgroundWorker1.DoWork += backgroundWorker1_DoWork; //not found in snippet
this.backgroundWorker1.RunWorkerCompleted +=backgroundWorker1_RunWorkerCompleted;
Also, as mentioned by Mong-Zhu, you need to initialize Backgroundworker like this in form2.
this.backgroundWorker1 = new BackGroundWorker();
Also, I personally think it is not a good idea to call backgroundworker of different form.
After reading the comments and such, I can see that you're not referencing the same form2, and you're also not initializing a new one, meaning the said null reference is invalid.
When you do the code
Form2 form2;
This is simply preparing a variable to be assigned, and since you haven't done this you can't access it's objects. If you wish to reference your form2, initialise it globally where you're able to access it, and from there you can use it's objects.
If you need any more guidance just reply :)
It seems that your use of BackgroundWorker is incomplete. You can use it with the Designer, which is easier, or in the code-behind.
To use with the designer, drag and drop a backgroundWorker object onto the component tray. Then click on the newly created BackgroundWorker1 object. Go over to the properties tray and select the lightning bolt for events. There are 3 events, the two that you will need are the DoWork and RunWorkerCompleted. Double-click on both to generate the methods for you.
It appears in your code snippet that you are missing the DoWork part, as well as not actually instantiating your BackGroundWorker object. The way it flows is this: The BackgroundWorker is declared and initialized. When you need to make an asynchronous call you raise the .RunWorkerAsync event. That RunWorkerAsync event will make its way to your DoWork event handler. This is where you place the code for the work you wish to do asynchronously. Once this DoWork event expires, the RunWorkercompleted event is called. Once this RunWorkerCompleted event expires, so does the new thread.
If you try to change designer components while in a different thread than the thread it was created on (i.e. setting button text from inside the DoWork event handler for the BackgroundWorker), you will have to ensure to use the .InvokeRequired, as it appears you have already started.
If you are calling this backgroundworker from outside of form2 make sure that you are giving the handle to form2 to that class. It is unclear from the snippet whether you instantiated a new one or not. An easy way is to make a private field for Form2 in your Serialization class, as well as a method, say AttachForm(Form f) and then call that method from Form2, passing this as a parameter.
I have a WinForm with a backgroundWorker:
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 SeoTools.Utils;
namespace SeoTools.UI
{
public partial class UIProgress : Form
{
public UIProgress(DoWorkEventHandler doWorkEventHandler, RunWorkerCompletedEventHandler runWorkerCompletedEventHandler)
{
InitializeComponent();
this.backgroundWorker.WorkerReportsProgress = true;
this.backgroundWorker.WorkerSupportsCancellation = true;
this.backgroundWorker.DoWork += doWorkEventHandler;
this.backgroundWorker.RunWorkerCompleted += runWorkerCompletedEventHandler;
}
public void Start()
{
var foo = SynchronizationContext.Current;
backgroundWorker.RunWorkerAsync();
}
private void btnStop_Click(object sender, EventArgs e)
{
btnStop.Enabled = false;
btnStop.Text = "Stopping...";
backgroundWorker.CancelAsync();
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
try
{
wdgProgressBar.Value = e.ProgressPercentage;
if (this.Visible == false)
{
this.ShowDialog();
this.Update();
}
}
catch (InvalidOperationException) {}
}
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.Hide(); //Here I get a InvalidOperationException
this.Dispose();
}
}
}
First time I run this it works fine. But second time I get InvalidOperationException when calling this.Hide().
"Additional information: Cross-thread operation not valid: Control 'UIProgress' accessed from a thread other than the thread it was created on."
The weird thing is on first run foo in Start() is a WindowsFormsSyncronizationContext but on the second try it's a System.Threading.SyncronizationContext.
The application I'm writing is a ExcelDna plugin.
EDIT
Start() is called like this:
UIProgress uiProgress = new UIProgress(
delegate(object sender, DoWorkEventArgs args)
{
....
},
delegate(object sender, RunWorkerCompletedEventArgs args)
{
...
}
);
uiProgress.Start();
Your Start() method must be called from code that runs on the UI thread to allow the BackgroundWorker to operate correctly. It was not when you get this exception. Add protective code to your method so you can diagnose this mishap:
public void Start()
{
if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA) {
throw new InvalidOperationException("Bug! Code called from a worker thread");
}
backgroundWorker.RunWorkerAsync();
}
Now you can set a breakpoint on the throw statement and use the debugger's Call Stack window to find out why this happened.
You are calling UI operation on background thread. This is the reason for that exception. I would use entirely different method to make the progress form the best one is to use Task with IProgress. The other way it to use this:
private void backgroundWorker_ProgressChanged( object sender , ProgressChangedEventArgs e )
{
this.UpdateOnMainThread(
( ) =>
{
wdgProgressBar.Value = e.ProgressPercentage;
if ( this.Visible == false )
{
this.ShowDialog( );
this.Update( );
}
} );
}
private void UpdateOnMainThread( Action action )
{
if ( this.InvokeRequired )
{
this.BeginInvoke( ( MethodInvoker ) action.Invoke);
}
else
{
action.Invoke( );
}
}
private void backgroundWorker_RunWorkerCompleted( object sender , RunWorkerCompletedEventArgs e )
{
this.UpdateOnMainThread(
( ) =>
{
this.Hide( ); //Here I get a InvalidOperationException
this.Dispose( );
} );
}
Use the BeginInvoke() method on the form:
//http://msdn.microsoft.com/en-us/library/0b1bf3y3(v=vs.110).aspx
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.BeginInvoke(new InvokeDelegate(InvokeMethod));
}
public delegate void InvokeDelegate();
public void InvokeMethod()
{
this.Hide();
this.Dispose();
}
I think you can find some help here: BackgroundWorker hide form window upon completion .
However don't forget to detach BackgroundWorker events and stop BackgroundWorker it self like explained in here: Proper way to Dispose of a BackGroundWorker .
The problem can be in the
this.Dispose();
in the backgroundWorker_RunWorkerCompleted event. With that you are disposing form page. Is that what you want to do? Or you want to dispose BackgroundWorker? Disposing form page all resources are released so doing this.Hide(); a second time can be a mistake.
For more info, you can see this links: C# Form.Close vs Form.Dispose and Form.Dispose Method
You must check this link
How to update the GUI from another thread in C#?
Probably have all the possible answers
Hope this Help
You're running a call to the main thread from a thread that can't manipulate UI.
The simplest way is to use anonymous delegate invoke.
Change this:
if (this.Visible == false)
{
this.ShowDialog();
this.Update();
}
For this:
this.Invoke((MethodInvoker) delegate {
if (this.Visible == false)
{
this.ShowDialog();
this.Update();
}
});
It's not the most optimized way but does the job awesomely fast without much recode. :)
I've recently made this small Windows Forms Application:
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 Spammer
{
public partial class Form1 : Form
{
Thread t1;
int delay, y = 1;
public Form1()
{
t1 = new Thread(send);
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
delay = int.Parse(textBox2.Text);
t1.Start();
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
private void button2_Click(object sender, EventArgs e)
{
y = 0;
}
private void send()
{
while (y == 1)
{
String textt = textBox1.Text;
Thread.Sleep(delay);
SendKeys.SendWait(textt);
}
}
private void label1_Click(object sender, EventArgs e)
{
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
}
}
}
Now, it looks like this:
It has a Delay textbox, a Text to Send textbox, and 2 buttons: Start and Stop.
Now, I've tried running it and setting the delay to 1000ms.
When I press the "Stop" button, it perfectly stops and no more messages are sent.
But when I input in the delay very small delays like 100ms, for example, pressing "Stop" doesn't do anything.
It's even kind of hard to click it, and even when I click it doesn't stop sending the messages.
Why is this? And can I solve it somehow?
OK, Thank you, everyone, for helping!
I'm now using the GUI timer and it works flawlessly.
So for some reason when I code this.Close(); into my program it won't actually close it.
I have the program open a different .exe file then close, but I open my task manager and it actually is still running in the background. I have this issue with the "Close" option on my context menu also.
Any ideas why?
EDIT: Even when I exit with the button, it's still in the background.
EDIT:
private void closeToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Close();
}
private void launch_Click(object sender, EventArgs e)
{
System.Diagnostics.Process.Start(Environment.ExpandEnvironmentVariables("%AppData%\\program.exe"));
this.Close();
}
Only actual two codes that are closing the program. But it's still running in the background.
Even when I exit through the actual x button, it still runs in the background.
You must close the process that you've created. Create a variable to save the process that has been created and when you close the form or press another button close process. See: http://msdn.microsoft.com/en-us/library/system.diagnostics.process.close.aspx
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication4
{
public partial class Form1 : Form
{
private Process _process;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
this._process = Process.Start("notepad.exe");
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (this._process != null) {
this._process.CloseMainWindow();
this._process.Close();
}
}
}
}
As menstion in above comment add using System.Diagnostics; to your code and try this code
public Form1()
{
InitializeComponent();
Application.ApplicationExit += new EventHandler(Application_ApplicationExit);
}
void Application_ApplicationExit(object sender, EventArgs e)
{
Process.GetCurrentProcess().Kill();
}
I have two forms. form1 calls starts a background running thread during its loading.
once it stars running. form 2 will popup having two buttons (start&stop).
when i press stop button the thread should pause and when i press start, the pause thread should start it execution from where it stopped.
I tried to use this code.
myResetEvent.WaitOne();// to pause the thread
myResetEvent.Set(); // to resume the thread.
as these events are defined in the form1but I'm wanting it to work from form2.
Finally i got the answer, it worked for my case,posting it, might it will help others..
Form 1 code..
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 thread_example
{
public partial class Form1 : Form
{
private int i = 0;
public Thread Run_thread = null, run1 = null; // thread definition
public static AutoResetEvent myResetEvent = new AutoResetEvent(false);//intially set to false..
public Form1()
{
InitializeComponent();
run1 = new Thread(new ThreadStart(run_tab));
run1.IsBackground = true;
run1.Start();
}
private void run_tab()
{
//do something.
}
private void button1_Click(object sender, EventArgs e)
{
form2 f2 = new form2();
f2.Show();
}
}
}
// Form 2 code...
namespace thread_example
{
public partial class form2 : Form
{
public form2()
{
InitializeComponent();
}
private void btn_stop_Click(object sender, EventArgs e)
{
Form1.myResetEvent.WaitOne();
}
private void button2_Click(object sender, EventArgs e)
{
Form1.myResetEvent.Set();
}
}
}
You can pass the Event instance to the second form as form parameters.
class Form1
{
ManualEvent myResetEvent;
void ShowForm2()
{
var form2 = new Form2(myResetEvent);
form.ShowDialog();
}
}
class Form2
{
ManualEvent myResetEvent;
Form2(ManualEvent event)
{
myResetEvent = event;
}
void StopButtonClick()
{
myResetEvent.Reset();
}
void ContinueButtonClick()
{
myResetEvent.Set();
}
}