C#.net Form1.visible来自不同的类和线程

时间:2018-06-11 11:46:19

标签: c# .net

我正在研究一个客户端服务器应用程序,这一切都运行正常但是因为我对它进行了编程,以便当客户端从服务器获得响应时,这将在不同的类和线程中处理。我想从那里切换form1.Visible为false(登录成功后)。我尝试过很多东西:

尝试传递表单实例但由于代码是作为服务器的回复而无法获取它。

在Form1中创建一个隐藏它并启动form2的函数。 这失败了,因为我不能从另一个线程开始那部分。

查找活动表单并隐藏不起作用,因为我不允许从其他线程执行此操作。

如何从不同的类和线程隐藏表单来做一些简单的事情?

代码:

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.
        }
    }
}

单击Form1上的登录按钮时会触发此脚本。在我的networkmanager上启动loginclick并将数据发送到服务器。当服务器回复上面的代码时就会运行。

1 个答案:

答案 0 :(得分:1)

您的架构错了。你必须在某个地方引用form1。可能它应该作为一个界面。

在最坏的情况下,您可以将其传递给ClientHandleData,如:

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

在应用的开头:

ClientHandleData.LoginForm = form1;

然后如果你想从另一个线程关闭表单,你应该使用Invoke:

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

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

然后,当你想要隐藏它时,你只需要调用HideLoginForm。 此代码首先检查您是否在不同的线程(InvokeRequired)并从正确的线程调用DoHideLoginForm。

但是你的架构很糟糕,它会带给你越来越多的问题。 我认为这应该更像这样:

  • 您应该有登录控制器类
  • 您应该有登录界面和登录表单,例如

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

然后你的loginForm(form1)应该实现这个接口:

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

你的控制器应该是这样的:

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
        }
    }
}

然后在你的切入点:

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

当然这不是理想的解决方案,但这是你应该去的方式。阅读MVC,IoC(控制反转)和DI(依赖注入)