0

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());
            }
        }
    }
SnuKies
  • 1,578
  • 1
  • 16
  • 37
  • Inside the`Load` event the handle is already created. Use the `CreateHandle` method after you instantiate your class from outside. – abto Jan 15 '17 at 08:53

1 Answers1

0

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.

Community
  • 1
  • 1
Martin Zikmund
  • 38,440
  • 7
  • 70
  • 91