public delegate void MessageReceiveEventHandler(MessageReceiveEventArgs e);
public event MessageReceiveEventHandler MessageReceiveEvent;
public class MessageReceiveEventArgs : EventArgs
{
public string Message { get; }
public MessageReceiveEventArgs(string Message)
{
this.Message = Message;
}
}
private void OnMessageReceiveEvent(string Message)
{
if (MessageReceiveEvent == null) return;
MessageReceiveEventArgs MessageREvent = new MessageReceiveEventArgs(Message);
MessageReceiveEvent(MessageREvent);
}
This is my event code. and i call event when my socket client receive message(data). but event not worked..
ClientSocket cs;
public Form1()
{
InitializeComponent();
cs = new ClientSocket();
cs.MessageReceiveEvent += Cs_MessageReceiveEvent1;
}
private void Cs_MessageReceiveEvent1(ClientSocket.MessageReceiveEventArgs e)
{
listBox1.Items.Add(e.Message);
}
I tried this.
I cannot see anywhere where you are raising the event. Try making the OnMessageReceiveEvent method public and then call it from the Form1 constructor.
public Form1()
{
InitializeComponent();
cs = new ClientSocket();
cs.MessageReceiveEvent += Cs_MessageReceiveEvent1;
cs.OnMessageReceiveEvent("Testing Event");
}
Related
I have a list of objects and I want to assign values in a factory method. I have checked similar questions but they have access to a method in existing assembly. I want to use a custom method and also define which event should be set.
for example
mylist.Assign(nameofevent,assignfuntion);
the usage something like
public static void Assign(this Control[] controls,eventhandler #event,Action func)
{
foreach (var item in controls)
//assign function to event
item.clicked += func;//Preferably clicked must be Specified from argument
}
Trying to help to get to the bottom of what is wrong with Shervin Ivari's question. I'm illustration how you can achieve it. But still unsure if this is what you want?
public static void Main()
{
var listeners = new List<SomeClassWithListener>
{
new SomeClassWithListener(),
new SomeClassWithListener(),
new SomeClassWithListener()
};
var theEvent = new SomeClassWithEvent();
MatchEmUp(listeners, theEvent);
theEvent.RaiseEvent();
}
public static void MatchEmUp(IEnumerable<SomeClassWithListener> listeners, SomeClassWithEvent theEvent)
{
foreach(SomeClassWithListener listener in listeners)
theEvent.ItsAlive += listener.ThenIllSlayIt;
}
public class SomeClassWithListener
{
public void ThenIllSlayIt(object sender, EventArgs e)
{
Console.WriteLine("Chaaaaaarge!");
}
}
public class SomeClassWithEvent
{
public EventHandler ItsAlive;
public void RaiseEvent()
{
ItsAlive.Invoke(this, new EventArgs());
}
}
https://dotnetfiddle.net/4Y13cf
Or by using delegates, EventHandler is also a delegate:
public static void Main()
{
var listener1 = new SomeClassWithListener();
var listener2 = new SomeClassWithListener();
var listener3 = new SomeClassWithListener();
var listeners = new List<EventHandler>
{
listener1.ThenIllSlayIt,
listener2.ThenIllSlayIt,
listener3.ThenIllSlayIt
};
var theEvent = new SomeClassWithEvent();
MatchEmUp(listeners, theEvent);
theEvent.RaiseEvent();
}
public static void MatchEmUp(IEnumerable<EventHandler> listeners, SomeClassWithEvent theEvent)
{
foreach(EventHandler listener in listeners)
theEvent.ItsAlive += listener;
}
public class SomeClassWithListener
{
public void ThenIllSlayIt(object sender, EventArgs e)
{
Console.WriteLine("Chaaaaaarge!");
}
}
public class SomeClassWithEvent
{
public EventHandler ItsAlive;
public void RaiseEvent()
{
ItsAlive.Invoke(this, new EventArgs());
}
}
https://dotnetfiddle.net/k16lsy
I have a first class that raises an event when some changes occur:
public class MyFirstClass {
public event EventHandler ChangesHappened;
public MyFirstClass() {
}
public void MyMethod() {
//Thing happened
ChangesHappened?.Invoke(this, new EventArgs());
}
}
I also have a second class that have a list of FirstClass:
public class MySecondClass {
private List<MyFirstClass> first;
public MySecondClass() {
foreach(var f in first) {
first.Changed += (s, e) => {};
}
}
}
And last I have a WPF application with an instance of SecondClass. How can I handle the Changed event (FirstClass) from WPF? Should I create an event in SecondClass and raise it inside first.Changed += (s, e) => { NewEvent(this, new EventArgs()); } and then catch this in the WPF?
The objective is get the Changed event in the WPF application.
It seems to me that this is the simplest answer:
public class MySecondClass
{
public event EventHandler ChangesHappened;
private List<MyFirstClass> first;
public MySecondClass()
{
foreach (var f in first)
{
f.ChangesHappened += (s, e) => ChangesHappened?.Invoke(s, e);
}
}
}
Another option is to use Microsoft's Reactive Framework which lets you pass events (well observables) around as first-class language citizens.
You could do this:
void Main()
{
var msc = new MySecondClass();
msc.Changes.Subscribe(ep =>
{
/* Do stuff with
ep.Sender
ep.EventArgs
from the `MyFirstClass` instances
*/
});
}
public class MyFirstClass
{
public event EventHandler ChangesHappened;
public IObservable<EventPattern<EventArgs>> Changes;
public MyFirstClass()
{
this.Changes = Observable.FromEventPattern<EventHandler, EventArgs>(
h => this.ChangesHappened += h, h => this.ChangesHappened += h);
}
public void MyMethod()
{
ChangesHappened?.Invoke(this, new EventArgs());
}
}
public class MySecondClass
{
public IObservable<EventPattern<EventArgs>> Changes;
private List<MyFirstClass> first = new List<MyFirstClass>();
public MySecondClass()
{
this.Changes = first.Select(f => f.Changes).Merge();
}
}
As #Enigmativity already mentioned: When you have a class, that has to manage other classes (bunch of MyFirstClass references) then you have to forward your events from sub class to manager class.
public class MySecondClass
{
public event EventHandler Changed;
private List<MyFirstClass> firstClassList;
public MySecondClass()
{
firstClassList = new List<MyFirstClass>();
}
public void AddMyFirstClassList(List<MyFirstClass> firstClassList)
{
foreach (var firstClass in firstClassList)
AddMyFirstClass(firstClass);
}
public void AddMyFirstClass(MyFirstClass firstClass)
{
// from sub class to manager class
firstClass.Changed += firstClass_Changed;
firstClassList.Add(firstClass);
}
private void firstClass_Changed(object sender, EventArgs args)
{
Changed?.Invoke(sender, args);
}
public void RemoveMyFirstClass(MyFirstClass firstClass)
{
MyFirstClass.Remove -= firstClass_Changed;
firstClassList.Remove(firstClass);
}
}
Another option is to pass a callback function. You should avoid this, unless you need it explicity:
public class MyFirstClass
{
EventHandler handler;
public MyFirstClass(EventHandler handler)
{
this.handler = handler;
}
public void MyMethod()
{
handler?.Invoke(this, new EventArgs());
}
}
public class MySecondClass
{
private List<MyFirstClass> firstClassList;
public MySecondClass()
{
firstClassList = new List<MyFirstClass>();
}
// you have instantiated your class and passed your callback function previously.
public void AddMyFirstClass(MyFirstClass firstClass)
{
firstClassList.Add(firstClass);
}
// for demonstrating the instantiation.
public void AddMyFirstClass(EventHandler handler)
{
firstClassList.Add(new MyFirstClass(handler));
}
}
I have a M2MQTT client subscribed to a topic in the DashboardViewModel class. On message receive, the UI gets updated by calling Writelog.
public class DashboardViewModel : Object, IDashboardViewModel
{
private IDashboardView View { get; }
public DashboardViewModel(IDashboardView view)
{
View = view;
mqttClient = new MqttClient("localhost");
mqttClientId = Guid.NewGuid().ToString();
mqttClient.MqttMsgPublishReceived += mqttClient_MsgPublishReceived;
mqttClient.Subscribe(new string[] { "Home/Temperature" }, new byte[] { MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE });
mqttClient.Connect(mqttClientId);
//...
}
private void mqttClient_MsgPublishReceived(object sender, MqttMsgPublishEventArgs eventArgs)
{
string message = Encoding.UTF8.GetString(eventArgs.Message);
View.Writelog(message);
}
}
The textbox on FrmMain does not update; tbxLogs.InvokeRequired always returns false, i.e. tbxLogs.AppendText always executes. Any suggestions please?
public partial class FrmMain : Form, IDashboardView
{
private IDashboardViewModel dashboardViewModel = null;
private delegate void WriteLogCallback(string text);
public FrmMain()
{
InitializeComponent();
}
public void Writelog(string text)
{
if (tbxLogs.InvokeRequired)
{
WriteLogCallback callback = new WriteLogCallback(Writelog);
tbxLogs.Invoke(callback, new object[] { text });
}
else
{
tbxLogs.AppendText(text + "\n");
}
}
}
I think you need to use dispatcher :)
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action<String>(Writelog), message);
inside of this method
private void mqttClient_MsgPublishReceived(object sender, MqttMsgPublishEventArgs eventArgs)
{
string message = Encoding.UTF8.GetString(eventArgs.Message);
//here instead of View.Writelog(message);
}
I open multiple serial ports and assign the DataReceived event to a single method. If now multiple com ports receive at the same time something, SerialPort_DataReceived is called parallel(?) so i tried to use lock so that only one event could be handled at the same time.
using System;
using System.Collections.Generic;
using System.Windows;
using System.IO.Ports;
using System.Text;
namespace MainApplication
{
public partial class MainWindow : Window
{
private SerialConnectionHandler m_SerialConnectionHandler;
public MainWindow()
{
InitializeComponent();
m_SerialConnectionHandler = new SerialConnectionHandler();
m_SerialConnectionHandler.ResponseReceived += SerialConnectionHandler_ResponseReceived;
}
private void SerialConnectionHandler_ResponseReceived(object sender, EventArgs e)
{
// Do something.
}
}
public class SerialConnectionHandler
{
private List<SerialPort> m_SerialConnections;
private List<SerialCommand> m_CommandQueue;
private object m_DataReceivedLock;
public event EventHandler ResponseReceived;
public SerialConnectionHandler()
{
m_SerialConnections = new List<SerialPort>();
m_CommandQueue = new List<SerialCommand>();
m_DataReceivedLock = new object();
foreach (var comPortName in SerialPort.GetPortNames())
{
var newSerialPort = new SerialPort(comPortName);
newSerialPort.DataReceived += SerialPort_DataReceived;
var newSerialCommand = new SerialCommand(comPortName, "Command", "Response");
newSerialPort.Open();
newSerialPort.Write(newSerialCommand.Command, 0, newSerialCommand.Command.Length);
m_SerialConnections.Add(newSerialPort);
}
}
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
lock (m_DataReceivedLock)
{
var serialPort = (SerialPort)sender;
var receivedContent = new byte[serialPort.BytesToRead];
serialPort.Read(receivedContent, 0, receivedContent.Length);
// Clear in buffer.
serialPort.DiscardInBuffer();
// Do something which could lead to problems if multiple com ports receive at the same time something.
foreach (var command in m_CommandQueue.FindAll(command => command.SerialPortName.Equals(serialPort.PortName)))
{
if (command.ExpectedResponse.Equals(receivedContent.ToString()))
{
ResponseReceived?.Invoke(this, new EventArgs());
m_CommandQueue.Remove(command);
break;
}
}
}
}
}
public class SerialCommand
{
public string SerialPortName { get; }
public byte[] Command { get; }
public string ExpectedResponse { get; }
public SerialCommand(string serialPortName, string command, string expectedResponse)
{
SerialPortName = serialPortName;
Command = Encoding.ASCII.GetBytes(command);
ExpectedResponse = expectedResponse;
}
}
}
My question is now, could lock lead to missed received content due to the fact that not every event is handled immediately? I'm calling SerialPort.Read() and SerialPort.DiscardInBuffer() from inside the lock block.
I have a problem when I need to collect event argument data that has been changed through event hadnler that contains async calls. As you can see in code below, MessageReceiver raises event and collects data from property "Change", and continues processing. Problem is when event handler is async because it calles asny method with "await". In method OnMyEvent code continues immediately after calling the handler, it does not wait for handler to finish, so "Change" property is not set... How to make things more "in sync"?
public class MyEventArgs:EventArgs
{
public bool Change { get; set; }
}
public delegate void MyEventHandler(object sender, MyEventArgs e);
public class MessageReceiver
{
public event MyEventHandler MyEvent;
public void RaiseEvent()
{
OnMyEvent();
}
protected void OnMyEvent()
{
MyEventArgs e = new MyEventArgs();
if (MyEvent != null)
MyEvent(this, e);
if (e.Change)
Console.WriteLine("Change occured");
}
}
public class Form
{
MessageReceiver mr;
public Form(MessageReceiver MR)
{
mr = MR;
mr.MyEvent += Mr_MyEvent;
}
private async void Mr_MyEvent(object sender, MyEventArgs e)
{
string s = await GetString();
e.Change = true;
}
public async Task<string> GetString()
{
return await Task.Factory.StartNew(() =>
{
return Guid.NewGuid().ToString();
}
);
}
}
public class Program
{
static void Main(string[] args)
{
MessageReceiver mr = new MessageReceiver();
Form frm = new Form(mr);
mr.RaiseEvent();
}
}
I discuss a variety of approaches for asynchronous events on my blog. I recommend the deferral approach, which you can implement using the DeferralManager and IDeferralSource types from my Nito.AsyncEx.Coordination library:
public class MyEventArgs: EventArgs, IDeferralSource
{
private readonly DeferralManager _deferralManager;
public MyEventArgs(DeferralManager deferralManager)
{
_deferralManager = deferralManager;
}
public bool Change { get; set; }
public IDisposable GetDeferral() { return _deferralManager.GetDeferral(); }
}
public class MessageReceiver
{
protected async Task OnMyEventAsync()
{
if (MyEvent != null)
{
DeferralManager deferralManager = new DeferralManager();
MyEventArgs e = new MyEventArgs(deferralManager);
MyEvent(this, e);
await deferralManager.WaitForDeferralsAsync();
}
if (e.Change)
Console.WriteLine("Change occured");
}
}
public class Form
{
private async void Mr_MyEvent(object sender, MyEventArgs e)
{
using (e.GetDeferral())
{
string s = await GetString();
e.Change = true;
}
}
}