Search code examples
c#multithreadingwinformstcpclienttcpserver

Cant call ParametizedThread from Child Form


I am developing a Client/server app. In the Client app, I have a Main Form that is an MDI parent. The Main Form has a Load event that creates a new instance of a Child Form and makes it visible. This event also establishes Main as the MdiParent of Child. The Child form is meant to be a sign-in screen. From the child form, I create a reference to the parent, to be able to call methods from the parent.

However, upon executing the MdiParent.RequestConnection method, the GUI becomes stuck. So I tried to execute the method from a Thread, but it is not accepting my declaration, even if I'm seemingly following the correct syntax. I don't see what am I doing wrong. Please help

Main form

public partial class frmMainForm: Form
    {
        
        public frmMainForm()
        {
            InitializeComponent();
           
        }
        Thread runningClient;
        public MyTcpClient client= new MyTcpClient ();
        frmChildForm frmSignIn;
        bool clientConnected;
       

        private void frmMainForm_Load(object sender, EventArgs e)
        {
            clientConnected= false;
            panelSidebar.Hide();
            if(frmSignIn == null)
            {
                frmSignIn= new frmChildForm();
                frmSignIn.MdiParent = this;
                
                frmSignIn.Show();
            }
        }

        public void TurnOnPanels()
        {
            panelSidebar.Visible = true;
            panelSidebar.BringToFront();
        }

        public void RequestConnection(string username)
        {
            
            string serverRsp = client.Connect(username);
            if(serverRsp.Equals("SUCCESS")) 
            {
                MessageBox.Show("Signed In", "Welcome", MessageBoxButtons.OK, MessageBoxIcon.Information);
                clientConnected = true;
                frmSignIn.Close();
            }
        }
    }

And my child form

public partial class frmChildForm : Form
    {
        frmMainForm frmParent;
        Thread clientRunning;
        public frmChildForm()
        {
            InitializeComponent();
            frmParent= (frmMainForm)this.MdiParent;
        }

        private void frmSignIn_FormClosing(object sender, FormClosingEventArgs e)
        {
            frmParent= (frmMainForm)this.MdiParent;
            frmParent.TurnOnPanels();
        }

        private void btnSignIn_Click(object sender, EventArgs e)
        {
            if (txtSignInUsername.Text.Equals(""))
            {
                MessageBox.Show("No empty fields.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            } 
            else
            {
                //This is where it fails
                clientRunning= new Thread(new ParameterizedThreadStart(frmParent.RequestConnection);
                //"No Overload for RequestConnection matches delegate ParameterizedThreadStart"
                //If I try to include the parameter inside that call, I get a "waiting for method                      //name" syntax error message instead.
                clientRunning.Start(txtSignInUsername.Text.ToUpper());
            }
        }

        private void frmSignIn_Load(object sender, EventArgs e)
        {
            frmParent = (frmMainForm)this.MdiParent;
        }
    }

I also tried to do it from the main form by creating a thread inside RequestConnection, where it was supposed to execute client.Connect, but I got the same error.


Solution

  • Couple of things you need to fix

    public void RequestConnection(object username) // changed parameter type
    {
        if (username == null)
            throw new ArgumentNullException(nameof(username));
    
        if (!(username is string))
            throw new InvalidCastException("Expect string");// give proper message
    
        string serverRsp = client.Connect(username.ToString());
        if (serverRsp.Equals("SUCCESS"))
        {
            MessageBox.Show("Signed In", "Welcome", MessageBoxButtons.OK, MessageBoxIcon.Information);
            clientConnected = true;
    
            //this is require to solve cross-thread operation
            if (this.InvokeRequired)
                this.Invoke(new MethodInvoker(delegate ()
                {
                    frmSignIn.Close();
                }));
            else
                frmSignIn.Close();
        }
    }
    

    you need to get MdiParent in Form Load Event and remove from Constructor.

    Your child form load event/ or use Parent changed Event

    private void FrmLogin_Load(object sender, EventArgs e)
    {
        frmParent = (MainForm)this.MdiParent;
    }