accessing window elements out of a thread impossible?

G

Guest

Hi,

I encountered a problem wich is a big mystery to me and my colleagues.
So this is the application I wrote:

- A C# Client application for Windows CE .NET CompactFramework which
connects to a server via TcpClient and sends a "Next"-package to tell the
server to send data
- A C# Server application (WinXP SP2) which waits for a "Next" or "Stop"
package (TcpListener) and then generates some numbers to send to the client.
- Basically the whole application is just some kind of proof-of-concept,
it's not a huge thing.
- I use the VS.NET (2003) Windows CE emulator to run the wince client app

This is my problem:
The whole data transfer works very well and quite fast, until I move the
mouse into the WinCE-application window of the WincE Emulator. Then the data
transfer slows down until it totally stops. I have no explanation for that,
because I didn't write any event listeners. How can the program stop when I
move the _MOUSE_ even though I don't have a single line of code that refers
to mouse movement?

I traced down the problem to the following: When I uncomment the line of
code which puts the responseData into a label, the program will not stop. You
can check yourself by commenting / uncommenting the line "label1.Text =
responseData;" in the client application. (You will notice that I even put
this line into a separate thread, because then you will see that the Thread
dies, not the application.)

This is my concluding question:
Is it not possible to access the window elements of the control thread out
of a separate thread?

So here is the code, you can try youself and see if you have the same
problem (just move the mouse in the client window, while the connection is
active):

Client application:

Code:
using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Data;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace AR_Client
{
/// <summary>
/// Zusammenfassung für Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.TextBox tb_Server;
private System.Windows.Forms.TextBox tb_Request;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.Label label1;
private bool running = false;
private System.Windows.Forms.TextBox textBox1;
private String res;
static String responseData = "";

public Form1()
{
//
// Erforderlich für die Windows Form-Designerunterstützung
//
InitializeComponent();
this.res = this.tb_Request.Text;

//
// TODO: Konstruktorcode hinter dem
InitializeComponent-Aufruf hinzufügen
//
}
/// <summary>
/// Verwendete Ressourcen bereinigen.
/// </summary>
protected override void Dispose( bool disposing )
{
base.Dispose( disposing );
}
#region Vom Windows Form-Designer generierter Code
/// <summary>
/// Erforderliche Methode für die Designerunterstützung.
/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert
werden.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.button3 = new System.Windows.Forms.Button();
this.tb_Server = new System.Windows.Forms.TextBox();
this.tb_Request = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.textBox1 = new System.Windows.Forms.TextBox();
//
// button1
//
this.button1.Location = new System.Drawing.Point(8, 8);
this.button1.Size = new System.Drawing.Size(104, 20);
this.button1.Text = "Start";
this.button1.Click += new
System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.Location = new System.Drawing.Point(144, 8);
this.button2.Text = "Stop";
this.button2.Click += new
System.EventHandler(this.button2_Click);
//
// button3
//
this.button3.Location = new System.Drawing.Point(224, 8);
this.button3.Text = "Quit";
this.button3.Click += new
System.EventHandler(this.button3_Click);
//
// tb_Server
//
this.tb_Server.Location = new System.Drawing.Point(8, 32);
this.tb_Server.Text = "172.17.31.34";
//
// tb_Request
//
this.tb_Request.Location = new System.Drawing.Point(8, 56);
this.tb_Request.Text = "Next";
this.tb_Request.TextChanged += new
System.EventHandler(this.tb_Request_TextChanged);
//
// label1
//
this.label1.Location = new System.Drawing.Point(144, 48);
this.label1.Size = new System.Drawing.Size(96, 16);
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(136, 64);
this.textBox1.Text = "";
this.FormBorderStyle =
System.Windows.Forms.FormBorderStyle.FixedToolWindow;
//
// Form1
//
this.ClientSize = new System.Drawing.Size(306, 90);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.label1);
this.Controls.Add(this.tb_Request);
this.Controls.Add(this.tb_Server);
this.Controls.Add(this.button1);
this.Controls.Add(this.button2);
this.Controls.Add(this.button3);
this.MaximizeBox = false;
this.Text = "TCP/IP Client";

}
#endregion

/// <summary>
/// Der Haupteinstiegspunkt für die Anwendung.
/// </summary>

static void Main()
{
Application.Run(new Form1());
}

