How To Pass Tcpclient Between 2 Forms C# - 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.

Related

How to Save data on application close or entered background in WinUI3 app

How to intercept app_closing or app_entering_background in WinUi 3 app.
In UWP apps we do have Application_EnteredBackground event , in which we can intercept app close, we use GetDeferral() to save data .
Is there any same kind of event in WinUI 3 apps, I need to save data on app close, or entering background.
Tried window_VisibilityChanged and window_Closed events, but not able to use GetDeferral().
Kindly help
Thanks in advance .
Noorul
Here is my test code for your reference, you can intercept the closing event.
(closing is executed before closed)
public sealed partial class MainWindow : Window
{
private AppWindow _appWindow;
public MainWindow()
{
this.InitializeComponent();
this.Closed += OnClosed;
_appWindow = GetAppWindowForCurrentWindow();
_appWindow.Closing += OnClosing;
}
private void OnClosed(object sender, WindowEventArgs e)
{
string btnText = myButton.Content.ToString();
}
private async void OnClosing(object sender, AppWindowClosingEventArgs e)
{
string btnText = myButton.Content.ToString();
e.Cancel = true; //Cancel close
//Otherwise, the program will not wait for the task to execute, and the main thread will close immediately
//await System.Threading.Tasks.Task.Delay(5000); //wait for 5 seconds (= 5000ms)
Func<bool> funcSaveData = () =>
{
//perform operations to save data here
return true;
};
var funResult = await Task.Run(funcSaveData);
this.Close(); //close
}
private AppWindow GetAppWindowForCurrentWindow()
{
IntPtr hWnd = WindowNative.GetWindowHandle(this);
WindowId myWndId = Win32Interop.GetWindowIdFromWindow(hWnd);
return AppWindow.GetFromWindowId(myWndId);
}
private void myButton_Click(object sender, RoutedEventArgs e)
{
myButton.Content = "Clicked";
}
}

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.

How to get access to form's controls from class 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.

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);

Delegate loads the Alert Form but I can't use any of the components.. its stuck

The problem is below. Here's my code...
// Contents of Form1.cs
// Usual includes
namespace ProcessMonitor
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public Boolean getStatus()
{
// Returns true if the system is active
if (label1.Text.Equals("Active"))
return true;
return false;
}
private void button1_Click(object sender, EventArgs e)
{
if(getStatus())
{
label1.Text = "Not Active";
button1.Text = "Activate";
}
else
{
label1.Text = "Active";
button1.Text = "Deactivate";
}
}
private void Form1_Load(object sender, EventArgs e)
{
Monitor mon = new Monitor(this);
mon.Run();
}
}
}
// Contents of Monitor.cs
// Usual includes
using System.Management;
using System.Diagnostics;
using System.Threading;
namespace ProcessMonitor
{
class Monitor
{
Form1 parent;
private void ShowAlert(Alert al)
{
al.Show();
}
public Monitor(Form1 parent)
{
this.parent = parent;
}
public void InvokeMethod()
{
//This function will be on main thread if called by Control.Invoke/Control.BeginInvoke
Alert frm = new Alert(this.parent);
frm.Show();
}
// This method that will be called when the thread is started
public void Run()
{
var query = new WqlEventQuery("__InstanceCreationEvent", new TimeSpan(0, 0, 0, 0, 1),
"TargetInstance isa \"Win32_Process\");
while (true)
{
using (var watcher = new ManagementEventWatcher(query))
{
ManagementBaseObject mo = watcher.WaitForNextEvent();a
//MessageBox.Show("Created process: " + ((ManagementBaseObject)mo["TargetInstance"])["Name"] + ",Path: " + ((ManagementBaseObject)mo["TargetInstance"])["ExecutablePath"]);
ManagementBaseObject o = (ManagementBaseObject)mo["TargetInstance"];
String str = "";
foreach (PropertyData s in o.Properties)
{
str += s.Name + ":" + s.Value + "\n";
}
this.parent.Invoke(new MethodInvoker(InvokeMethod), null);
}
}
}
}
}
Alert.cs is just a blank form with a label that says “new process has started”. I intend to display the name of the process and location, pid, etc. by passing it to this alert form via the Thread (i.e. class Monitor). I have deliberately made the thread load in form_load so that I can resolve this error first. Adding it as a thread properly after the main form loads fully is a later task. I need to fix this first..
The delegate creates the Alert form but I can’t click on it, its just stuck. Need help to solve this.
Your while loop in Run is blocking the UI thread.
by passing it to this alert form via the Thread
You never actually create a new thread or task here - you just run code which executes in the UI thread, and causes an infinite loop. This will prevent the main form, as well as your Alert form, from ever displaying messages.
You need to push this into a background thread in order for it to work, ie:
private void Form1_Load(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(_ =>
{
Monitor mon = new Monitor(this);
mon.Run();
});
}

Categories

Resources