How to get access to form's controls from class C# - c#

I've got problem when I am trying to get access to form's controls from another class. My program is hanging in infinite loop. I know why, but I don't know how to write this correctly.
Here is Form1.cs (to my Form)
public Form1()
{
InitializeComponent();
Load config = new Load();
string[] data = config.readConfig("config.ini");
if (data.Length == 4) { //client
Client run = new Client();
run.startClient(data[1], Convert.ToInt32(data[2]));
}
else if (data.Length == 3) //server
{
Server run = new Server();
run.startServer(Convert.ToInt32(data[1]));
}
}
public void addLog(string dataLog){
richTextBox1.Text += dataLog;
}
and here is Client.cs file:
class Client
{
public void startClient(string ipAddr, int port)
{
Form1 form1 = new Form1();
TcpClient client = new TcpClient();
try
{
form1.addLog("Connecting...");
client.Connect(ipAddr, port);
form1.addLog("Connected to server: " + ipAddr + ":" + port.ToString());
}
catch
{
MessageBox.Show("We couldn't connect to server");
}
}
}
How can I change text value without running each time new form. Maybe There is something like run_once?

The infinite loop is here:
Form1:
//Always runs if the config file is a certain length
Client run = new Client();
Client:
Form1 form1 = new Form1();
Each constructor creates the other object, which in turn creates the first object, ad infintum.
If you need to get the form object to the client don't create a new one!. It doesn't work anyways, as your new form object knows nothing about the old one. Just pass it in:
public Client(Form1 form)
{
//Do whatever with it
}
//Form class
Client c = new Client(this);
Disclaimer: There are usually far better ways to do this, but you'll learn those as you get more familiar with design patterns/architecture.

Related

Start SCS server from another class (WinForms)