private void Connect()
{
try
{
if (this.running)
{
// Objekte erstellen, damit nicht der ganze
Speicher vom PDA verschwendet wird
Int32 port = 81;
TcpClient client;
Byte[] data;
NetworkStream stream;
String con = tb_Server.Text;
while (this.running)
{
//                              MessageBox.Show("1");
client = new TcpClient(con, port );

// Die Überprüfung mach ich erst hier drinnen
(könnte ja auch schon beim Stop-Button sein), damit
// der Server noch ein Stop empfängt und
ebenfalls aufhört.
//                              MessageBox.Show("2");
if (res == "Stop")
running = false;

//                              MessageBox.Show("3");
data = new byte[4];
data[0] = 78;
data[1] = 101;
data[2] = 120;
data[3] = 116;

//                              MessageBox.Show("4");
stream = client.GetStream();

stream.Write(data, 0, 4);

//                              MessageBox.Show("6");
data = new Byte[256];
//                              MessageBox.Show("8");
Int32 bytes = stream.Read(data, 0, data.Length);
//                              MessageBox.Show("9");
responseData =
System.Text.Encoding.ASCII.GetString(data, 0, bytes);


//                              MessageBox.Show("10");
//                              this.textBox1.Text = responseData;

// Close everything.
//                              MessageBox.Show("11");
stream.Close();
client.Close();
client = null;
//                              Thread.Sleep(10);
}
}
}
catch (ArgumentNullException e)
{
MessageBox.Show("ArgumentNullException: "+ e.ToString());
}
catch (SocketException e)
{
MessageBox.Show("SocketException: "+ e.ToString());
}
catch (Exception e)
{
MessageBox.Show("Exception: "+e.ToString());
}
}

private void writeRespData()
{
while (running)
{
//                    label1.Text = responseData;
//                    MessageBox.Show(responseData);
Thread.Sleep(10);
}
}

private void button1_Click(object sender, System.EventArgs e)
{
running = true;
tb_Request.Text = "Next";
Thread clientThread = new Thread(new ThreadStart(Connect));
clientThread.Start();
Thread respDataThread = new Thread(new
ThreadStart(writeRespData));
respDataThread.Start();
}

private void button2_Click(object sender, System.EventArgs e)
{
tb_Request.Text = "Stop";
}

private void button3_Click(object sender, System.EventArgs e)
{
this.Close();
}

private void tb_Request_TextChanged(object sender,
System.EventArgs e)
{
this.res = this.tb_Request.Text;
}
}
}

And this is the server application:

Code:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace AR_Server
{
/// <summary>
/// Zusammenfassung für Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.GroupBox groupBox2;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.TextBox tb_IP;
private System.Windows.Forms.TextBox tb_Msg;
private System.Windows.Forms.TextBox tb_Port;
private Thread serverThread;
private static bool running = false;
private System.Windows.Forms.RichTextBox richTextBox1;

/// <summary>
/// Erforderliche Designervariable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Erforderlich für die Windows Form-Designerunterstützung
//
InitializeComponent();

//
// TODO: Fügen Sie den Konstruktorcode nach dem Aufruf von
InitializeComponent hinzu
//
}

/// <summary>
/// Die verwendeten Ressourcen bereinigen.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Vom Windows Form-Designer generierter Code
/// <summary>
/// Erforderliche Methode für die Designerunterstützung.
/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert
werden.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.tb_IP = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.button2 = new System.Windows.Forms.Button();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.tb_Port = new System.Windows.Forms.TextBox();
this.button3 = new System.Windows.Forms.Button();
this.label2 = new System.Windows.Forms.Label();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.tb_Msg = new System.Windows.Forms.TextBox();
this.richTextBox1 = new System.Windows.Forms.RichTextBox();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(248, 24);
this.button1.Name = "button1";
this.button1.TabIndex = 0;
this.button1.Text = "Set";
this.button1.Click += new
System.EventHandler(this.button1_Click);
//
// tb_IP
//
this.tb_IP.Location = new System.Drawing.Point(32, 24);
this.tb_IP.Name = "tb_IP";
this.tb_IP.TabIndex = 1;
this.tb_IP.Text = "172.17.31.34";
//
// label1
//
this.label1.Location = new System.Drawing.Point(8, 24);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(24, 16);
this.label1.TabIndex = 2;
this.label1.Text = "IP:";
//
// button2
//
this.button2.Location = new System.Drawing.Point(192, 16);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(72, 32);
this.button2.TabIndex = 3;
this.button2.Text = "Start Server";
this.button2.Click += new
System.EventHandler(this.button2_Click);
//
// groupBox1
//
this.groupBox1.Controls.Add(this.tb_Port);
this.groupBox1.Controls.Add(this.button3);
this.groupBox1.Controls.Add(this.tb_IP);
this.groupBox1.Controls.Add(this.label1);
this.groupBox1.Controls.Add(this.button2);
this.groupBox1.Controls.Add(this.label2);
this.groupBox1.Location = new System.Drawing.Point(8, 8);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(328, 56);
this.groupBox1.TabIndex = 4;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Admin";
//
// tb_Port
//
this.tb_Port.Location = new System.Drawing.Point(140, 24);
this.tb_Port.Name = "tb_Port";
this.tb_Port.Size = new System.Drawing.Size(40, 20);
this.tb_Port.TabIndex = 5;
this.tb_Port.Text = "81";
//
// button3
//
this.button3.Location = new System.Drawing.Point(272, 16);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(48, 32);
this.button3.TabIndex = 4;
this.button3.Text = "Quit";
this.button3.Click += new
System.EventHandler(this.button3_Click);
//
// label2
//
this.label2.Font = new System.Drawing.Font("Microsoft Sans
Serif", 15.75F, System.Drawing.FontStyle.Bold,
System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
this.label2.Location = new System.Drawing.Point(130, 18);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(8, 24);
this.label2.TabIndex = 2;
this.label2.Text = ":";
//
// groupBox2
//
this.groupBox2.Controls.Add(this.tb_Msg);
this.groupBox2.Controls.Add(this.button1);
this.groupBox2.Location = new System.Drawing.Point(8, 72);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(328, 56);
this.groupBox2.TabIndex = 5;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Application";
//
// tb_Msg
//
this.tb_Msg.Location = new System.Drawing.Point(16, 24);
this.tb_Msg.Name = "tb_Msg";
this.tb_Msg.Size = new System.Drawing.Size(224, 20);
this.tb_Msg.TabIndex = 1;
this.tb_Msg.Text = "Test";
//
// richTextBox1
//
this.richTextBox1.Location = new System.Drawing.Point(8, 144);
this.richTextBox1.Name = "richTextBox1";
this.richTextBox1.ScrollBars =
System.Windows.Forms.RichTextBoxScrollBars.ForcedBoth;
this.richTextBox1.Size = new System.Drawing.Size(328, 96);
this.richTextBox1.TabIndex = 6;
this.richTextBox1.Text = "";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(344, 285);
this.Controls.Add(this.richTextBox1);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1);
this.Name = "Form1";
this.Text = "AR Server";
this.groupBox1.ResumeLayout(false);
this.groupBox2.ResumeLayout(false);
this.ResumeLayout(false);

}
#endregion

private void button3_Click(object sender, System.EventArgs e)
{
if (running)  // dem Thread bescheid sagen, daß er aufhören
soll
running = false;

Application.Exit();
}

private void StartServer()
{
long count = 0;
try
{
Int32 port = Convert.ToInt32(tb_Port.Text);
IPAddress localAddr = IPAddress.Parse(tb_IP.Text);

TcpListener server = new TcpListener(localAddr, port);

// Start listening for client requests.
server.Start();

// Buffer for reading data
Byte[] bytes = new Byte[256];

// Enter the listening loop.
while(running)
if (server.Pending())
{
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket()
here.
TcpClient client = server.AcceptTcpClient();


String data = null;

// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();

int i;

// Loop to receive all the data sent by the
client.
while(((i = stream.Read(bytes, 0,
bytes.Length))!=0) && (running))
{
// Translate data bytes to a ASCII string.
data =
System.Text.Encoding.ASCII.GetString(bytes, 0, i);

// Process the data sent by the client.

string response = String.Empty;
// schickt Default-Meldung, daß er dieses Datenpaket nicht zuordnen
kann

switch (data)
{
default:
response = "Unknown";
break;
case "Next":
response = tb_Msg.Text;
// schickt das, was in der TextBox steht
break;
case "Stop":
response = "Stop";
running = false;
break;
}

byte[] msg = new byte[response.Length];
for (int i2 = 0; i2<response.Length; i2++)
msg[i2] =
Convert.ToByte(response[i2]);

// Send back a response.
stream.Write(msg, 0, msg.Length);
count++;
if (richTextBox1.Lines.Length > 1000)
richTextBox1.Text =
count.ToString()+": rcv "+data+" resp "+response+" \n";
else
richTextBox1.Text =
count.ToString()+": rcv "+data+" resp "+response+" \n"+richTextBox1.Text;

// Zufallsdaten fürs Netzwerk erfinden
Random test = new
Random(Environment.TickCount); // dieses Environment.TickCount dient nur der
Initialisierung
int teiler = test.Next(100,2000);
tb_Msg.Text = teiler.ToString();
//                                   Thread.Sleep(10); // Das hier ist nur
da, um die Prozessorlast zu senken, damit der nicht die ganze Zeit die
Schleife mit voller Power durchläuft.
}

// Shutdown and end connection
stream.Close();
client.Close();
}
server.Stop();
}
catch(SocketException e)
{
MessageBox.Show("SocketException: "+e.ToString());
}
catch(Exception e)
{
MessageBox.Show("Exception: "+e.ToString());
}
}


