C# 从另一个线程调用一个方法或从另一个线程触发一个在主线程上处理的事件
我知道,这个标题可能会让人困惑,但简而言之,我无法更好地表达它 基本上,我正在编写一个TCP服务器。我没有要显示的Windows窗体,用户看到的唯一东西是TrayIcon 我的TCP服务器类为监听客户端创建一个线程,然后为每个处理通信的客户端创建额外的线程。当所有通信完成后,我想在主线程上调用一个方法 我通过从客户机通信线程触发一个事件来完成这项工作,该事件在主线程上得到处理,在我想将桌面通知添加到我的应用程序之前,所有这些都工作得很好。我已经使用WPF(C# 从另一个线程调用一个方法或从另一个线程触发一个在主线程上处理的事件,c#,multithreading,C#,Multithreading,我知道,这个标题可能会让人困惑,但简而言之,我无法更好地表达它 基本上,我正在编写一个TCP服务器。我没有要显示的Windows窗体,用户看到的唯一东西是TrayIcon 我的TCP服务器类为监听客户端创建一个线程,然后为每个处理通信的客户端创建额外的线程。当所有通信完成后,我想在主线程上调用一个方法 我通过从客户机通信线程触发一个事件来完成这项工作,该事件在主线程上得到处理,在我想将桌面通知添加到我的应用程序之前,所有这些都工作得很好。我已经使用WPF(iControlNotification
iControlNotification
)构建了一个通知,并希望在我前面提到的事件处理程序中显示它,但是我收到一条错误消息,上面说“调用线程必须是STA线程”
以下是一些代码(我删除了不必要的一方):
-
-
那么,我应该如何调用tcpServer_CommandReceived
,以便以正确的方式显示通知窗口
我真的被困在这里了,我真的很感谢你在这方面的帮助 //如何从另一个线程调用方法: a) 您可以通过向其传递SynchronizationContext对象在其他线程中调用它:
void Method(object s)
{
SynchronizationContext sync = s as SynchronizationContext;
sync.Post(delegate { // what to do in other thread}, null);
}
然后在代码中,在新任务中运行此方法,将同步上下文作为对象传递(例如):
b) 您可以为此创建扩展方法(以下是我在win forms应用程序中用于更新UI的示例):
class TCPServer {
public delegate void CommandReceivedEventHandler(object source, CommandReceivedEventArgs e);
public event CommandReceivedEventHandler CommandReceived;
public class CommandReceivedEventArgs : EventArgs {
private string _command;
private string[] _splittedCommands;
private iControlClient _client;
public CommandReceivedEventArgs(string command, iControlClient client) {
_command = command;
_splittedCommands = command.Split(new Char[]{' '});
_client = client;
}
public string Command { get { return _command; } }
public string[] SplittedCommands { get { return _splittedCommands; } }
public iControlClient Client { get { return _client; } }
}
public TCPServer() {
this.tcpListener = new TcpListener(IPAddress.Any, Port);
this.icClients = new Dictionary<String, iControlClient>();
}
public Boolean Start() {
if (PortIsAvailable(Port)) {
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
Program.Log("ListeningThread started.");
return true;
} else {
return false;
}
}
private void ListenForClients() {
this.tcpListener.Start();
TcpClient client;
while (this.keepListening) {
try {
client = this.tcpListener.AcceptTcpClient();
} catch {
break;
}
iControlClient icClient = new iControlClient(client);
icClient.Thread = new Thread(new ParameterizedThreadStart(HandleClientCommunication));
icClient.Thread.Start(icClient);
}
Program.Log("Stop listening.");
}
private void HandleClientCommunication(object client) {
iControlClient icClient = (iControlClient)client;
NetworkStream clientStream = icClient.TCP.GetStream();
clientStream.ReadTimeout = 10;
int bufflen = 4096;
byte[] message = new byte[bufflen];
int bytesRead;
while (this.keepReceiving && icClient.keepConnected) {
bytesRead = 0;
try {
bytesRead = clientStream.Read(message, 0, bufflen);
} catch {
break;
}
if (bytesRead == 0) {
break;
}
ProcessReceivedData(icClient, ParseData(message, bytesRead));
}
Program.Log("[" + icClient.IPAddress + "] Connection closed.");
icClient.TCP.Close();
this.icClients.Remove(icClient.IPAddress);
}
private void ProcessReceivedData(iControlClient icClient, String[] commands) {
Program.Log("[" + icClient.IPAddress + "] >> " + String.Join(" ", commands));
if (this.CommandReceived != null) {
CommandReceived(this, new CommandReceivedEventArgs(String.Join(" ", commands), icClient));
}
NetworkStream clientStream = icClient.TCP.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("::ok");
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
icClient.keepConnected = false;
}
}
public class iControlNotificationManager {
private iControlNotifications _notifications;
public void ShowNotfication(string caption, string message) {
if ((Boolean)Program.GetSetting("notifications", true) == false) return;
Dispatcher.CurrentDispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(
() => {
iControlNotification noti = new iControlNotification(caption, message);
noti.Show();
}));
}
}
public class iControlNotification : Window {
private iControlNotificationModel _notification;
public iControlNotification(string caption, string message) { // Here's the error
InitializeComponent();
_notification = new iControlNotificationModel() {
Caption = caption,
Message = message
};
this.DataContext = _notification;
}
}
void Method(object s)
{
SynchronizationContext sync = s as SynchronizationContext;
sync.Post(delegate { // what to do in other thread}, null);
}
Task t = Task.Factory.StartNew(Method, SynchronizationContext.Current);
public static class ControlExtensions
{
/// Executes the Action asynchronously on the UI thread, does not block execution on the calling thread.
public static void UIThread(this Control @this, Action code)
{
if (@this.InvokeRequired)
{
@this.BeginInvoke(code);
}
else
{
code.Invoke();
}
}
}