I'm trying to implement a SCS framework server with WinForms in C# but I am having issues making it work. The server standalone works fine when using it in the Main method (no WinForms). I have a client-sided and a server-sided sample code from the SCS framework that I'm trying to implement in WinForms together with some of my own code. It all went well until I decided to try and use WinForms aswell (I had to move the server code to a class of it's own).
I am not getting any errors when I am starting the server, however I can't connect with the client anymore (worked before I moved the server to a class of its own). Client gets System.Net.Sockets.SocketException. On the server-side, I get the error System.InvalidOperationException when the client is trying to connect.
This is my Form1.cs:
using System;
using System.Windows.Forms;
namespace Server_Test
{
public partial class Form1 : Form
{
public static Form1 Self;
Server server = new Server();
public Form1()
{
InitializeComponent();
Self = this;
}
public void rtb1Text(string text)
{
richTextBox1.AppendText(text);
}
public void rtb2Text(string text)
{
richTextBox2.Text = text;
}
private void button1_Click(object sender, EventArgs e)
{
if (button1.Text.EndsWith("Start"))
{
button1.Text = "Stop";
server.ServerInit();
}
else if (button1.Text.EndsWith("Stop"))
{
button1.Text = "Start";
// Does nothing atm
}
}
}
}
And this is my Server.cs
using System;
using Hik.Communication.Scs.Communication.EndPoints.Tcp;
using Hik.Communication.Scs.Communication.Messages;
using Hik.Communication.Scs.Server;
namespace Server_Test
{
class Server
{
public void ServerInit()
{
// Create a server that listens 10085 TCP port for incoming connections
var server = ScsServerFactory.CreateServer(new ScsTcpEndPoint(10085));
// Register events of the server to be informed about clients
server.ClientConnected += Server_ClientConnected;
server.ClientDisconnected += Server_ClientDisconnected;
// Start the server
server.Start();
// Form1.Self.rtb1Text("Server has been started successfully.\n");
Console.WriteLine("Server has been started successfully.\n");
}
static void Server_ClientConnected(object sender, ServerClientEventArgs e)
{
Form1.Self.rtb1Text("A new client with ID: " + e.Client.ClientId + " has connected.\n");
// Register to MessageReceived event to receive messages from new client
e.Client.MessageReceived += Client_MessageReceived;
}
static void Server_ClientDisconnected(object sender, ServerClientEventArgs e)
{
Form1.Self.rtb1Text("A client is disconnected! Client Id = " + e.Client.ClientId + "\n");
}
static async void Client_MessageReceived(object sender, MessageEventArgs e)
{
var message = e.Message as ScsTextMessage; // Server only accepts text messages
if (message == null)
{
return;
}
//Get a reference to the client
var client = (IScsServerClient)sender;
Form1.Self.rtb1Text("Client (ID:" + client.ClientId + ") sent a request: " + message.Text + "\n");
switch (message.Text)
{
case "api":
HttpPost httpPost = new HttpPost();
var apiResponse = await httpPost.SendPost("robot_info");
//Send reply message to the client
client.SendMessage(
new ScsTextMessage(
apiResponse,
message.MessageId //Set first message's id as replied message id
));
break;
default:
break;
}
}
}
}
My guess is that I'm doing something wrong when creating a new instance of the Server class and how I'm initializing/starting the server. Might be something else though, I've tried debugging but it didn't make me any smarter.
Any ideas?

How To Pass Tcpclient Between 2 Forms C#

This Is the first form:
public partial class MainWindow : Window
{
TcpClient client = null;
public MainWindow()
{
InitializeComponent();
}
private void Connect()
{
client = new TcpClient();
client.Connect("127.0.0.1", 8826);
CreateRoomWindow menuWindow = new CreateRoomWindow(client);
menuWindow.Show();
this.Close();
}
}
This is the second form:
public partial class CreateRoomWindow : Window
{
TcpClient client;
const int createRoomMessage = 206;
public CreateRoomWindow(TcpClient loggedClient)
{
InitializeComponent();
client = loggedClient;
}
}
I tried to pass the TcpClient to the another window
But when I click on the createTheRoom Button its happen:
private void CreateTheRoom_Click(object sender, RoutedEventArgs e)
{
string message = "2060068{\"answerTimeout\":2,\"maxUsers\":22,\"questionCount\":2,\"roomName\":\"Name\"}";
int timedSize = message.Length;
string size = timedSize.ToString().PadLeft(4, '0');
message = Convert.ToString(createRoomMessage) + size + message;
Byte[] data = Encoding.ASCII.GetBytes(message);
NetworkStream stream = client.GetStream();
}
The program down with the exception System.InvalidOperationException
in the last line
So my question is How can I pass the TcpClient To make it work
The problem
Show displays the form and returns control to the caller, so in this code, Close() gets called almost immediately:
CreateRoomWindow menuWindow = new CreateRoomWindow(client);
menuWindow.Show();
this.Close(); //Executes immediately
This is a problem, because there is only one instance you're working with, and if you close it in one place, it's closed to everyone.
Solution #1. Make the child form modal.
You can delay the call until after the form is closed by using ShowDialog instead:
CreateRoomWindow menuWindow = new CreateRoomWindow(client);
menuWindow.ShowDialog();
this.Close(); //Executes after form is closed
Solution #2. Close it when the child form is closed.
Another option is to close it in the "FormClosed" handler for the child form:
CreateRoomWindow menuWindow = new CreateRoomWindow(client);
menuWindow.ShowDialog();
//Doesn't call close any more
public partial class CreateRoomWindow : Window
{
TcpClient client;
const int createRoomMessage = 206;
public CreateRoomWindow(TcpClient loggedClient)
{
InitializeComponent();
client = loggedClient;
}
private void Form1_FormClosed(Object sender, FormClosedEventArgs e)
{
client.Close(); //Closes after we're done with the form
}
}
Note: You must register the Form1_FormClosed handler, which you would typically do by double-clicking the event in the property sheet it in the form designer window in Visual Studio.

C# handler not creating and failing when using .CreateHandler()

I'm creating a game in which I use TCP/IP connection. The problem is that I'm using .Invoke to help me receive and send message.
The program goes like this: I'm my first window, i'm starting and connecting to the server like this :
{
TcpListener listener = new TcpListener(IPAddress.Any, this.port);
listener.Start();
try {
this.client = listener.AcceptTcpClient();
gameWindow = new GameWindow(this.client, true);
gameWindow.StartGame();
}
}
then i'm connecting to it like this:
{
IPEndPoint ipEnd = new IPEndPoint(this.serverIP, this.port);
{
try {
client.Connect(ipEnd);
if (client.Connected) {
gameWindow = new GameWindow(this.client, false);
gameWindow.StartGame();
}
}
}
The constructor for gameWindow (which is a form) looks like this:
public GameWindow(TcpClient thisClient, bool isServer)
{
InitializeComponent();
this.client = thisClient;
this.reader = new StreamReader(thisClient.GetStream());
this.writer = new StreamWriter(thisClient.GetStream());
this.writer.AutoFlush = true;
}
I must wait for the server to send a message to the client, and then start the client ( I have a function .startGame() that uses .ShowDialog() and creates some pictureBoxs)
But nowhere I can get my handle created. I've tried to put this.createHandle() (read about it here) into GameWindow_Load but still not works. If I try to send a message with:
workerSendData.RunWorkerAsync(); I get:
Additional information: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
What can I do to get my handler created? Using Thread.Sleep will sleep my whole UI, which does not work (a "solution" found on the internet)
My code for sending message :
private void workerSendData_DoWork(object sender, DoWorkEventArgs e)
{
if (client.Connected) {
this.writer.WriteLine(this.toSend); // aici trimitem datele.
// de modificat : aici vom adauga in lista noastra miscarile.
this.Invoke(new MethodInvoker(delegate () { MessageBox.Show("Me:" + this.toSend + "\n"); }));
}
else {
MessageBox.Show("Send failed");
}
workerSendData.CancelAsync();
}
My code for receiving data:
private void workerReceiveData_DoWork(object sender, DoWorkEventArgs e)
{
while (client.Connected) {
try {
this.received = this.reader.ReadLine();
this.myTurn = true;
this.Invoke(new MethodInvoker(delegate () {
MessageBox.Show("This has been received: " + this.received);
/*this.tbReceive.AppendText("You:" + this.received + "\n");*/
}));
this.received = "";
}
catch (Exception x) {
MessageBox.Show(x.Message.ToString());
}
}
}
It seems that you cannot invoke an action before the Window is fully initialized and loaded. Assuming you are working in Windows Forms, there is a solution provided by #Greg D on this question, but it doesn't be to be the safest way to go.
I would suggest that you try to find a way to start the worker only after the window is loaded (for example using the Loaded event), so that the handle is definitely ready and this situation does not occur.

SuperWebSocket server can receive only one message

I followed an example at SuperWebSocket discussions to create a tiny web socket server with echo functionality. However, my server can receive and send back only one message, when I try to send second message to it, the connection closes. I use this echo page to test my server.
Here is my code (I use WPF without MVVM here):
public partial class MainWindow : Window
{
private WebSocketServer ws;
public MainWindow()
{
InitializeComponent();
}
private void ConnectButton_Click(object sender, RoutedEventArgs e)
{
var r = new RootConfig();
var s = new ServerConfig();
s.Name = "SuperWebSocket";
s.Ip = "Any";
s.Port = 8089;
s.Mode = SocketMode.Tcp;
var f = new SocketServerFactory();
if (ws != null)
{
ws.Stop();
ws = null;
}
ws = new WebSocketServer();
ws.Setup(r, s, f);
ws.NewMessageReceived += ws_NewMessageReceived;
ws.Start();
}
private void ws_NewMessageReceived(WebSocketSession session, string e)
{
session.Send("Message: " + e);
}
}
I can send messages from the server without problems, but can't receive more than one message without closing the connection. What is the reason of this problem and how do I fix it?
Try replacing:
ws.NewMessageReceived += ws_NewMessageReceived;
with:
ws.NewMessageReceived += new SuperWebSocket.SessionEventHandler<SuperWebSocket.WebSocketSession, string>(ws_NewMessageReceived);

C# Sockets: Automatically receiving messages

I am rather new to C# and Sockets however I am trying my hand at making a kind of "chat" program. What I am having an issue with at the moment is making the client able to automatically receive a message from the server if one is available.
What I have tried so far:
System.Threading.Thread myThread = new System.Threading.Thread(new
System.Threading.ThreadStart(listenThread));
public static void listenThread()
{
while(true){
Form1 form1 = new Form1();
form1.ReceiveLoop();
}
}
private void ReceiveLoop()
{
clientSocket.ReceiveTimeout = 100;
byte[] receivedBuffer = new byte[1024];
try
{
int rec = clientSocket.Receive(receivedBuffer);
byte[] data = new byte[rec];
Array.Copy(receivedBuffer, data, rec);
updateClient("Received: " + Encoding.ASCII.GetString(data));
}
catch (SocketException e)
{
//MessageBox.Show(e.ToString());
}
}
ReceiveLoop() works when I access from the GUI thread, however it will not work(Throws SocketException, due to timeout) when accessed via myThread.
Any help or suggestions on another way I could approach this would be greatly appreciated :D

Categories

Resources