I am running server/client communication.
Now i want to write something on the server textBox and show it on the client textBox so I am sending a message from the server to the client which takes it using a static method:
static void Client_MessageReceived(object sender, MessageEventArgs e)
{
//Client only accepts text messages
var message = e.Message as ScsTextMessage;
if (message == null)
{
return;
}
}
Now I just want to append the message to the client textBox from this static method. I guess that I will need some kind of invoke but I don't know how to do it, and I cant find anything useful on Google.
Invoke method
public void AppendText(string what, bool debug = false)
{
if (debug)
return;
if (this.InvokeRequired)
{
this.Invoke(
new MethodInvoker(
delegate() { AppendText(what); }));
}
else
{
DateTime timestamp = DateTime.Now;
tbox.AppendText(timestamp.ToLongTimeString() + "\t" + what + Environment.NewLine);
}
}
Message received method
private void Client_MessageReceived(object sender, MessageEventArgs e)
{
//Client only accepts text messages
var message = e.Message as ScsTextMessage;
if (message == null)
{
return;
}
AppendText(message.Text, false);
//Console.WriteLine("Server sent a message: " + message.Text);
}
// Program.cs
public static ProgramForm Form;
publi static void Main()
{
// ...
Application.Run(Form = new ProgramForm());
// ...
}
public static void ChangeText(String message)
{
Form.TextBox1.Text = message;
}
// ProgramForm.cs
private void Client_MessageReceived(object sender, MessageEventArgs e)
{
if (e.Message != null)
Program.ChangeText(e.Message);
}
Related
I have a WPF (.NET Framework 4.6) application that uses websocket-sharp (version 3.0.0) to create a websocket server.
I have a WebsocketServer and using EventHandler to tranfer event to MainWindow.xaml.cs but it not working. The MainWindow.xaml.cs listened to a RaiseOnScanDevice event but not any event invoked here.
I think this issue is relative to different thread. I try using Dispatcher.Invoke but it still not working.
System.Windows.Application.Current.Dispatcher.Invoke(new System.Action(() =>
{
RaiseOnScanDevice(this, new EventArgs());
}));
I found an issue (https://github.com/sta/websocket-sharp/issues/350) but the answers do not resolve my issue.
Please help me a solution for this issue.
WebsocketServer.cs file
public class WebsocketServer : WebSocketBehavior
{
private static readonly Lazy<WebsocketServer> lazyInstance = new Lazy<WebsocketServer>(() => new WebsocketServer());
public static WebsocketServer Instance
{
get
{
return lazyInstance.Value;
}
}
private const string TAG = "WebsocketServer";
private const string HOST_IP_ADDRESS = "127.0.0.2"; // localhost
private const int PORT = 38001;
public WebSocketServer socket;
private PacketHandler packetHandler = new PacketHandler();
public event EventHandler<EventArgs> RaiseOnScanDevice = new EventHandler<EventArgs>((a, e) => { });
public WebsocketServer()
{
Initialize();
}
public void Initialize()
{
socket = new WebSocketServer(IPAddress.Parse(HOST_IP_ADDRESS), PORT);
socket.AddWebSocketService<WebsocketServer>("/");
StartServer();
}
public void StartServer()
{
socket.Start();
}
public void StopServer()
{
socket.Stop();
}
protected override Task OnOpen()
{
return base.OnOpen();
}
protected override Task OnClose(CloseEventArgs e)
{
return base.OnClose(e);
}
protected override Task OnError(ErrorEventArgs e)
{
return base.OnError(e);
}
protected override Task OnMessage(MessageEventArgs e)
{
System.IO.StreamReader reader = new System.IO.StreamReader(e.Data);
string message = reader.ReadToEnd();
//Converting the event back to 'eventName' and 'JsonPayload'
PacketModel packet = packetHandler.OpenPacket(message);
HandleMessageFromClient(packet);
return base.OnMessage(e);
}
private void HandleMessageFromClient(PacketModel packet) {
var eventName = packet.EventName;
var data = packet.Data;
if (eventName == null || eventName.Equals(""))
{
return;
}
switch (eventName)
{
case SocketEvent.Hello:
Send("OK");
break;
case SocketEvent.ScanDevice:
ScanDevice();
break;
default:
break;
}
}
private void ScanDevice()
{
try
{
RaiseOnScanDevice(this, new EventArgs());
// or dispatch to Main Thread
System.Windows.Application.Current.Dispatcher.Invoke(new System.Action(() =>
{
RaiseOnScanDevice(this, new EventArgs());
}));
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
}
}
MainWindow.xaml.cs file
public partial class MainWindow : Window
{
public WebsocketServer WebsocketConnection
{
get { return WebsocketServer.Instance; }
}
public MainWindow()
{
InitializeComponent();
WebsocketConnection.RaiseOnScanDevice += SocketConnection_RaiseOnScanDevice;
}
private void SocketConnection_RaiseOnScanDevice(object sender, EventArgs e)
{
Console.WriteLine("SocketConnection_RaiseOnScanDevice");
}
The queue of messages is a good idea but you may want to use a lock to guard access to it. Most likely it won't be an issue but if you don't, you leave yourself open to the possibility of an error if the coroutine is reading from the queue as the websocket is writing to it. For example you could do something like this:
var queueLock = new object();
var queue = new Queue<MyMessageType>();
// use this to read from the queue
MyMessageType GetNextMessage()
{
lock (queueLock) {
if (queue.Count > 0) return queue.Dequeue();
else return null;
}
}
// use this to write to the queue
void QueueMessage(MyMessageType msg)
{
lock(queueLock) {
queue.Enqueue(msg);
}
}
I have a v4.0.0.1 implementation of Somdron's "Reliable Pub-Sub" pattern for communication between two parts of a new application. This application will have a "Server" (the engine that does all the heavy calculations) and "Clients" that will send requests and get information on progress back from the server.
The problem I have with my current version of "Reliable Pub-Sub" is that I don't seem to have a proper way for sending requests to the sever from the client. Let me start by showing you the code:
SERVER:
using NetMQ;
using NetMQ.Sockets;
using System;
using System.Linq;
namespace Demo.Messaging.Server
{
public class ZeroMqMessageServer : IDisposable
{
private const string WELCOME_MESSAGE = "WM";
private const string HEARTBEAT_MESSAGE = "HB";
private const string PUBLISH_MESSAGE_TOPIC = "PUB";
private readonly TimeSpan HEARTBEAT_INTERVAL = TimeSpan.FromSeconds(2);
private NetMQActor actor;
private NetMQTimer heartbeatTimer;
private XPublisherSocket publisher;
private NetMQPoller poller;
public ZeroMqMessageServer(string address)
{
Address = address;
actor = NetMQActor.Create(Start);
}
private void Start(PairSocket shim)
{
using (publisher = new XPublisherSocket())
{
publisher.SetWelcomeMessage(WELCOME_MESSAGE);
publisher.Bind(Address);
//publisher.ReceiveReady -= DropPublisherSubscriptions;
publisher.ReceiveReady += DropPublisherSubscriptions;
heartbeatTimer = new NetMQTimer(HEARTBEAT_INTERVAL);
heartbeatTimer.Elapsed += OnHeartbeatTimeElapsed;
shim.ReceiveReady += OnShimReceiveReady;
shim.SignalOK(); // Let the actor know we are ready to work.
poller = new NetMQPoller() { publisher, shim, heartbeatTimer };
poller.Run();
}
}
private void DropPublisherSubscriptions(object sender, NetMQSocketEventArgs e)
{
publisher.SkipMultipartMessage();
}
private void OnHeartbeatTimeElapsed(object sender, NetMQTimerEventArgs e)
{
publisher.SendFrame(HEARTBEAT_MESSAGE);
}
private void OnShimReceiveReady(object sender, NetMQSocketEventArgs e)
{
var socket = e.Socket;
string command = socket.ReceiveFrameString();
if (command == PUBLISH_MESSAGE_TOPIC)
{
// Forward the message to the publisher.
NetMQMessage message = socket.ReceiveMultipartMessage();
publisher.SendMultipartMessage(message);
}
else if (command == NetMQActor.EndShimMessage)
{
// Dispose command received, stop the poller.
poller.Stop();
}
}
public void PublishMessage(NetMQMessage message)
{
// We can use actor like NetMQSocket and publish messages.
actor.SendMoreFrame(PUBLISH_MESSAGE_TOPIC)
.SendMultipartMessage(message);
}
public string Address { get; private set; }
private bool disposedValue = false;
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
actor?.Dispose();
publisher?.Dispose();
poller?.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(true);
}
}
}
CLIENT:
using NetMQ;
using NetMQ.Sockets;
using System;
using System.Collections.Generic;
using System.Linq;
using Messaging.Helpers;
namespace Demo.Messaging.Client
{
public class ZeroMqMessageClient : IDisposable
{
private string SUBSCRIBE_COMMAND = "S";
private const string WELCOME_MESSAGE = "WM";
private const string HEARTBEAT_MESSAGE = "HB";
private const string PUBLISH_MESSAGE_TOPIC = "PUB";
private readonly TimeSpan TIMEOUT = TimeSpan.FromSeconds(5);
private readonly TimeSpan RECONNECTION_PERIOD = TimeSpan.FromSeconds(5);
private readonly string[] addressCollection;
private List<string> subscriptions = new List<string>();
private NetMQTimer timeoutTimer;
private NetMQTimer reconnectionTimer;
private NetMQActor actor;
private SubscriberSocket subscriber;
private PairSocket shim;
private NetMQPoller poller;
public ZeroMqMessageClient(params string[] addresses)
{
addressCollection = addresses;
actor = NetMQActor.Create(Start);
}
private void Start(PairSocket shim)
{
this.shim = shim;
shim.ReceiveReady += OnShimReceiveReady;
timeoutTimer = new NetMQTimer(TIMEOUT);
timeoutTimer.Elapsed += OnTimeoutTimerElapsed;
reconnectionTimer = new NetMQTimer(RECONNECTION_PERIOD);
reconnectionTimer.Elapsed += OnReconnectionTimerElapsed;
poller = new NetMQPoller() { shim, timeoutTimer, reconnectionTimer };
shim.SignalOK();
Connect();
poller.Run();
if (subscriber != null)
subscriber.Dispose();
}
private void Connect()
{
using (NetMQPoller tmpPoller = new NetMQPoller())
{
List<SubscriberSocket> socketCollection = new List<SubscriberSocket>();
SubscriberSocket connectedSocket = null;
EventHandler<NetMQSocketEventArgs> messageHandler = (s, e) =>
{
connectedSocket = (SubscriberSocket)e.Socket;
tmpPoller.Stop();
};
// We cancel the poller without setting the connected socket.
NetMQTimer tmpTimeoutTimer = new NetMQTimer(TIMEOUT);
tmpTimeoutTimer.Elapsed += (s, e) => tmpPoller.Stop();
tmpPoller.Add(tmpTimeoutTimer);
// Attempt to subscribe to the supplied list of addresses.
foreach (var address in addressCollection)
{
SubscriberSocket socket = new SubscriberSocket();
socketCollection.Add(socket);
//socket.ReceiveReady -= messageHandler;
socket.ReceiveReady += messageHandler;
tmpPoller.Add(socket);
// Subscribe to welcome messages.
socket.Subscribe(WELCOME_MESSAGE);
socket.Connect(address);
}
tmpPoller.Run(); // Block and wait for connection.
// We should have an active socket/conection.
if (connectedSocket != null)
{
// Remove the connected socket from the collection.
socketCollection.Remove(connectedSocket);
ZeroMqHelpers.CloseConnectionsImmediately(socketCollection);
// Set the active socket.
subscriber = connectedSocket;
//subscriber.SkipMultipartMessage(); // This skips the welcome message.
// Subscribe to subscriptions.
subscriber.Subscribe(HEARTBEAT_MESSAGE);
foreach (var subscription in subscriptions)
subscriber.Subscribe(subscription);
// Remove start-up handler, now handle messages properly.
subscriber.ReceiveReady -= messageHandler;
subscriber.ReceiveReady += OnSubscriberReceiveReady;
poller.Add(subscriber);
// Reset timers.
timeoutTimer.Enable = true;
reconnectionTimer.Enable = false;
}
else // We need to attempt re-connection.
{
// Close all existing connections.
ZeroMqHelpers.CloseConnectionsImmediately(socketCollection);
timeoutTimer.Enable = false;
reconnectionTimer.Enable = true;
}
}
}
private void OnShimReceiveReady(object sender, NetMQSocketEventArgs e)
{
string command = e.Socket.ReceiveFrameString();
if (command == NetMQActor.EndShimMessage)
{
poller.Stop();
}
else if (command == SUBSCRIBE_COMMAND)
{
string topic = e.Socket.ReceiveFrameString();
subscriptions.Add(topic);
if (subscriber != null)
subscriber.Subscribe(topic);
}
}
private void OnTimeoutTimerElapsed(object sender, NetMQTimerEventArgs e)
{
if (subscriber != null)
{
poller.Remove(subscriber);
subscriber.Dispose();
subscriber = null;
Connect();
}
}
private void OnReconnectionTimerElapsed(object sender, NetMQTimerEventArgs e)
{
// We re-attempt connection.
Connect();
}
private void OnSubscriberReceiveReady(object sender, NetMQSocketEventArgs e)
{
// Here we just forwward the message on to the actor.
var message = subscriber.ReceiveMultipartMessage();
string topic = message[0].ConvertToString();
// Let us see what is in the message.
if (message.Count() > 1)
{
string content = message[1].ConvertToString();
Console.WriteLine($"ZMQ_ALT - {topic}:: {content}");
}
if (topic == WELCOME_MESSAGE)
{
// Disconnection has occurred we might want to restore state from a snapshot.
}
else if (topic == HEARTBEAT_MESSAGE)
{
// We got a heartbeat, lets postponed the timer.
timeoutTimer.Enable = false;
timeoutTimer.Enable = true;
}
else
{
shim.SendMultipartMessage(message);
}
}
public void Subscribe(string topic)
{
actor.SendMoreFrame(SUBSCRIBE_COMMAND).SendFrame(topic);
}
public NetMQMessage ReceiveMessage()
{
return actor.ReceiveMultipartMessage();
}
public void PublishMessage(NetMQMessage message)
{
actor.SendMoreFrame(PUBLISH_MESSAGE_TOPIC)
.SendMultipartMessage(message);
}
private bool disposedValue = false;
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
actor?.Dispose();
subscriber?.Dispose();
shim?.Dispose();
poller?.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(true);
}
}
}
Now, I can send messages from the server to the client which is awesome and the client using the following code from the main method in two separate console applications
Program.cs for SERVER:
class Program
{
static void Main(string[] args)
{
using (ZeroMqMessageServer server = new ZeroMqMessageServer("tcp://127.0.0.1:6669"))
{
while (true)
{
NetMQMessage message = new NetMQMessage();
message.Append("A");
message.Append(new Random().Next().ToString());
server.PublishMessage(message);
Thread.Sleep(200);
}
}
}
}
Program.cs for CLIENT:
class Program
{
static void Main(string[] args)
{
Task.Run(() =>
{
using (ZeroMqMessageClient client = new ZeroMqMessageClient("tcp://127.0.0.1:6669"))
{
client.Subscribe(String.Empty);
while (true) { }
}
});
Console.ReadLine();
}
}
The client correctly auto-detects dropped connections and reconnects, fantastic little pattern.
However, this pattern out-of-the-box does not allow the client to send messages to the server. So in the client I have added the following code
public void PublishMessage(NetMQMessage message)
{
actor.SendMoreFrame(PUBLISH_MESSAGE_TOPIC)
.SendMultipartMessage(message);
}
and in the client I have changed the publisher.ReceiveReady += DropPublisherSubscriptions; event handler to
private void DropPublisherSubscriptions(object sender, NetMQSocketEventArgs e)
{
var message = e.Socket.ReceiveMultipartMessage();
string topic = message[0].ConvertToString();
Console.WriteLine($"TOPIC = {topic}");
// Let us see what is in the message.
if (message.Count() > 1)
{
string content = message[1].ConvertToString();
Console.WriteLine($"TEST RECIEVE FROM CLIENT - {topic}:: {content}");
}
publisher.SkipMultipartMessage();
}
but this does not seem to handle my messages. It receives the heartbeats and welcome messages, but I am not doing this right.
How can I enable/facilitate the client to talk to the server without breaking what I have already?
Thanks for your time.
I'm kind of new to this ask-answer thing, please let me know if I've done any mistakes. I have this server program, running on my laptop. Server is a console application;
class Program
{
static void Main(string[] args)
{
Server sv = new Server("192.168.2.69", 52025);
sv.OnClientAccept += new ClientAcceptHandler(sv_OnClientAccept);
sv.OnClientMessage += new ClientMessageHandler(sv_OnClientMessage);
sv.Start();
}
static void sv_OnClientMessage(Server s, System.Net.Sockets.TcpClient client, string message)
{
Console.WriteLine("Message received from client " + GetClientIp(client) + ": \"" + message + "\"");
string msgToAll = message;
s.SendToAllClients(msgToAll);
Console.WriteLine("Message sent: \"" + message + "\" to the clients:");
foreach (TcpClient cl in s.Clients)
{
Console.WriteLine(GetClientIp(cl));
}
}
static void sv_OnClientAccept(Server s, System.Net.Sockets.TcpClient client)
{
Console.WriteLine("Client Accepted : " + GetClientIp(client));
}
static string GetClientIp(TcpClient Client)
{
return ((IPEndPoint)Client.Client.RemoteEndPoint).Address.ToString();
}
}
The Server class;
public delegate void ClientAcceptHandler(Server s, TcpClient client);
public delegate void ClientMessageHandler(Server s, TcpClient client, string message);
public class Server
{
private List<TcpClient> clients = new List<TcpClient>();
object lockObjc;
private TcpListener server;
private string ip;
private int port;
private Thread accepter, listener;
public List<TcpClient> Clients { get { return this.clients; } set { this.clients = value; } }
public event ClientAcceptHandler OnClientAccept;
public event ClientMessageHandler OnClientMessage;
public Server(string IP, int Port)
{
ip = IP;
port = Port;
}
private void ClientAccepted(TcpClient Client)
{
if (OnClientAccept != null)
{
OnClientAccept.Invoke(this, Client);
}
}
private void ClientMessaged(TcpClient Client, string Message)
{
if (OnClientMessage != null)
{
OnClientMessage.Invoke(this, Client, Message);
}
}
public void Start()
{
lockObjc = new object();
IPAddress ipAddress = IPAddress.Parse(ip);//127.0.0.1 -> local || "192.168.2.69" -> laptop
server = new TcpListener(ipAddress, port);//2014 -> local || 52025
server.Start();
accepter = new Thread(AcceptClients);
accepter.Start();
listener = new Thread(Listen);
listener.Start();
}
private void AcceptClients()
{
while (true)
{
TcpClient attachedCl = server.AcceptTcpClient();
if (attachedCl != null)
{
lock (lockObjc)
{
if (!clients.Contains(attachedCl))
{
clients.Add(attachedCl);
ClientAccepted(attachedCl);
}
}
}
}
}
private void Listen()
{
while (true)
{
for (int i = 0; i < clients.Count; i++)
{
TcpClient client = clients[i];
lock (lockObjc)
{
try
{
StreamReader clientIn = new StreamReader(client.GetStream());
string msg = clientIn.ReadLine();
if (msg != string.Empty)
{
ClientMessaged(client, msg);
}
}
catch
{
}
}
}
}
}
private bool send(TcpClient Client, string Msg)
{
bool b = true;
try
{
TcpClient client = Client;
StreamWriter clientOut = new StreamWriter(client.GetStream());
clientOut.AutoFlush = true;
clientOut.WriteLine(Msg);
}
catch
{
b = false;
}
return b;
}
public bool SendToACLient(TcpClient Client, string Message)
{
return send(Client, Message);
}
public bool SendToAClient(int i, string Message)
{
return send(clients[i], Message);
}
public bool SendToAllClients(string Message)
{
bool b = true;
for (int i = 0; i < clients.Count; i++)
{
b = b && send(clients[i], Message);
}
return b;
}
public bool SendToAllClientsExcept(TcpClient Client, string Message)
{
int x = clients.IndexOf(Client);
bool b = true;
for (int i = 0; i < clients.Count; i++)
{
if (i != x)
{
b = b && send(clients[i], Message);
}
}
return b;
}
}
Since I'm really new to server-client relationships, I don't know if the server part is OK, but it seems OK to me programmatically (But I'm also amateur programer, no real education).
And the client part is;
public delegate void ServerMessageHandler(Client Receiver, string Message);
public class Client
{
private StreamReader clientIn;
private StreamWriter clientOut;
private TcpClient client;
private Thread listener;
private object lockObj;
public event ServerMessageHandler OnServerMessage;
public bool Connected { get { return (client != null && client.Connected); } }
public Client()
{
lockObj = new object();
client = new TcpClient();
listener = new Thread(Listen);
}
private void ServerMessaged(string Message)
{
if (OnServerMessage != null)
{
OnServerMessage.Invoke(this, Message);
}
}
private void Listen()
{
string serverMsg;
while (true)
{
try
{
serverMsg = clientIn.ReadLine();
if (serverMsg != string.Empty)
{
ServerMessaged(serverMsg);
}
}
catch
{
}
}
}
private void start()
{
listener.Start();
}
public bool Connect(string Ip, int Port)
{
client.Connect(Ip, Port);//"192.168.2.69", 52025
if (client.Connected)
{
clientIn = new StreamReader(client.GetStream());
clientOut = new StreamWriter(client.GetStream());
clientOut.AutoFlush = true;
start();
}
return client.Connected;
}
public void Send(string Message)
{
if (client.Connected)
{
clientOut.WriteLine(Message);
}
}
}
Here's the form that I run Client class;
public partial class Form1 : Form
{
string s;
Client c;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
c = new Client();
c.OnServerMessage += new ServerMessageHandler(c_OnServerMessage);
bool b = c.Connect("192.168.2.69", 52025);
if (b)
{
s += "Connected to the server: 192.168.2.69:52025\r\n";
}
timer1.Start();
}
void c_OnServerMessage(Client Receiver, string Message)
{
s += "Server: " + Message + "\r\n";
}
private void button1_Click(object sender, EventArgs e)
{
c.Send(textBox1.Text);
}
private void timer1_Tick(object sender, EventArgs e)
{
textBox2.Text = s;
}
private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
c.Send(textBox1.Text);
}
}
}
This form has two textboxes, first one is the one which takes user input (textBox1), the second one is the one which shows server responds. Why I'm not using Console? Because I've tried it in a way which I was waiting an input from user (Console.ReadLine) which as far as I know locks the console until user presses enter, even tough I'm using a thread for listening the server, I wasn't able to show the server answer on console.
So, I decided to create my own console (sort-of). The reason I run a timer to show messages is I get an error when I try to change the textbox text from a method that is being called by a thread (which is the c_OnServerMessage method, being called, indirectly, from the Listener thread from Client class)
But the problem I get here is this: I run the server on my laptop, I also run one client on my laptop which goes perfectly fine until I open up another client on another computer. At that point things go this way: I send a message from a client, the message reaches the server and is sent back. When I send another message, that message does not reach the server until I send a message from Client 2. And when I send a message from Client 2, the server gets the message from Client 2 even tough I sent the message from Client 1 first.
So basically what happens is, if I run 2 clients, I cannot send 2 messages in a row from a client, it kind of acts like a chess game where there is a turn for playing. I really don't understand the reason.
This problem is probably from a basic mistake but I had to write this whole message to be able to express myself. Thank you for your patient and your helps.
EDIT:
Problem solved thanks to this: TCP server with multiple Clients
My problem was the Listen method from Server class. The Listen method is being called by a thread, but still it runs a for loop in itself. Which if loop stops and waits for something, thread wouldn't make any difference. Thanks again, i think i will keep question, because i do not know what should happen to solved problems.
This is a method in the other class that i want to get the message from in my mainform.
string message = Encoding.ASCII.GetString(data);
Console.WriteLine(message);
Can i subscribe to this method from the main method somehow to get the data each time this method is triggered?
Edit:
Okay so this is what my code looks like now:
} else {
string message = Encoding.ASCII.GetString(data);
DoSomething(message);
//Console.WriteLine(message);
}
} catch (Exception ex) {
Log("Error recieving data: " + ex.ToString());
}
}
}
public delegate void SomethingHappenedHandler(string s);
public SomethingHappenedHandler SomethingHappened = null;
public void DoSomething(string message)
{
Console.WriteLine(message);
var sh = SomethingHappened;
if (sh == null)
{
sh(message);
}
}
And in the main method:
dht.dhtNode.SomethingHappened += (msg) =>
{
talkText.Text += "[Friend]: " + msg + "\n\n";
};
But it does not trigger it? what else should i do to make it work?
You can create a delegate and subscribe to it. For ex,
someInstance.SomethingHappened += (msg) =>
{
//your code
};
public delegate void SomethingHappenedHandler(string s);
public SomethingHappenedHandler SomethingHappened = null;
public void DoSomething()
{
string message = Encoding.ASCII.GetString(data);
Console.WriteLine(message);
var sh = SomethingHappened;
if (sh != null) sh(message);
}
EDIT:
And to display the result in a UI control you should be aware of Cross-threads operations. Cross-thread operation not valid
I need to create a class with two properties:
LogOutput
ExceptionOutput
These properties (Actions<>) send a message or a exception depending on the target function. This target function is set via properties.
Currently, I have this functional code:
public class Output
{
private Action<string> logOutput;
private Action<Exception, string> exceptionOutput;
public Action<string> LogOutput { set { this.logOutput = value; } get { return this.logOutput; } }
public Action<Exception, string> ExceptionOutput { set { this.exceptionOutput = value; } get { return this.exceptionOutput; } }
public Output() : this(null, null) { }
public Output(Action<string> logAction, Action<Exception, string> exceptionAction)
{
this.logOutput = logAction;
this.exceptionOutput = exceptionAction;
}
public void WriteLogMessage(string format, params object[] args)
{
if (this.logOutput != null)
logOutput(string.Format(format, args));
}
public void WriteExceptionMessage(Exception ex, string format, params object[] args)
{
if (this.exceptionOutput != null)
exceptionOutput(ex, string.Format(format, args));
}
}
And this is my form code:
private void MainForm_Load(object sender, EventArgs e)
{
// my Output object
Output myOutput = new Output();
// set properties
myOutput.ExceptionOutput = this.WriteExceptionMessageToTextBox;
myOutput.LogOutput = this.WriteLogMessageToTextBox;
// test
myOutput.WriteLogMessage("this is my log message to text box");
myOutput.WriteExceptionMessage(new Exception("this is my exception"), "this is my exception message to text box");
}
private void WriteLogMessageToTextBox(string message)
{
// nothing to do here
if (this.txtBox.IsDisposed)
return;
if (this.InvokeRequired)
{
BeginInvoke(new MethodInvoker(delegate() { WriteLogMessageToTextBox(message); }));
}
else
{
// write to text box
this.txtBox.AppendText(message + Environment.NewLine);
}
}
private void WriteExceptionMessageToTextBox(Exception ex, string message)
{
// nothing to do here
if (this.txtBox.IsDisposed)
return;
if (this.InvokeRequired)
{
BeginInvoke(new MethodInvoker(delegate() { WriteExceptionMessageToTextBox(ex, message); }));
}
else
{
string msg = "";
msg += string.Format("Program:{0}", message);
msg += string.Format("Message{0}", ex.Message);
msg += string.Format("StackTrace:{0}", ex.StackTrace);
msg += string.Format("Source:{0}", ex.Source);
// write to text box
this.txtBox.AppendText(msg + Environment.NewLine);
}
}
It is correct this model? There is another way to do this?
It is correct this model? There is another way to do this?
There is nothing wrong with this, necessarily. However, events may be a more common approach to handling this, as you're effectively using the delegate as an event in this scenario.
Using events does have one significant advantage (potentially), in that you can also easily have multiple subscribers, which would make it simple to allow more than one item to "listen" to the exceptions or log messages. (*While this works with delegates as well, it wouldn't be as standard of a way to use delegates..)
sorry offtopic but use StringBuilder string is not prefer for editing
string msg = "";
msg += string.Format("Program:{0}", message);
msg += string.Format("Message{0}", ex.Message);
msg += string.Format("StackTrace:{0}", ex.StackTrace);
msg += string.Format("Source:{0}", ex.Source);
StringBuilder sb = new StringBuilder();
sb.Append(string.Format("Program:{0}", message));
sb.Append(string.Format("Message{0}", ex.Message));
sb.Append(string.Format("StackTrace:{0}", ex.StackTrace));
sb.Append(string.Format("Source:{0}", ex.Source));
string result = sb.ToString();