views:

41

answers:

2

I have a console that I want to use to invoke commands on a WinForm in another computer (I'm testing it through localhost though).

When the form starts, it instantiates the CommandListener to receive commands over TCP. Whenever I attempt to instantiate it without a separate thread, the winform doesn't display at all, so I used "Initialize" to run it on a separate thread.

    public CommandListener(Form client)
    {
        this.ClientControl = client;

        Socket CommandSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPAddress ipa = IPAddress.Loopback;
        IPEndPoint ipe = new IPEndPoint(ipa, 23120);

        CommandSocket.Bind(ipe);
        CommandSocket.Listen(1);

        Thread RemoteCommandListener = new Thread(new ParameterizedThreadStart(Initialize));
        RemoteCommandListener.Start(CommandSocket);

    }

    private void Initialize(object obj)
    {
        Socket CommandSocket = (Socket)obj;

        while (true)
        {
            allDone.Reset();
            CommandSocket.BeginAccept(new AsyncCallback(AcceptCallback), CommandSocket);
            allDone.WaitOne();
        }
    }

Unfortunately, if I do use a separate thread, I receive "cross thread operation not valid" as an error when attempting to invoke the command on the winform.

            int bytesRead = Master.EndReceive(ar);
            if (bytesRead > 0)
            {
                state.sb.Append(Encoding.ASCII.GetString(state.Buffer, 0, bytesRead));

                command = state.sb.ToString();
                if (command.IndexOf("Write") > -1)
                {
                    try
                    {
                        MethodInfo method = typeof(Multiboxxy).GetMethod(command);
                        method.Invoke(ClientControl, new object[] { "Success!" });
                    }
                    catch (Exception e)
                    {
                        MessageBox.Show(e.InnerException.Message);
                    }
                }
                else
                {
                    Master.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0,
                       new AsyncCallback(ReadCallback), state);
                }
            }
+1  A: 

I recommend using WCF instead; there is an option in WCF to synchronize automatically to the SynchronizationContext of the host.

The next-best option is to use automatically-synchronizing socket objects such as those in Nito.Async.

A third option is to keep the .NET Socket class but when you need to do UI updates, use a Task scheduled to the UI thread (TaskScheduler.FromCurrentSynchronizationContext). Task and TaskScheduler are built into .NET 4.0 and are available in a library for .NET 3.5.

A fourth option is to keep the .NET Socket class and use SynchronizationContext directly for updating the UI.

Stephen Cleary
A: 

Instead of MethodInfo.Invoke, use:

// somewhere, define a delegate type for the invoked method (e.g. 'InvokerDelegate')

if (ClientControl.InvokeRequired)
    ClientControl.Invoke(Delegate.CreateDelegate(typeof(InvokerDelegate), ClientControl, method), "Success!");
else
    method.Invoke(ClientControl, new object[] { "Success!" });

The Control class' Invoke() method is, to the best of my knowledge, the only way to perform proper thread synchronization when calling methods on controls.

Bradley Smith
Thanks for the reply, but could you provide an example for the "InvokerDelegate"?
Gio Borje
Well in the example you posted, the delegate would be defined as:`delegate void InvokerDelegate(string arg);` - since you are not doing anything with the return value and you are only passing 1 string as a parameter...
Bradley Smith
@Bradley: for future reference, `ISynchronizeInvoke` (which includes `Control.Invoke`) is an outdated synchronization mechanism. It limits the code to work only with Windows Forms. Its replacement is `SynchronizationContext` (introduced in .NET 2.0), which works with Windows Forms, WPF, Silverlight, ASP.NET, Console applications, Win32 services, etc.
Stephen Cleary