简体   繁体   中英

C# .net Form1.visible from different class and thread

I'm working on a client server application and this all works fine but since I programmed it so that when the client gets response from the server this is handled in a different class and thread. I would like to switch form1.Visible to be false from there (after login is successful). I tried many things like:

Trying to pass the form instance but was not able to get it there since the code happens as a reply from the server.

Making a function in Form1 that hides it and starts form2. this failed because I can't start that part from a different thread.

Finding the active form and hide that did not work either since I was not allowed to do that from a different thread.

How can i do something simple as hiding a form from a different class and thread?

the code:

public class ClientHandleData
{
    public static ByteBuffer playerBuffer;
    private delegate void Packet_(byte[] data);
    private static Dictionary<long, Packet_> packets = new Dictionary<long, Packet_>();
    private static long pLength;

    public static void InitMessages()
    {
        Console.WriteLine("Initializing network messages..");
        packets.Add((long)ServerPackets.SLoginCheckRes, Packet_Login_response);
    }

    public static void HandleData(byte[] data)
    {
        byte[] Buffer;
        Buffer = (byte[])data.Clone();

        if (playerBuffer == null) playerBuffer = new ByteBuffer();
        playerBuffer.WriteBytes(Buffer);

        if (playerBuffer.Count() == 0)
        {
            playerBuffer.Clear();
            return;
        }

        if (playerBuffer.Length() >= 8)
        {
            pLength = playerBuffer.ReadLong(false);
            if (pLength <= 0)
            {
                playerBuffer.Clear();
                return;
            }
        }

        if (playerBuffer.Length() >= 8)
        {
            pLength = playerBuffer.ReadLong(false);
            if (pLength <= 0)
            {
                playerBuffer.Clear();
                return;
            }
        }

        while (pLength > 0 & pLength <= playerBuffer.Length() - 8)
        {
            if (pLength <= playerBuffer.Length() - 8)
            {
                playerBuffer.ReadLong();
                data = playerBuffer.ReadBytes((int)pLength);
                HandleDataPackets(data);
            }
            pLength = 0;

            if (playerBuffer.Length() >= 8)
            {
                pLength = playerBuffer.ReadLong(false);
                if (pLength < 0)
                {
                    playerBuffer.Clear();
                    return;
                }
            }
        }
    }

    public static void HandleDataPackets(byte[] data)
    {
        long packetnum; ByteBuffer buffer; Packet_ packet;
        buffer = new ByteBuffer();
        buffer.WriteBytes(data);
        packetnum = buffer.ReadLong();
        buffer = null;

        if (packetnum == 0) return;

        if (packets.TryGetValue(packetnum, out packet))
        {
            packet.Invoke(data);
        }
    }

    private static void Packet_Login_response(byte[] data)
    {
        long packetnum; ByteBuffer buffer;
        buffer = new ByteBuffer(); ;
        buffer.WriteBytes(data);
        packetnum = buffer.ReadLong();
        string msg = buffer.ReadString();

        if(msg == "Wrong password")
        {
            System.Windows.Forms.MessageBox.Show("Wachtwoord is incorrect.");
        }
        else if(msg == "Wrong username")
        {
            System.Windows.Forms.MessageBox.Show("Gebruikersnaam is incorrect.");
        }
        else if(msg == "Login succes")
        {
            //here i want form1.visible to be false.
        }
    }
}

This script triggers when I click a login button on Form1. that starts loginclick on my networkmanager and that sends the data to the server. when the server replies the above code will run.

Your architecture is wrong. You have to have a reference to form1 somewhere. Possibly it should be as a interface.

In worst case scenario, you could pass it to ClientHandleData like:

public class ClientHandleData
{
  public static Form LoginForm { get; set; }
}

And at the beginning of your app:

ClientHandleData.LoginForm = form1;

And then if you want to close form from a different thread you should use Invoke:

static void DoHideLoginForm()
{
    LoginForm.Visible = false;
}

static void HideLoginForm()
{
    if(LoginForm.InvokeRequired)
        LoginForm.Invoke(new Action(() => DoHideLoginForm()));
    else
        DoHideLoginForm();
}

And then you just call HideLoginForm when you want to hide it. This code first checks if you're in a different thread (InvokeRequired) and calls DoHideLoginForm from a proper thread.

But your architecture is bad and it can bring you to more and more problems. I think that this should be done more like this:

  • You should have a login controller class
  • You should have login interface and login form, like

     public interface ILoginView: IDisposable { string Login {get; set;} string Pass {get; set;} DialogResult ShowDialog(); } 

Then your loginForm (form1) should implement this interface:

class LoginForm: Form, ILoginView
{
    //here go Login and Pass properties
}

And your controller should be like this:

class LoginController
{
    ILoginView loginView;

    public LoginController(ILoginView loginView)
    {
        this.loginView = loginView;
    }

    public async Task<bool> Login()
    {
        loginView.ShowDialog();
        bool result = await DoYourLoginProcedure(loginView.Login, loginView.Pass);
        if(result)
        {
           loginView.Hide(); //or possibly Dispose
        }
    }
}

And then in your entry point:

LoginForm loginForm = new LoginForm();
LoginController contr = new LoginController(loginForm);
if(!contr.Login())
  //exit application

Of course this is not ideal solution, but this is the way you should go. Read about MVC, IoC (inversion of control) and DI (dependency injection)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM