Reputation: 225
I trying to write a server program with UI on c#. the server is called from background worker->saparated thread. In the server' i have to update the UI about what cient connected on what prot, and also some other parameters. I understand that i have to use the Invoke and i read about it, but somehow i can't implement it on my code. So here is my code, thanks ahead for any help:
enter code here
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.Net;
using System.Runtime.InteropServices;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Configuration;
using System.Collections;
namespace WindowsFormsApplication1
{
public partial class ServerAppMainDisplay : Form
{
public Int32 local_port = 40000;
public int StopOrSrart = 0;
public string localIP = "?";
public string myHostName = "?";
public string ServerIP = "Server IP: ";
public string DefaultPort = "Listening on default port: ";
public string MachineName = "Machine Name: ";
public static bool ThrdState = false;
public static bool TxtBoxVsblty = false;
public ServerAppMainDisplay()
{
InitializeComponent();
textBox2.Text = DefaultPort;
textBox1.Text = ServerIP;
textBox3.Text = MachineName;
textUpdate.ShowDialogs();
}
private void UpdateText(string text)
{
// Set the textbox text
textBox5.Text = text;
}
private void button1_Click(object sender, EventArgs e)
{
myHostName = Dns.GetHostName().ToString();
localIP = Dns.Resolve(myHostName).AddressList[0].ToString();
textBox1.Text = ServerIP + localIP;
textBox3.Text = MachineName + myHostName;
textBox2.Text = DefaultPort + local_port.ToString();
backgroundWorker1.RunWorkerAsync();
}
private void button2_Click(object sender, EventArgs e)
{
//Data Log txt
}
private void button3_Click(object sender, EventArgs e)
{
//Data Log Excel
}
private void button4_Click(object sender, EventArgs e)
{
DialogResult dialogResult = MessageBox.Show("Are you sure you want to stop server application?",
"Stop server application", MessageBoxButtons.YesNo);
if (dialogResult == DialogResult.Yes)
{
textBox2.Text = DefaultPort;
textBox1.Text = ServerIP;
textBox3.Text = MachineName;
myTCPServer.thread.Abort();
myTCPServer.listener.Stop();
myTCPServer.DefSoc.Dispose();
for (int i = 1; i < 10; i++)
{
if (myTCPServer.Connection[i].portFlag)
{
myTCPServer.Connection[i].slistener.Stop();
myTCPServer.Connection[i].socket.Dispose();
}
}
ThrdState = true;
TxtBoxVsblty = false;
}
if (dialogResult == DialogResult.No) return;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
myTCPServer.myMain();
}
private void button5_Click(object sender, EventArgs e)
{
DialogResult dialogResult = MessageBox.Show("Are you sure you want to exit server window application?",
"Exit server window application", MessageBoxButtons.YesNo);
if (dialogResult == DialogResult.Yes)
{
backgroundWorker1.Dispose();
backgroundWorker1.CancelAsync();
myTCPServer.thread.DisableComObjectEagerCleanup();
myTCPServer.thread.Abort();
this.Close();
Application.Exit();
}
if (dialogResult == DialogResult.No) return;
}
}
public class myTCPServer
{
public static Socket DefSoc;
public static Thread thread = new Thread(new ThreadStart(Service));
public static TcpListener listener;
public struct Connection_s
{
public int port;
public bool portFlag;
public Socket socket;
public TcpListener slistener;
};
public static myTCPServer.Connection_s[] Connection = new myTCPServer.Connection_s[10];
public const int DefaultPort = 40000;
public static void myMain()
{
if (!WindowsFormsApplication1.ServerAppMainDisplay.ThrdState)
myTCPServer.thread.Start();
else
{
myTCPServer.thread = new Thread(new ThreadStart(Service));
myTCPServer.thread.Start();
}
}
public static void Service()
{
for (int i = 1; i < 10; i++)
{
Connection[i].portFlag = false;
Connection[i].port = DefaultPort + i;
}
myTCPServer.listener = new TcpListener(DefaultPort);
myTCPServer.DefSoc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
while (true)
{
byte[] SndBfr;
string str;
myTCPServer.listener.Start();
if (myTCPServer.listener.Pending())
{
DefSoc = myTCPServer.listener.AcceptSocket();
for (int i = 1; i < 10; i++)
{
if (Connection[i].portFlag == false)
{
Thread.Sleep(10);
str = "<" + Connection[i].port as string;
SndBfr = System.Text.Encoding.UTF8.GetBytes(str);
DefSoc.Send(SndBfr);
Thread.Sleep(10);
Connection[i].slistener = new TcpListener(Connection[i].port);
Connection[i].slistener.Start();
Connection[i].socket = Connection[i].slistener.AcceptSocket();
Connection[i].portFlag = true;
yourTextBox.Invoke(new UpdateTextCallback(this.UpdateText),
new object[]{”Text generated on non-UI thread.”});
DefSoc.Disconnect(true);
DefSoc.Dispose();
myTCPServer.listener.Stop();
myTCPServer.listener = new TcpListener(DefaultPort);
myTCPServer.DefSoc = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
break;
}
}
}
Thread.Sleep(10);
for (int i = 1; i < 10; i++)
{
if (Connection[i].portFlag == true)
{
int SndRslt = 0;
str = DateTime.Now.ToString(@"MM\/dd\/yyyy h\:mm tt");
try
{
SndRslt = Connection[i].socket.Send(System.Text.Encoding.UTF8.GetBytes("+" + str));
}
catch (SocketException) { }
if (SndRslt <= 0)
{
try
{
Connection[i].portFlag = false;
Connection[i].socket.Disconnect(true);
Connection[i].slistener.Stop();
}
catch (SocketException) { }
}
}
}
}
}
}
}
Upvotes: 2
Views: 1400
Reputation: 11287
Change your UpdateText(string text)
to this:
private void UpdateText(string text)
{
if(textBox5.InvokeRequired)
{
Action a = () => UpdateText(text);
Invoke(a);
}
else
textBox5.Text = text;
}
This will invoke the textbox if required.
Invoke
From MSDN
The Invoke method searches up the control's parent chain until it finds a control or form that has a window handle if the current control's underlying window handle does not exist yet. If no appropriate handle can be found, the Invoke method will throw an exception. Exceptions that are raised during the call will be propagated back to the caller.
Upvotes: 3
Reputation: 8785
Invoke a delegate to the function that updates the UI and use InvokeRequired in the function to check if the delegate needs to be called.
Example:
Imports System.Management
Private watcher As New ManagementEventWatcher
//delegate to udater UI function
Delegate Sub SetItemCallback(ByVal item As ListViewItem)
Private item1 As ListViewItem
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim query As New WqlEventQuery("Win32_ProcessStartTrace")
watcher.Query = query
AddHandler watcher.EventArrived, AddressOf EventWorker
watcher.Start()
End Sub
'This method start when event arrived. It's invoked from another thead. (not UI thread)
Public Sub EventWorker(ByVal sender As Object, ByVal e As System.Management.EventArrivedEventArgs)
Try
Dim mbo As ManagementBaseObject = e.NewEvent
For Each p As PropertyData In mbo.Properties
item1 = New ListViewItem(p.Name)
If p.Value IsNot Nothing Then : item1.SubItems.Add(p.Value.ToString)
Else : item1.SubItems.Add(String.Empty)
End If
'updates de UI
Me.SetItem(item1)
Next
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
End Sub
'If InvokeRequired (no UI thread) create the delegate and invoke it else update the UI
Private Sub SetItem(ByVal itm As ListViewItem)
If Me.ListView1.InvokeRequired Then
Dim d As New SetItemCallback(AddressOf SetItem)
Me.Invoke(d, New Object() {itm})
Else
ListView1.Items.Add(itm)
End If
End Sub
Private Sub Form1_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
watcher.Stop()
End Sub
Upvotes: 0
Reputation: 453
You should go for "MethodInvoker" for cross-thread [Moreover, to ensure the "Method" executes on GUI thread]
Maybe this could help:
MethodInvoker method = delegate{
yourTextBox.Text = "the text you need";
};
if (InvokeRequired) // You may skip this
BeginInvoke(method);
Upvotes: 0