1

Im new to programming and just wanted to know if a solution for a problem I got is appropriate.

I wanted to write a status (string) into a textbox from a class which is creating a Socket and the class listens for data to receives (in an other thread).

This is what i did:

Create the Class whithin the Form.cs with a button click:

 private void button_Create_Click(object sender, EventArgs e)
    {
        int port;
        Int32.TryParse(textBox_Port.Text, out port);
        ServerSocketClass serverSocket = new ServerSocketClass(port, this);
    }

The ServerSocketClass looks like:

class ServerSocketClass
{
    Socket ServerSocket;
    Socket Accepted;
    IPEndPoint LocalEndpoint;
    int Port = 1337; // just for fun
    Messenger MainForm;

    public ServerSocketClass(int port, Messenger form)
    {

        MainForm = form;

        if (port != 0)
            Port = port;
        ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        LocalEndpoint = new IPEndPoint(IPAddress.Any, Port);

        MainForm.writeToMessages("Binding Endpoint to Socket...");
        ServerSocket.Bind(LocalEndpoint);

        MainForm.writeToMessages("Starting ServerListener Thread...");
        Thread ServerListenThread = new Thread(startListening);
        ServerListenThread.Name = "ServerListenerThread";
        ServerListenThread.Start();        
    }

    private void startListening()
    {            
        ServerSocket.Listen(5);

        MainForm.writeToMessages("Whaiting for incoming connections...");
        Accepted = ServerSocket.Accept();
        whaitForData();
    }

and to update the GUI in the forms class i created a delegate and a "update" method with an invoke:

public delegate void writeMessege(string message);    
public writeMessege MessegeDelegate;
public void writeToMesseges(string messege)
    {
        if (InvokeRequired)
        {
            this.Invoke(MessegeDelegate, new object[] { messege });
            return;
        }
        textBox_Messeges.AppendText("SYSTEM: " + messege + "\n");
    }

It works, but I wanted to know if this is a "valid" way to do it or if I should go to the developer hell ;-)

thanks in advance

Locke

Locke
  • 163
  • 1
  • 9

3 Answers3

0

It's a perfectly valid way to do that, although whether it is "right" depends very much on the context - how often you call it, what you want to do inside it, and the code that you need to call it. There are many different ways of doing it without invoke, but there is nothing wrong with using InvokeRequired/Invoke - that's what it's there for. You could just use an update method that invokes itself, which is almost the same as your code, but slightly less verbose:

public void WriteMessages(string message)
{ 
  if (InvokeRequired)
  { this.Invoke(new Action<string>(WriteMessages), new object[] { message }); }
  else
  { textBox_Messages.AppendText("SYSTEM: " + message + "\n"); }
}

There are a lot of posts already on Invoke/InvokeRequired. As a starting point, check: Isn't blindly using InvokeRequired just bad practice?

Community
  • 1
  • 1
Richard Matheson
  • 1,125
  • 10
  • 24
  • 1
    *Instead* of using Invoke, one can use the `Progress` class and publish messages to the UI thread. It's *not* a good idea to mix UI and networking code. In fact, the MVC,MVVM patterns were created to decouple the UI from anything going on in the background – Panagiotis Kanavos Apr 19 '16 at 10:50
  • thanks, i was more i doubt because of passing a form into a new class, just to call the method of this form for updating the GUI. – Locke Apr 19 '16 at 10:54
  • That's interesting, I wasn't aware of Progress. This is why I love stack overflow :) – Richard Matheson Apr 26 '16 at 11:03
0

I had a similar situation, where I had a class that was called from other classes with many separate threads and I had to update one specific form from all these other threads. So creating a delegate and an event in the class with a handler in the form was the answer. So I wanted to share it as it seems simpler (even if not necessarily a better solution).

