gpt4 book ai didi

c# - 热从另一个线程调用方法或从另一个线程触发事件,该事件在主线程上处理

转载 作者:太空宇宙 更新时间:2023-11-03 13:06:00 25 4
gpt4 key购买 nike

我知道,标题可能令人困惑,但我真的无法用简短的语言更好地表达它。

基本上,我正在编写一个 TCP 服务器。我没有要显示的 Windows 窗体,用户看到的唯一东西是 TrayIcon。

我的 TCP 服务器类创建一个线程来监听客户端,然后为每个客户端处理通信创建额外的线程。当所有通信完成后,我想在主线程上调用一个方法。

我通过从客户端通信线程触发一个事件来完成它,该事件在主线程上得到处理,并且一切正常,直到我想将桌面通知添加到我的应用程序。我已经使用 WPF (iControlNotification) 构建了一个通知,并想在我之前提到的事件处理程序中显示它,但我收到一条错误消息,内容类似于“调用线程必须是一个STA 线程”。

这是一些代码(我删除了不必要的部分):

static class Program {

[...]

[STAThread]
static void Main() {
Log("iControlServerApplication started.");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

trayIcon = new TrayIcon();
trayIcon.Display();

NotificationManager = new iControlNotificationManager();

server = new TCPServer();
server.CommandReceived += new TCPServer.CommandReceivedEventHandler(tcpServer_CommandReceived);
if (server.Start()) {
NotificationManager.ShowNotfication("iControl Server Application", "Server started. " + plugins.Count + " plugins loaded.");
Application.Run();
} else {
MessageBox.Show("Port " + server.Port + " is already in use. Server could not be started.", ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}

[...]

static void tcpServer_CommandReceived(object source, TCPServer.CommandReceivedEventArgs e) {
string toolTipText = "[" + e.Client.IPAddress + "] >> " + e.Command;
NotificationManager.ShowNotfication("iControl Server Application", toolTipText);

foreach (IiControlPlugin plugin in plugins) {
plugin.Handle(e.SplittedCommands, e.Client);
}
}

[...]
}

-

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

那么我应该如何调用 tcpServer_CommandReceived 以便以正确的方式显示通知窗口?

我真的被困在这里,非常感谢任何帮助!

最佳答案

//如何从另一个线程调用一个方法:

a) 您可以通过将 SynchronizationContext 对象传递给它来在其他线程中调用它:

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);

b) 您可以为此目的创建扩展方法(这里是我在 win 表单应用程序中用于更新 UI 的示例):

   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();
}
}
}

关于c# - 热从另一个线程调用方法或从另一个线程触发事件,该事件在主线程上处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30786847/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com