private void button2_Click(object sender, System.EventArgs e)
{
if (button2.Text=="Start Server")
{
running = true;
serverThread = new Thread(new ThreadStart(StartServer));
serverThread.Start();
button2.Text = "Stop Server";
}
else
{
running = false;
//                    if (serverThread.IsAlive)
//                         serverThread.Abort(0);
button2.Text = "Start Server";
}

}

private void button1_Click(object sender, System.EventArgs e)
{

}
}
}

Can anybody help me please? ... otherwise I become desperate ... :)
Thank you in advance!

BTW: Sorry for the German comments - I'm German. But I guess the code is
quite obvious.
 
G

Guest

Thanks, I tried it the following way, using the link you provided:

private Queue mDataQue = new Queue();
private EventHandler mUpdateDel = new EventHandler(UpdateBox);

private void OnNonGuiThread(Object o)
{
lock(mDataQue.SyncRoot)
{
mDataQue.Enqueue(o);
}
this.Invoke(mUpdateDel);
}

private void UpdateBox(object sender, EventArgs e)
{
object o;
lock(mDataQue.SyncRoot)
{
if (mDataQue.Count > 0)
{
o = mDataQue.Dequeue();
}
}
}

I get the error "A field initializer cannot reference the nonstatic field,
method, or property 'field' ". While I do understand what the error means I
don't see how it makes sense in that context ...
 
G

Guest

After I made the UpdateBox static ("private static void UpdateBox(..)") the
error is gone. But now - what else could it be? - I get another error:

lock(mDataQue.SyncRoot)
{
if (mDataQue.Count > 0)
{
o = mDataQue.Dequeue();
}
}

The lock statement wants to have a class as argument, like
(Thread.CurrentThread)

.... I'm lost.
 
G

Guest

The problem is solved, this is my solution and it works perfectly.
Thanks again for the hint! :)

private EventHandler mUpdateDel = new EventHandler(UpdateBox);

private static void UpdateBox(object sender, System.EventArgs e)
{
lock(responseData)
{
label1.Text = responseData;
}
}

private void writeRespData()
{
while (running)
{
label1.Invoke(mUpdateDel);
}
}
 
D

Daniel Moth

You shouldn't have to do that. Can you post the class you are trying this
in? Also show us the sub main... It sounds like you are using a static class
somewhere and its demand propagate to other members you declare...

Cheers
Daniel
 
D

Daniel Moth

Glad you got it solved but I am still missing why you had to make the method
static. It also seems you got rid of the queue which is bad move as you
could lose data (responseData can get its value overwritten). Also if you
set responseData to null from somewhere else the lock statement will throw.

If you post a complete repro sample I can look at it for you... otherwise,
keep using your working solution until it breaks...

Cheers
Daniel
 
G

Guest

Ok,
so here's what it's looking like at the moment:
(this works - but funny enough it only works until I receive package number
#469 or #470 - then suddenly the app slowes down and stopps to get a
connection to the server ... and then the emulator crashes sometimes ...)

