C# WPF-调用其他类时GUI不更新?(TCP应用程序)
C# WPF-调用其他类时GUI不更新?(TCP应用程序),c#,wpf,tcp,controls,textblock,C#,Wpf,Tcp,Controls,Textblock,我有一个相当奇怪的问题?我在web上见过如何将控件从主类传递到另一个类,据说这是可行的,但事实并非如此 我试图做的是创建一个简单的异步TCP客户机-服务器连接,它将消息从客户机发送到服务器。问题是当我想更新客户端的文本块时,应用程序退出(并没有错误,只是关闭)。我只有一个主线程,所以我认为不需要调用 来自主类的代码: public partial class MainWindow : Window { public MainWindow() { Initial
我有一个相当奇怪的问题?我在web上见过如何将控件从主类传递到另一个类,据说这是可行的,但事实并非如此
我试图做的是创建一个简单的异步TCP客户机-服务器连接,它将消息从客户机发送到服务器。问题是当我想更新客户端的文本块时,应用程序退出(并没有错误,只是关闭)。我只有一个主线程,所以我认为不需要调用
来自主类的代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void connect_ClickEvent(object sender, RoutedEventArgs e)
{
try
{
_statusPanel.Text += "Sending request to server (IP address: " + _ipTextBox.Text + ", port number: " + _portTextBox.Text + ")\n";
_statusPanel.Text += "Connecting.....\n";
AsynchronousClient.setStatusPanel(_statusPanel);
AsynchronousClient.setPort(Convert.ToInt32(_portTextBox.Text));
AsynchronousClient.setIpAddress(_ipTextBox.Text);
AsynchronousClient.StartClient(_message.Text);
_statusPanel.Text += "... connection established!\n";
_statusPanel.Text += "Enter the string to be transmitted !\n";
}
catch (Exception ee)
{
_statusPanel.Text += ee.StackTrace + "\n";
}
}
}
public class AsynchronousClient
{
// The port number for the remote device.
private static int port;
private static IPAddress ipAd;
public static TextBlock statusPanel;
public static void setStatusPanel(TextBlock status)
{
statusPanel = status; //That's my setter for statusPanel which I want to update
}
public static void StartClient(string message)
{
// Connect to a remote device.
try
{
IPAddress ipAddress = ipAd;
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
client.BeginConnect(remoteEP,
new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
string sendingMessage = message + "<EOF>";
Send(client, sendingMessage);
sendDone.WaitOne();
Receive(client);
receiveDone.WaitOne();
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch (Exception e)
{
statusPanel.Text += e.ToString() + "\n";
}
}
private static void ConnectCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket)ar.AsyncState;
client.EndConnect(ar);
//This next line is where my program closes without error
statusPanel.Text = "Socket connected to " + client.RemoteEndPoint.ToString() + "\n";
connectDone.Set();
}
catch (Exception e)
{
statusPanel.Text += e.ToString() + "\n";
}
}
来自其他类的代码:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void connect_ClickEvent(object sender, RoutedEventArgs e)
{
try
{
_statusPanel.Text += "Sending request to server (IP address: " + _ipTextBox.Text + ", port number: " + _portTextBox.Text + ")\n";
_statusPanel.Text += "Connecting.....\n";
AsynchronousClient.setStatusPanel(_statusPanel);
AsynchronousClient.setPort(Convert.ToInt32(_portTextBox.Text));
AsynchronousClient.setIpAddress(_ipTextBox.Text);
AsynchronousClient.StartClient(_message.Text);
_statusPanel.Text += "... connection established!\n";
_statusPanel.Text += "Enter the string to be transmitted !\n";
}
catch (Exception ee)
{
_statusPanel.Text += ee.StackTrace + "\n";
}
}
}
public class AsynchronousClient
{
// The port number for the remote device.
private static int port;
private static IPAddress ipAd;
public static TextBlock statusPanel;
public static void setStatusPanel(TextBlock status)
{
statusPanel = status; //That's my setter for statusPanel which I want to update
}
public static void StartClient(string message)
{
// Connect to a remote device.
try
{
IPAddress ipAddress = ipAd;
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
client.BeginConnect(remoteEP,
new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
string sendingMessage = message + "<EOF>";
Send(client, sendingMessage);
sendDone.WaitOne();
Receive(client);
receiveDone.WaitOne();
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch (Exception e)
{
statusPanel.Text += e.ToString() + "\n";
}
}
private static void ConnectCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket)ar.AsyncState;
client.EndConnect(ar);
//This next line is where my program closes without error
statusPanel.Text = "Socket connected to " + client.RemoteEndPoint.ToString() + "\n";
connectDone.Set();
}
catch (Exception e)
{
statusPanel.Text += e.ToString() + "\n";
}
}
公共类异步客户端
{
//远程设备的端口号。
专用静态int端口;
专用静态IP地址;
公共静态文本块状态面板;
公共静态无效setStatusPanel(文本块状态)
{
statusPanel=status;//这是我要更新的statusPanel的setter
}
公共静态void StartClient(字符串消息)
{
//连接到远程设备。
尝试
{
IPAddress IPAddress=ipAd;
IPEndPoint remoteEP=新IPEndPoint(ipAddress,端口);
套接字客户端=新套接字(AddressFamily.InterNetwork,
流,ProtocolType.Tcp);
client.BeginConnect(remoteEP,
新的异步回调(ConnectCallback),客户端);
connectDone.WaitOne();
字符串sendingMessage=消息+“”;
发送(客户端,发送消息);
sendDone.WaitOne();
接收(客户);
receiveDone.WaitOne();
client.Shutdown(SocketShutdown.Both);
client.Close();
}
捕获(例外e)
{
statusPanel.Text+=e.ToString()+“\n”;
}
}
专用静态无效连接回调(IAsyncResult ar)
{
尝试
{
套接字客户端=(套接字)ar.AsyncState;
客户端.EndConnect(ar);
//下一行是我的程序无误关闭的地方
statusPanel.Text=“套接字已连接到”+客户端.RemoteEndPoint.ToString()+“\n”;
connectDone.Set();
}
捕获(例外e)
{
statusPanel.Text+=e.ToString()+“\n”;
}
}
**如果我将“statusPanel.text”替换为“Console.WriteLine”,一切正常!有人知道我做错了什么吗?***异步回调将在单独的线程上调用,而不是在主线程上调用,因此您无法从其他线程更新textBox值。您只能从主UI线程执行此操作
因此,您必须将其委托给主线程,如下所示:
statusPanel.Dispatcher.Invoke(new Action(() =>
statusPanel.Text = "Socket connected to " +
client.RemoteEndPoint.ToString() + "\n"));
方法
ConnectCallback
不会在WPF用户界面线程上执行,而是由线程池的后台线程上的套接字类调用。在该方法中,您可以设置状态面板的文本
使用StatusOanel.Dispatcher.Invoke
在UI线程上执行您的方法。如果您想了解更多有关它的信息,本文可能是这样的:我尝试使用statusPanel.Dispatcher(您发布的代码)但它不起作用。UI冻结了!问题出在您的代码中的某个地方。很可能是在BeginInvoke
操作之后,您正在这里等待一些线程sendDone.WaitOne()
和receiveDone.WaitOne();
。尝试注释这些行(仅用于测试以确定问题)并查看问题是否仍然存在。如果我将.Invoke更改为.BeginInvoke,则会得到client.RemoteEndPoint.ToString()的错误(无法访问已释放的对象)。那么,我如何告诉线程先完成更新,然后再继续?不,我不是要将Invoke更改为BeginInvoke。它必须是Invoke only。我的意思是当您调用委托client.BeginConnect(remoteEP,新的异步回调(ConnectCallback),client)时;
。在这一行之后,你调用多个方法,并使用WaitOne
等待它们,但我没有看到你从代码中设置这些WaitOne,因此你的UI线程将继续等待它们,直到你设置它们。试着注释代码,看看这是否是问题所在。我发布的代码肯定不会挂起UI。你是对的。是WaitOne()和线程停止!