The solution that worked for me:

  1. I created an event in the class I wanted to do the update on another form. (First of course I instantiated the form (called SubAsstToolTipWindow) in the class.

  2. Then I used this event (ToolTipShow) to create an event handler on the form I wanted to update the label on. Worked like a charm.

I used this description to devise my own code below in the class that does the update:

public static class SubAsstToolTip
{
    private static SubAsstToolTipWindow ttip = new SubAsstToolTipWindow();
    public delegate void ToolTipShowEventHandler();
    public static event ToolTipShowEventHandler ToolTipShow;

    public static void Show()
    {
        // This is a static boolean that I set here but is accessible from the form.
        Vars.MyToolTipIsOn = true; 
        if (ToolTipShow != null)
        {
            ToolTipShow();
        }
    }

    public static void Hide()
    {
        // This is a static boolean that I set here but is accessible from the form.
        Vars.MyToolTipIsOn = false;
        if (ToolTipShow != null)
        {
            ToolTipShow();
        }
    }
}

Then the code in my form that was updated:

public partial class SubAsstToolTipWindow : Form
{
    public SubAsstToolTipWindow()
    {
        InitializeComponent();
        // Right after initializing create the event handler that 
        // traps the event in the class
        SubAsstToolTip.ToolTipShow += SubAsstToolTip_ToolTipShow;
    }

    private void SubAsstToolTip_ToolTipShow()
    {
        if (Vars.MyToolTipIsOn) // This boolean is a static one that I set in the other class.
        {
            // Call other private method on the form or do whatever
            ShowToolTip(Vars.MyToolTipText, Vars.MyToolTipX, Vars.MyToolTipY);     
        }
        else
        {
            HideToolTip();
        }

    }
ib11
  • 2,530
  • 3
  • 22
  • 55
  • @Locke -- Certainly welcome. You can and should upvote the answers/comments if they are useful. That is the best way to thank and also make sure others get access to useful solutions. Best, – ib11 Apr 23 '16 at 22:20
  • 1
    I cant, because Im not allowed to untill i got 15 reputation points :-( – Locke Apr 29 '16 at 17:17
0

long time ago, but I wanted you all know how I finally solved this to my full satisfaction (solved it with Events - of course ;-)):

I defined an EventArgs to pass all the Information I wanted to pass:

public class IncomingMessageEventArgs : EventArgs
{
    private Message _message;
    public Message Message
    {
        get
        {
            return _message;
        }
    }

    public IncomingMessageEventArgs(Message message)
    {
        _message = message;
    }

}    

On the Class that publishes the information (to the WPF - Form) define the Event and its Handler:

public delegate void IncomingMessageEventHandler(object sender, IncomingMessageEventArgs e);
    public event IncomingMessageEventHandler IncomingMessageEvent;
    protected void OnIncomingMessageEvent(IncomingMessageEventArgs e)
    {
        if (IncomingMessageEvent != null)
            IncomingMessageEvent(this, e);
    }

and of course Raise the event, if the WPF Form needs to be updated (also on the "information sending class"):

 OnIncomingMessageEvent(new IncomingMessageEventArgs(message));

on the WPF Class you need to listen to the events but first define a EventHandler because your information comes from a differen Thread!! : private delegate void writeMessageToChatEventHandler(object sender, IncomingMessageEventArgs e);

now we write our method witch will handle the raised event:

// Write to Chat
    private void writeMessageToChat(object sender, IncomingMessageEventArgs e)
    {
        try
        {
            if (!Dispatcher.CheckAccess())
            { 
                Dispatcher.Invoke(new writeMessageToChatEventHandler(writeMessageToChat), new object[] { sender, e } );
                return;
            }
            textBox_Chat.AppendText(e.Message.getFormatedMessageText() + "\n");
        }
        catch (Exception ex)
        {
            writeLogToChat(this, new IncomingLogEventArgs("ERROR: " + ex.Message));
        }
    }

and finally, we need to subscribe to the event of course (the first method, you can ignore, its just to meet the MS Nameing conventions:

private void ClientSocket_IncomingMessageEvent(object sender, IncomingMessageEventArgs e)
    {
        writeMessageToChat(sender, e);
    }

ClientSocket.IncomingMessageEvent += ClientSocket_IncomingMessageEvent;

Hopefully I made this understandable :P Thanks to all the people how helped me!

bye

Locke
  • 163
  • 1
  • 9