<code>
using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Data;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace AR_Client
{
/// <summary>
/// Zusammenfassung für Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.TextBox tb_Server;
private System.Windows.Forms.TextBox tb_Request;
private System.Windows.Forms.Button button3;
private static System.Windows.Forms.Label label1;
private bool running = false;
private String res;
static String responseData = "";

public Form1()
{
//
// Erforderlich für die Windows Form-Designerunterstützung
//
InitializeComponent();
this.res = this.tb_Request.Text;

//
// TODO: Konstruktorcode hinter dem InitializeComponent-Aufruf hinzufügen
//
}
/// <summary>
/// Verwendete Ressourcen bereinigen.
/// </summary>
protected override void Dispose( bool disposing )
{
base.Dispose( disposing );
}
#region Vom Windows Form-Designer generierter Code
/// <summary>
/// Erforderliche Methode für die Designerunterstützung.
/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.button3 = new System.Windows.Forms.Button();
this.tb_Server = new System.Windows.Forms.TextBox();
this.tb_Request = new System.Windows.Forms.TextBox();
label1 = new System.Windows.Forms.Label();
//
// button1
//
this.button1.Location = new System.Drawing.Point(8, 8);
this.button1.Size = new System.Drawing.Size(104, 20);
this.button1.Text = "Start";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.Location = new System.Drawing.Point(144, 8);
this.button2.Text = "Stop";
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// button3
//
this.button3.Location = new System.Drawing.Point(224, 8);
this.button3.Text = "Quit";
this.button3.Click += new System.EventHandler(this.button3_Click);
//
// tb_Server
//
this.tb_Server.Location = new System.Drawing.Point(8, 32);
this.tb_Server.Text = "172.17.31.34";
//
// tb_Request
//
this.tb_Request.Location = new System.Drawing.Point(8, 56);
this.tb_Request.Text = "Next";
this.tb_Request.TextChanged += new
System.EventHandler(this.tb_Request_TextChanged);
//
// label1
//
label1.Location = new System.Drawing.Point(152, 48);
label1.Size = new System.Drawing.Size(96, 16);
label1.Text = "no data received";
this.FormBorderStyle =
System.Windows.Forms.FormBorderStyle.FixedToolWindow;
//
// Form1
//
this.ClientSize = new System.Drawing.Size(306, 90);
this.Controls.Add(label1);
this.Controls.Add(this.tb_Request);
this.Controls.Add(this.tb_Server);
this.Controls.Add(this.button1);
this.Controls.Add(this.button2);
this.Controls.Add(this.button3);
this.MaximizeBox = false;
this.Text = "TCP/IP Client";

}
#endregion

/// <summary>
/// Der Haupteinstiegspunkt für die Anwendung.
/// </summary>

static void Main()
{
Application.Run(new Form1());
}

private void Connect()
{
try
{
if (this.running)
{
// Create objects only once (not within the while-loop) to save memory
on the PDA
Int32 port = 81;
TcpClient client;
Byte[] data;
NetworkStream stream;
String con = String.Copy(tb_Server.Text);
int count = 0;
while (this.running)
{
count++;
// connect
client = new TcpClient(con, port );

// I do the check in the while loop, because I want to make the server
stop as well. (it could also be outside of the while loop, at the
button2_Click function, but then the server wouldn't stop)
if (res == "Stop")
running = false;

// prepare data to be sended. we will send a byte-stream
data = new byte[4];
for (int i = 0; i < data.Length; i++)
{
data = Convert.ToByte(this.res);
}

// get the stream-object from the connection/client-object
stream = client.GetStream();
//write the data into the stream
stream.Write(data, 0, data.Length);

// prepare bytearray to receive information
data = new Byte[4]; // we don't know how big the receiving stream will
be but I assume not bigger than 256 elements
// read data from the stream. this is the response the server has sent
to us.
Int32 bytes = stream.Read(data, 0, data.Length);
// convert the received bytearray-data to string
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);

// Tell label1 that it will be updated from another thread
label1.Invoke(mUpdateDel);

// Close everything.
stream.Close();
client.Close();
client = null; // to make sure
}
}
}
catch (ArgumentNullException e)
{
MessageBox.Show("ArgumentNullException: "+ e.ToString());
}
catch (SocketException e)
{
MessageBox.Show("SocketException: "+ e.ToString());
}
catch (Exception e)
{
MessageBox.Show("Exception: "+e.ToString());
}
}

/*
* now this is wicked code:
*/

private EventHandler mUpdateDel = new EventHandler(UpdateBox); //
Delegate for the Update function of the label1.Text field

private static void UpdateBox(object sender, System.EventArgs e)
{
lock(responseData) // lock the variable "responseData". Important!
Otherwise it will not work.
{
label1.Text = responseData; // finally update the label1.text value
}
}

