my form freezes immediately when I run my code. I'm not sure why, but please take a look at the code below and see the screenshot. Basically when I run my code, the form freezes once my code loads, and it just says "not responding" what could it be doing?
namespace MySample
{
public class Driver
{
static void Main(string[] args)
{
log4net.Config.XmlConfigurator.Configure();
Form1 form = new Form1();
form.Show();
try
{
StartModbusSerialRtuSlave();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
public static void StartModbusSerialRtuSlave()
{
using (SerialPort slavePort = new SerialPort("COM1"))
{
// configure serial port
slavePort.BaudRate = 38400;
slavePort.DataBits = 8;
slavePort.Parity = Parity.Odd;
slavePort.StopBits = StopBits.One;
slavePort.Open();
byte unitId = 1;
// create modbus slave
ModbusSlave slave = ModbusSerialSlave.CreateRtu(unitId, slavePort);
slave.DataStore = DataStoreFactory.CreateDefaultDataStore();
slave.Listen();
}
}
}
CODE ON FORM
namespace MySample
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
}
}
The function StartModbusSerialRtuSlave is not returning. The call to Listen likely blocks, which is normally fine, but its on the UI thread.
Because it isn't executing on its own thread (separate from the UI), it causes the application to "lock up" and deliver the error message you see.
Simple fix, don't perform long-running operations on the UI thread. Start things like I/O on their own thread.
For example:
log4net.Config.XmlConfigurator.Configure();
try
{
new Thread((p) => StartModbusSerialRtuSlave()).Start();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
//Start your form the right way!
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
Related
I have a form that is run as a scheduled task. When it is run, nothing shows up, the program executes. I would also like the option of showing the form and manually executing the program with the different options that are available on the main form.
So, using parameters, I am able to run this and it works fine as a scheduled task. As a form, however, I am unable to get the form to show.
Here is my code:
******* MAIN PROGRAM
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
if (args.Length > 0)
{
Application.Run(new FileProcessor(true));
}
else
{
Application.Run(new FileProcessor(false));
}
}
******* INSIDE THE FORM
bool RunOnSchedule = true;
private bool setCore;
public FileProcessor(bool automatic = true)
{
RunOnSchedule = automatic;
if (RunOnSchedule)
{
setCore = true;
SetVisibleCore(false);
}
else
{
SetVisibleCore(true);
}
InitializeComponent();
if (!RunOnSchedule)
{
btnProcess.Visible = false;
}
if (RunOnSchedule)
{
object sender = new object();
EventArgs e = new EventArgs();
FileProcessor_Load(sender, e);
GetDefaultFiles();
BtnProcess_Click(sender, e);
}
}
protected override void SetVisibleCore(bool value)
{
base.SetVisibleCore(setCore ? value : setCore);
}
If it doesn't run as a scheduled task, the form won't show up. I have tried using ShowDialog() instead of .Run() but it still doesn't work.
Any thoughts, ideas or help would be greatly appreciated.
I've been scratching my head on this one for a while now and despite looking for solutions, im not quite understanding the implementations (several answers on stack overflow have already been looked at)
My program loads a splash page when it is opened, during which it checks for a database connection. If there is a connection, the splash page closes and the main form loads, otherwise it provides an error message then closes completely.
public partial class StartupSplash : Form
{
ThreadStart th;
Thread thread;
public StartupSplash()
{
InitializeComponent();
th = new ThreadStart(DbAvaliable);
thread = new Thread(th);
thread.Start();
}
private void DbAvaliable()
{
Boolean result = false;
using (var connectiontest = new SqlConnection("myConnString"))
try
{
connectiontest.Open();
result = true;
}
catch (Exception ex)
{
result = false;
}
if (result)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainWindow());
}
else
{
MessageBox.Show("Unable to establish database connection. Please check your data connection and try again.");
}
}
}
I understand that I can't simply call this.Close() due to cross thread issues. I've read something about invoking methods, but im not too clear how to achieve the result above.
Initially I tried to use form load/shown events instead of alternate threads, but the image on the forms failed to load until after the messagebox had shown the error (rather than displaying, then running the connection check)
Could you set up an event to fire on Form2 with the results of the db check? Subscribe to the event on Form1 and tell it to close if the conditions warrant.
Not sure if it would work or not, but something like:
public Form2 : Form
{
public delegate void DbCheckHandler(object sender, DbEventArgs e);
public event DbCheckHandler DbCheckComplete;
//check the db
DbCheckComplete(this, new DbEventArgs { ShouldClose = true; });
}
public Form1 : Form
{
Form2 form2 = new Form2();
form2.DbCheckComplete += new DbCheckHandler(CheckDbResult);
form2.Show();
private void CheckDbResult(object sender, DbEventArgs e)
{
if(e.ShouldClose)
{
this.Close();
}
}
}
With some help from previous answers posted by Hans Passant (here and here), My solution was as follows:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
new MyApp().Run(args);
}
class MyApp : WindowsFormsApplicationBase
{
protected override void OnCreateSplashScreen()
{
this.SplashScreen = new StartupSplash();
}
protected override void OnCreateMainForm()
{
Boolean result = false;
using (var connectiontest = new SqlConnection("myConnectionString"))
try
{
connectiontest.Open();
result = true;
}
catch (Exception ex)
{
result = false;
}
// pause not needed while checking for db connection as that takes its own amount of time to complete.
if (result)
{
System.Threading.Thread.Sleep(3000); //pause moved here to give the splash some time on screen if db connection available
this.MainForm = new MainWindow();
}
else
{
MessageBox.Show("Unable to connect to the database");
Environment.Exit(1); // shuts down the program if database connection not avaliable.
}
}
}
I have a C# application that acts as a web server to the local machine only.
I have used the example from this site as the base for my web server.
So, here is my problem, the main application spawns a listener thread to listen for and handle the response.
In Program.cs
static class Program
{
[STAThread]
static void Main()
{
Application.Run(new SysTrayApp());
}
}
In SysTrayApp.cs:
public partial class SysTrayApp : Form
{
...
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
WebServer myWebServer = new WebServer(WebServer.Response, "http://localhost:8080/");
myWebServer.Run();
}
}
In WebServer.cs
...
public void Run()
{
ThreadPool.QueueUserWorkItem((o) =>
{
Console.WriteLine("Webserver running...");
try
{
while (_listener.IsListening)
{
var ctx = _listener.GetContext();
try
{
string rstr = _responderMethod(ctx.Request);
byte[] buf = Encoding.UTF8.GetBytes(rstr);
ctx.Response.ContentLength64 = buf.Length;
ctx.Response.OutputStream.Write(buf, 0, buf.Length);
}
catch { } // suppress any exceptions
finally
{
// always close the stream
ctx.Response.OutputStream.Close();
}
}
}
catch { } // suppress any exceptions
});
}
When a request is received, I want to display a Windows Form to the local environment (not the HTTP response). The problem is that I am no longer in the main STAThread when I receive the request, so I can't open a form properly.
If I try open it in the listener thread, the form just freezes because the listener starts listening and blocks the thread. A similar thing happens if I open a threadpool thread.
public static string Response(HttpListenerRequest request)
{
Form form = new Form();
form.Show();
return "TEST!";
}
If I open it in a new normal Thread, the form pops up and then the thread closes and then the form closes again.
public static string Response(HttpListenerRequest request)
{
Thread thread = new Thread(startForm);
thread.Start();
return "TEST!";
}
public static void startForm()
{
Form form = new Form();
form.Show();
}
So, from what I can figure out, only forms in the main application/UI thread seem to work properly and also, you can't block the main thread, or else the forms freeze. So, from within the WebServer listener, how do I trigger the opening of a form on the main thread?
Should I create an event on the main form that launches the second form and try to trigger it from the listener thread?
Or is there a better way to do it?
P.S. I am a PHP/Python programmer that has had to venture into C# just for a single project, so I am not really sure what I am doing.
You can invoke a method of SysTrayApp in the worker thread as below
public class SysTrayApp : Form
{
public SysTrayApp()
{
Task.Factory.StartNew(Process, TaskCreationOptions.LongRunning);
}
void ActualWork(DateTime dt)
{
this.Text = dt.ToString();
}
void Process()
{
while(true)
{
this.Invoke((Action)(() => ActualWork(DateTime.Now)));
Thread.Sleep(1000);
}
}
}
BTW: Don't use threads from threadpool for long running tasks. Why .net Threadpool is used only for short time span tasks?
I'm making an application that is reading the serial port and updating data in a WindowsForms application screen.
Sometimes when you try to close the program is locked.
I'm using delegate.
What should I be doing wrong?
void sp1_LineReceived(object sender, LineReceivedEventArgs Args)
{
Invoke(new Action(() =>
{
// execute code
}));
}
Init
public FormPrincipal()
{
InitializeComponent();
spSistema.LineReceived += new LineReceivedEventHandler(sp1_LineReceived);
// next codes
}
Outher codes
public partial class FormPrincipal : Form
{
SerialPort spSimulador = new SerialPort();
public static PortaSerial spSistema = new PortaSerial();
In general, BeginInvoke is preferable to Invoke, as it won't block. See here. You may well have a deadlock here.
void sp1_LineReceived(object sender, LineReceivedEventArgs Args)
{
BeginInvoke(new Action(() =>
{
// execute code
}));
}
Hi I'm working with winform and trying to use MessageBox for exception handling.
The weird thing here is, the MessageBox appears only after the main form ("Form1" in the code below) is closed.
public class Worker {
/* edited (see below)
public void doWork() {
try {
// do something
client.Connect(serverAddress);
stream = client.GetStream();
}
catch(Exception e) {
MessageBox.Show(e.ToString(),
"This will not show up until Form1 is closed");
}
}
*/
}
public class Form1 {
/* edited (see below)
* public void threadProc() {
* Worker worker = new Worker();
* worker.doWork();
* }
*/
void button_Click(object sender, EventArgs e) {
// create a thread that will end up throwing an exception
Thread thread = new Thread(threadProc);
thread.Start();
}
}
What could be a better way to use MessageBox for exception handling?
...So I added some codes for MessageBox-ing in the UI thread, but the problem remains.
public class WorkExceptionArgs : EventArgs {
public Exception e;
public WorkExceptionArgs (Exception e) { this.e = e; }
}
public partial class Worker1 { // renamed (Worker->Worker1)
/* (edited) Now Worker1 doesn't trigger any event (see below)
public event EventHandler<WorkExceptionArgs> workException;
*/
public void doWork() {
try {
// do something
client.Connect(serverAddress);
stream = client.GetStream();
}
catch(Exception e) {
/* (edited) suppose Worker1 never throws any exception (see below)
* // trigger event that will cause MessageBox-ing by UI thread
* workException(this, new WorkExceptionArgs(e));
*/
}
}
}
public partial class Form1 {
public void threadProc() {
Worker1 worker1 = new Worker();
/* (edited) Now Worker1 never throws any exception
* worker.workException += new EventHandler<WorkException>(worker_WorkException);
*/
worker1.doWork();
// (added) After doWork() is done, Form1 creates Worker2
Worker2 w2 = new Worker2(this, this.form2);
w2.workException += new EventHandlerArgs<WorkExceptionArgs>(form2.worker2_WorkException);
w2.doSomeOtherWork();
}
/* public void worker_WorkException(object sender, WorkExceptionArgs eArg) {
* MessageBox.Show(eArg.e.ToString(), "Still not showing");
* } */
Form2 form2 = new Form2(); // (added) At first form2 is hidden (see below)
}
Actually there have been another form and another worker. Once Worker(Worker1) made connection to the server, Form1 hides (.Hide()), Form2 shows (.Show()), and Worker2 starts working with the connection Worker1 made.
public class Worker2 {
Worker2(Worker1 w1, Form2 frm2) { this.w1=w1; this.frm2=frm2; }
public Worker1 w1;
public Form2 frm2;
public event EventHandler<WorkExceptionArgs> workException;
public void doSomeOtherWork() { // do some other, using data in Worker 1.
try { // This will throw an exception
BinaryFormatter formatter = new BinaryFormatter();
MyObj mo = (MyObj)formatter.Deserialize(w1.getStream());
}
catch(Exception e) {
workException(this, new WorkExceptionArgs(e));
}
}
}
public class Form2 {
public Form2(Form1 frm1) { // to switch from frm1 to frm2
InitializeComponent();
this.frm1 = frm1;
}
public Frm1 frm1 {get;set;}
public void worker2_WorkException(object sender, WorkExceptionArgs ea) {
MessageBox.Show(this, ea.e.ToString(), "SHOWS ONLY IF FORM2 IS CLOSED");
}
}
public partial class Form1 {
delegate void switchWindow_Callback();
public void switchWindow() { this.Hide(); form2.Show(); }
public void switchWindowCb(object sender, EventArgs e) {
if(this.InvokeRequired) {
SwitchWindow_Callback hcb = new SwitchWindow_Callback(switchWindow);
this.Invoke(hcb, new object[] {});
}
else { this.switchWindow(); }
}
}
Actually I'll bet the MessageBox is appearing behind the main form, and you just don't see it until you close it.
You'd be much better off letting the UI thread (the one that created and owns Form1) do the MessageBox-ing. You either want to make events, or otherwise have an error callback delegate in your worker class.
However, BackgroundWorker may be worth checking out here rather than trying to roll your own. Assuming it's a fatal exception, you can save and retrieve the error state, and you get an event automatically called when the thread finishes.
You should really be locking down the doWork method so that multiple threads cant access it at the same time, they need to queue.
Look into "Joining Threads". Imagine if you get two exception at the same time. Your app will fall over. Locking down the area of code that will be duplicated repeatedly will form a queue for your threads to access the area of code that handles the exception.
As lc stated, it's quite likely that your message box is appearing behind the main form, and therefore you only see it when the main form is closed.
The model I use to deal with unhandled exceptions in a Windows Forms app looks like this:
// Switch-off the Windows Forms default handler for unhandled exceptions.
// NB From .NET 4 upwards, this won't work if the process state is corrupted.
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
// Setup event handler to intercept an unhandled exception on a UI thread .
// NB The exception will still terminate the application.
// But you can show a MessageBox in the event handler and log the exception.
Application.ThreadException +=
new ThreadExceptionEventHandler(App_UiThreadException);
// Setup event handler to intercept an unhandled exception on a non-UI thread.
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(App_NonUiThreadException);
// Run the application (open main form etc).
The first line says that you want to catch any unhandled exception and deal with it yourself rather than letting the WinForms infrastructure deal with it. Note that from .NET 4 onwards, this setting won't work for an exception that corrupts process state (for example OutOfMemory).
If you have an unhandled exception on a UI thread, the second line will trigger a procedure you create called *App_UiThreadException*. That's where your MesssageBox code should go.
If you have an unhandled exception on a non-UI thread, the last line will trigger a procedure you create called *App_NonUiThreadException*. That's where your MesssageBox code should go.