G
Guest
Hi all
I stumbled over a new problem:
I have a programm with just a class that is asynchronous listening for
network connections. As soon as someone connected, a new form needs to be
created.
The Form gets created but hangs after creation. I'ts logical that that
happens because the new Form doesn't get a Message Loop.
The Message Loop is created on Application.Run() on the Main Method on the
Main Thread. The Callback is (normally) executed on another Thread so the
Form which is created there doesn't have this Message Loop and therefore
hangs.
Basically I would need to run the creation-code of the new Form on the Main
Thread. But how? I don't have a Form to call Invoke. Well I could make a
dummy form and pass that one to my Callback and invoke it there but that
doesn't seem very clean. I just need to somehow execute some code on the Main
Thread so that the Form is created there and can use the MessageLoop that is
waiting there.
Any Ideas how to solve that in a proper way?
At the end, you'll find a very simple example showing the problem. Form1 is
just needed that I can connect to the Application itself. You could also
comment out the Form1 Stuff and just use "telnet.exe localhost 1234" to
connect to the Application.
After the Connection, the Async-Callback from the class "Test" creates a new
Form with the "Create" Method. And there is where I need help. This "Create"
Method needs to run on the Main Thread so it can use it's Message Loop.
Thanks for help.
//Roman
/************ CODE ************/
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
namespace AsyncTest {
public class Form1 : Form {
private Button myButton;
public Form1() {
// Create Button
myButton = new Button();
myButton.Text = "Connect";
myButton.Click += new System.EventHandler(this.button1_Click);
// Add the Button
this.Controls.Add(myButton);
}
private void button1_Click(object sender, EventArgs e) {
// Just Connect...
TcpClient cl = new TcpClient("localhost", 1234);
// ... and disconnect
cl.Client.Close();
cl.Close();
}
protected override void OnClosed(EventArgs e) {
base.OnClosed(e);
Application.Exit();
}
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// Just needed for a Button to tell when to Connect, Could also
use Telnet
Form f = new Form1();
f.Show();
// Start the "listener"
Test t = new Test();
Application.Run();
}
}
class Test {
TcpListener m_tcpListener;
public Test() {
// Start Listener
m_tcpListener = new TcpListener(IPAddress.Any, 1234);
m_tcpListener.Start();
// Start Accepting
m_tcpListener.BeginAcceptTcpClient(new
AsyncCallback(AcceptTcpClientCallback), this);
}
private static void AcceptTcpClientCallback(IAsyncResult ar) {
Test cl = (Test)ar.AsyncState;
TcpListener listener = cl.m_tcpListener;
TcpClient client = listener.EndAcceptTcpClient(ar);
Console.WriteLine("Connected");
// Start Accepting again
listener.BeginAcceptTcpClient(new
AsyncCallback(AcceptTcpClientCallback), cl);
// This Method needs to run on the "main"-Thread where the
MessageLoop is running
// (which was started with Application.Run() )
cl.Create();
}
private void Create() {
Form bla = new Form();
bla.Show();
}
}
}
/************ END CODE ************/
I stumbled over a new problem:
I have a programm with just a class that is asynchronous listening for
network connections. As soon as someone connected, a new form needs to be
created.
The Form gets created but hangs after creation. I'ts logical that that
happens because the new Form doesn't get a Message Loop.
The Message Loop is created on Application.Run() on the Main Method on the
Main Thread. The Callback is (normally) executed on another Thread so the
Form which is created there doesn't have this Message Loop and therefore
hangs.
Basically I would need to run the creation-code of the new Form on the Main
Thread. But how? I don't have a Form to call Invoke. Well I could make a
dummy form and pass that one to my Callback and invoke it there but that
doesn't seem very clean. I just need to somehow execute some code on the Main
Thread so that the Form is created there and can use the MessageLoop that is
waiting there.
Any Ideas how to solve that in a proper way?
At the end, you'll find a very simple example showing the problem. Form1 is
just needed that I can connect to the Application itself. You could also
comment out the Form1 Stuff and just use "telnet.exe localhost 1234" to
connect to the Application.
After the Connection, the Async-Callback from the class "Test" creates a new
Form with the "Create" Method. And there is where I need help. This "Create"
Method needs to run on the Main Thread so it can use it's Message Loop.
Thanks for help.
//Roman
/************ CODE ************/
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
namespace AsyncTest {
public class Form1 : Form {
private Button myButton;
public Form1() {
// Create Button
myButton = new Button();
myButton.Text = "Connect";
myButton.Click += new System.EventHandler(this.button1_Click);
// Add the Button
this.Controls.Add(myButton);
}
private void button1_Click(object sender, EventArgs e) {
// Just Connect...
TcpClient cl = new TcpClient("localhost", 1234);
// ... and disconnect
cl.Client.Close();
cl.Close();
}
protected override void OnClosed(EventArgs e) {
base.OnClosed(e);
Application.Exit();
}
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// Just needed for a Button to tell when to Connect, Could also
use Telnet
Form f = new Form1();
f.Show();
// Start the "listener"
Test t = new Test();
Application.Run();
}
}
class Test {
TcpListener m_tcpListener;
public Test() {
// Start Listener
m_tcpListener = new TcpListener(IPAddress.Any, 1234);
m_tcpListener.Start();
// Start Accepting
m_tcpListener.BeginAcceptTcpClient(new
AsyncCallback(AcceptTcpClientCallback), this);
}
private static void AcceptTcpClientCallback(IAsyncResult ar) {
Test cl = (Test)ar.AsyncState;
TcpListener listener = cl.m_tcpListener;
TcpClient client = listener.EndAcceptTcpClient(ar);
Console.WriteLine("Connected");
// Start Accepting again
listener.BeginAcceptTcpClient(new
AsyncCallback(AcceptTcpClientCallback), cl);
// This Method needs to run on the "main"-Thread where the
MessageLoop is running
// (which was started with Application.Run() )
cl.Create();
}
private void Create() {
Form bla = new Form();
bla.Show();
}
}
}
/************ END CODE ************/