/*
* End of wicked code ;)
*/

private void button1_Click(object sender, System.EventArgs e)
{
running = true;
tb_Request.Text = "Next";
Thread clientThread = new Thread(new ThreadStart(Connect));
clientThread.Start();
}

private void button2_Click(object sender, System.EventArgs e)
{
tb_Request.Text = "Stop";
}

private void button3_Click(object sender, System.EventArgs e)
{
this.Close();
}

private void tb_Request_TextChanged(object sender, System.EventArgs e)
{
// if text is changed, put new text into res-object (res is the string
that will be sent to the server)
this.res = this.tb_Request.Text;
}
}
}
</code>
 
D

Daniel Moth

I have not run your code but my suggestion still is what it was before:
1) Remove all the static declarations you have (e.g. responseData, label1
etc) unless there is a specific reason you need them in your design.
2) Don't lock on the string, lock on a dedicated object for this job.

Cheers
Daniel
--
http://www.danielmoth.com/Blog/

Iotha said:
Ok,
so here's what it's looking like at the moment:
(this works - but funny enough it only works until I receive package
number
#469 or #470 - then suddenly the app slowes down and stopps to get a
connection to the server ... and then the emulator crashes sometimes ...)

<code>
using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Data;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace AR_Client
{
/// <summary>
/// Zusammenfassung für Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.TextBox tb_Server;
private System.Windows.Forms.TextBox tb_Request;
private System.Windows.Forms.Button button3;
private static System.Windows.Forms.Label label1;
private bool running = false;
private String res;
static String responseData = "";

public Form1()
{
//
// Erforderlich für die Windows Form-Designerunterstützung
//
InitializeComponent();
this.res = this.tb_Request.Text;

//
// TODO: Konstruktorcode hinter dem InitializeComponent-Aufruf hinzufügen
//
}
/// <summary>
/// Verwendete Ressourcen bereinigen.
/// </summary>
protected override void Dispose( bool disposing )
{
base.Dispose( disposing );
}
#region Vom Windows Form-Designer generierter Code
/// <summary>
/// Erforderliche Methode für die Designerunterstützung.
/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.button3 = new System.Windows.Forms.Button();
this.tb_Server = new System.Windows.Forms.TextBox();
this.tb_Request = new System.Windows.Forms.TextBox();
label1 = new System.Windows.Forms.Label();
//
// button1
//
this.button1.Location = new System.Drawing.Point(8, 8);
this.button1.Size = new System.Drawing.Size(104, 20);
this.button1.Text = "Start";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.Location = new System.Drawing.Point(144, 8);
this.button2.Text = "Stop";
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// button3
//
this.button3.Location = new System.Drawing.Point(224, 8);
this.button3.Text = "Quit";
this.button3.Click += new System.EventHandler(this.button3_Click);
//
// tb_Server
//
this.tb_Server.Location = new System.Drawing.Point(8, 32);
this.tb_Server.Text = "172.17.31.34";
//
// tb_Request
//
this.tb_Request.Location = new System.Drawing.Point(8, 56);
this.tb_Request.Text = "Next";
this.tb_Request.TextChanged += new
System.EventHandler(this.tb_Request_TextChanged);
//
// label1
//
label1.Location = new System.Drawing.Point(152, 48);
label1.Size = new System.Drawing.Size(96, 16);
label1.Text = "no data received";
this.FormBorderStyle =
System.Windows.Forms.FormBorderStyle.FixedToolWindow;
//
// Form1
//
this.ClientSize = new System.Drawing.Size(306, 90);
this.Controls.Add(label1);
this.Controls.Add(this.tb_Request);
this.Controls.Add(this.tb_Server);
this.Controls.Add(this.button1);
this.Controls.Add(this.button2);
this.Controls.Add(this.button3);
this.MaximizeBox = false;
this.Text = "TCP/IP Client";

}
#endregion

/// <summary>
/// Der Haupteinstiegspunkt für die Anwendung.
/// </summary>

static void Main()
{
Application.Run(new Form1());
}

