我正在研究一个客户端服务器应用程序,这一切都运行正常但是因为我对它进行了编程,以便当客户端从服务器获得响应时,这将在不同的类和线程中处理。我想从那里切换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并将数据发送到服务器。当服务器回复上面的代码时就会运行。
答案 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(依赖注入)