Meine Frage beinhaltet Ereignisse und wo ich die Ereignisse in meiner Klasse auslöst. Diese Klasse umschließt meine TCP-Funktionalität und ich verwende TcpListener, um dies zu erreichen. Ich weiß, einige TCP Sachen aus dem folgenden Beispiel fehlt möglicherweise, aber ich möchte die Dinge so einfach wie möglich machen:trigger event von einem AsyncCallback in C#
C# 2.0 Probe
class MyTcpClass
{
public delegate void ClientConnectHandler(Socket client, int clientNum);
public event ClientConnectHandler ClientConnect;
private Socket wellKnownSocket;
private Socket[] clientSockets = new Socket[MAX_CLIENTS];
private int numConnected = 0;
private void OnClientConnect(Socket client, int clientNum)
{
if (ClientConnect != null)
ClientConnect(client, clientNum);
}
public void StartListening()
{
//initialize wellKnownSocket
//...
wellKnownSocket.BeginAccept(new AsyncCallback(internal_clientConnect);
}
public void internal_clientConnect(IAsyncResult ar)
{
//Add client socket to clientSocket[numConnected]
//numConnected++;
//...
wellKnownSocket.EndAccept(ar);
OnClientConnect(clientSocket[numConnected], numConnected);
//error: event happens on different thread!!
}
}
class MainForm
{
void Button_click()
{
MyTcpClass mtc = new MyTcpClass();
mtc.ClientConnect += mtc_ClientConnected;
}
void mtc_clientConnected(Socket client, int clientNum)
{
ActivityListBox.Items.Add("Client #" + clientNum.ToString() + " connected.");
//exception: cannot modify control on seperate thread
}
}
Ich denke, meine Frage ist, ohne dieses Muster zu brechen viel, was macht mehr Sinn? Auch wenn jemand eine bessere elegante Lösung hat, sind sie willkommen.
Theorie
class MainForm
{
public MainForm()
{
MyTcpClass mtc = new MyTcpClass();
MyTcpClass2 mtc2 = new MyTcpClass2(this);
//this version holds a Form handle to invoke the event
mtc.ClientConnect += mtc_uglyClientConnect;
mtc2.ClientConnect += mtc2_smartClientConnect;
}
//This event is being called in the AsyncCallback of MyTcpClass
//the main form handles invoking the control, I want to avoid this
void mtc_uglyClientConnect(Socket s, int n)
{
if (mycontrol.InvokeRequired)
{
//call begininvoke to update mycontrol
}
else
{
mycontrol.text = "Client " + n.ToString() + " connected.";
}
}
//This is slightly cleaner, as it is triggered in MyTcpClass2 by using its
//passed in Form handle's BeginInvoke to trigger the event on its own thread.
//However, I also want to avoid this because referencing a form in a seperate class
//while having it (the main form) observe events in the class as well seems... bad
void mtc2_smartClientConnect(Socket s, int n)
{
mycontrol.text = "Client " + n.ToString() + " connected.";
}
}
Also schlagen Sie das erste Beispiel vor, wo ich Zugriff auf Winform-Steuerelement Sachen in der Event-Handler in MainForm mit Aufruf? Mir ist klar, dass MyTcpClass sich nicht bewusst ist, auf welchem Thread es läuft, aber MyTcpClass "Has An" asynchrone Callback-Beziehung mit Client-Verbindung. Am liebsten würde ich das Ereignis im Thread auslösen (egal zu welchem Thread), in dem MyTcpClass erstellt wurde. Ich sehe Ihren Standpunkt und stimme ihm zu, jedoch modelliert Microsoft selbst ein ähnliches Ereignis mit seinem "Hintergrundarbeiter" mit seinem progresschanged-Ereignis. –
@Tom: Das Problem ist, dass dieses Threading-Modell ziemlich spezifisch für Winforms ist - Sie können möglicherweise nicht einmal den Event-Handler für den Thread aufrufen, auf dem die Klasse erstellt wurde! (Was ist, wenn der Thread beendet wurde?) – cdhowie