private void Connect()
{
try
{
if (this.running)
{
// Create objects only once (not within the while-loop) to save memory
on the PDA
Int32 port = 81;
TcpClient client;
Byte[] data;
NetworkStream stream;
String con = String.Copy(tb_Server.Text);
int count = 0;
while (this.running)
{
count++;
// connect
client = new TcpClient(con, port );

// I do the check in the while loop, because I want to make the server
stop as well. (it could also be outside of the while loop, at the
button2_Click function, but then the server wouldn't stop)
if (res == "Stop")
running = false;

// prepare data to be sended. we will send a byte-stream
data = new byte[4];
for (int i = 0; i < data.Length; i++)
{
data = Convert.ToByte(this.res);
}

// get the stream-object from the connection/client-object
stream = client.GetStream();
//write the data into the stream
stream.Write(data, 0, data.Length);

// prepare bytearray to receive information
data = new Byte[4]; // we don't know how big the receiving stream will
be but I assume not bigger than 256 elements
// read data from the stream. this is the response the server has sent
to us.
Int32 bytes = stream.Read(data, 0, data.Length);
// convert the received bytearray-data to string
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);

// Tell label1 that it will be updated from another thread
label1.Invoke(mUpdateDel);

// Close everything.
stream.Close();
client.Close();
client = null; // to make sure
}
}
}
catch (ArgumentNullException e)
{
MessageBox.Show("ArgumentNullException: "+ e.ToString());
}
catch (SocketException e)
{
MessageBox.Show("SocketException: "+ e.ToString());
}
catch (Exception e)
{
MessageBox.Show("Exception: "+e.ToString());
}
}

/*
* now this is wicked code:
*/

private EventHandler mUpdateDel = new EventHandler(UpdateBox); //
Delegate for the Update function of the label1.Text field

private static void UpdateBox(object sender, System.EventArgs e)
{
lock(responseData) // lock the variable "responseData". Important!
Otherwise it will not work.
{
label1.Text = responseData; // finally update the label1.text value
}
}

/*
* End of wicked code ;)
*/

private void button1_Click(object sender, System.EventArgs e)
{
running = true;
tb_Request.Text = "Next";
Thread clientThread = new Thread(new ThreadStart(Connect));
clientThread.Start();
}

private void button2_Click(object sender, System.EventArgs e)
{
tb_Request.Text = "Stop";
}

private void button3_Click(object sender, System.EventArgs e)
{
this.Close();
}

private void tb_Request_TextChanged(object sender, System.EventArgs e)
{
// if text is changed, put new text into res-object (res is the string
that will be sent to the server)
this.res = this.tb_Request.Text;
}
}
}
</code>
 
G

Guest

Ok, I removed all statics and also made the UpdateBox non-static.
I lock on "this", because I wouldn't know any other object that I could
lock. Does "lock(this)" make sense?

That's in short what I am doing now:




private EventHandler mUpdateDel = new EventHandler(UpdateBox); //
Delegate for the Update function of the label1.Text field

private void UpdateBox(object sender, System.EventArgs e)
{
lock(this) // lock the variable "responseData". Important! Otherwise it
will not work.
{
this.label1.Text = this.responseData; // finally update the label1.text
value
}
}

P.S.: Sorry for my late responses .. I somehow don't get notified about new
replies ..
 
D

Daniel Moth

I don't see a question in there so I guess it is all working fine and you
are just reporting back...cool.

For locking, what you are doing will work fine but it is good practise to
lock on an object dedicated to that purpose i.e. create an instance level
object (object o = new object()) and lock on it (lock(o))

Cheers
Daniel
 
G

Guest

Oh actually I forgot to post my main question .. lol
But at first: thanks for the object-hint.

So here comes the problem:
When I create the delegate in the line
private EventHandler mUpdateDel = new EventHandler(UpdateBox);
it tells me:
"
Compiler Error CS0236
A field initializer cannot reference the nonstatic field, method, or
property 'field'
"

This is the reason why I started to make things static ...
 
D

Daniel Moth

Split the declaration from the assignment.e.g.

private EventHandler mUpdateDel;

<constructor>
{
mUpdateDel = new EventHandler(UpdateBox);
}

Cheers
Daniel
--
http://www.danielmoth.com/Blog/

Iotha said:
Oh actually I forgot to post my main question .. lol
But at first: thanks for the object-hint.

So here comes the problem:
When I create the delegate in the line
private EventHandler mUpdateDel = new EventHandler(UpdateBox);
it tells me:
"
Compiler Error CS0236
A field initializer cannot reference the nonstatic field, method, or
property 'field'
"

This is the reason why I started to make things static ...
 
G

Guest

Thank you, this works.
Can you please explain why this happened? As you can see C# is not my
mothertongue :)

Again, thank you.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top