I created a dll contain this event handler:
public void tcp1_Data(object sender, Sockets.DataEventArgs e)
{
Tcp tcp = (Tcp)sender;
response = "Socket Connection" + tcp.Tag.ToString() + " replied : " + e.Data.ToString();
tcp.Close();
}
this will fire when server write some thing in socket connection. so by this, I can read the data on socket.
I used this dll in another project. I want to know in my project (that used dll) exactly when server is writing data on socket connection. as you see in tcp1_Data event, I set result into response variable and in main project (that used dll), I checked this variable polling (if response is not null, it means that this event fired). but Its not what I want. I dont want check this variable all the time.
is there any other way?
I tried this as #ThorstenDittmar said:
my dll project (its name is ClientSample) contain:
TheClassInDLL Class
public class TheClassInDLL
{
public event EventHandler<MyEventArgs> DataEventCalled;
public void tcp1_Data(object sender, Sockets.DataEventArgs e)
{
Tcp tcp = (Tcp)sender;
// Note: LOCAL variable
string myresponse = "Socket Connection" + tcp.Tag.ToString() + " replied : " + e.Data.ToString();
// Call the new event here
if (DataEventCalled != null)
DataEventCalled(this, new MyEventArgs(myresponse));
tcp.Close();
}
// We use this class to pass arguments to the event handler
public class MyEventArgs : EventArgs
{
public MyEventArgs(string response)
{
this.Response = response;
}
public string Response
{
get;
private set;
}
}
}
TCPSample class
public class TCPSample
{
Tcp tcp = new Tcp();
tcp.Data += new System.EventHandler
and in another project that I used above dll:
public partial class Form1 : Form
{
private TheClassInDLL myClass;
ClientSample.TCPSample t = new ClientSample.TCPSample();
public Form1()
{
InitializeComponent();
myClass = new TheClassInDLL();
myClass.DataEventCalled += DataEvent;
}
private void button1_Click(object sender, EventArgs e)
{
t.newTCP();
}
private void DataEvent(object sender, TheClassInDLL.MyEventArgs e)
{
MessageBox.Show(e.Response);
}
}
but It didnt work, DataEvent never happend.
Thanks for any helping...
What you wrote here is an event handler that is called when something happens. There must be a class containing this event handler. Instead of writing a global response variable, declare and invoke another event you can subscribe to from outside that class like this:
public class <TheClassInDLL>
{
public event EventHandler<MyEventArgs> DataEventCalled;
// SNIP: All the other code that leads to tcp1_Data being called
...
// The event handler that's called by some code in the class
public void tcp1_Data(object sender, Dart.Sockets.DataEventArgs e)
{
Tcp tcp = (Tcp)sender;
// Note: LOCAL variable
string myresponse = "Socket Connection" + tcp.Tag.ToString() + " replied : " + e.Data.ToString();
// Call the new event here
if (DataEventCalled != null)
DataEventCalled(this, new MyEventArgs(myresponse));
tcp.Close();
}
// We use this class to pass arguments to the event handler
public class MyEventArgs : EventArgs
{
public MyEventArgs(string response)
{
this.Response = response;
}
public string Response
{
get;
private set;
}
}
}
From the caller, you use it like this:
public class <TheCallingClassOutsideDLL>
{
private <TheClassInDLL> myClass;
public TheCallingClassOutsideDLL()
{
myClass = new TheClassInDLL();
myClass.DataEventCalled += DataEvent;
}
private void DataEvent(object sender, <TheClassInDLL>.MyEventArgs e)
{
Console.WriteLine(e.Response);
}
}
Of course you need to replace <TheClassInDLL> and <TheCallingClassOutsideDLL> with the real class names! Creating additional classes of course doesn't work!
For that you got to define your own event and raise it when needed...
for Example -> In the class where you set the "response" variable define an event
//your custom event
public event EventHandler<CustomEventArgs> MyCustomEvent;
//This will raise your event and notify all who registered
private void RaiseMyCustomEvent(CustomEventArgs e)
{
var handler = MyCustomEvent;
if (handler != null)
{
handler(this, e);
}
}
Maybe you will also need CustomEventArgs (used in the example above)
public class CustomEventArgs : EventArgs
{
public String Message {get;private set;}
public CustomEventArgs(String message){
this.Message = message;
}
}
The class which is using the dll and that wants to get notified needs to register for this event
YourDllClassInstance.MyCustomEvent += OnMyCustomEvent;
public void OnMyCustomEvent(object sender, CustomEventArgs e){
Console.WriteLine("Event received");
}
That means in your dll class you got to do something like the following when you want to raise the event
response = "blablabla";
RaiseMyCustomEvent(new CustomEventArgs(response);
Is that what you where asking for?
Related
Im new to programming and just wanted to know if a solution for a problem I got is appropriate.
I wanted to write a status (string) into a textbox from a class which is creating a Socket and the class listens for data to receives (in an other thread).
This is what i did:
Create the Class whithin the Form.cs with a button click:
private void button_Create_Click(object sender, EventArgs e)
{
int port;
Int32.TryParse(textBox_Port.Text, out port);
ServerSocketClass serverSocket = new ServerSocketClass(port, this);
}
The ServerSocketClass looks like:
class ServerSocketClass
{
Socket ServerSocket;
Socket Accepted;
IPEndPoint LocalEndpoint;
int Port = 1337; // just for fun
Messenger MainForm;
public ServerSocketClass(int port, Messenger form)
{
MainForm = form;
if (port != 0)
Port = port;
ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
LocalEndpoint = new IPEndPoint(IPAddress.Any, Port);
MainForm.writeToMessages("Binding Endpoint to Socket...");
ServerSocket.Bind(LocalEndpoint);
MainForm.writeToMessages("Starting ServerListener Thread...");
Thread ServerListenThread = new Thread(startListening);
ServerListenThread.Name = "ServerListenerThread";
ServerListenThread.Start();
}
private void startListening()
{
ServerSocket.Listen(5);
MainForm.writeToMessages("Whaiting for incoming connections...");
Accepted = ServerSocket.Accept();
whaitForData();
}
and to update the GUI in the forms class i created a delegate and a "update" method with an invoke:
public delegate void writeMessege(string message);
public writeMessege MessegeDelegate;
public void writeToMesseges(string messege)
{
if (InvokeRequired)
{
this.Invoke(MessegeDelegate, new object[] { messege });
return;
}
textBox_Messeges.AppendText("SYSTEM: " + messege + "\n");
}
It works, but I wanted to know if this is a "valid" way to do it or if I should go to the developer hell ;-)
thanks in advance
Locke
It's a perfectly valid way to do that, although whether it is "right" depends very much on the context - how often you call it, what you want to do inside it, and the code that you need to call it. There are many different ways of doing it without invoke, but there is nothing wrong with using InvokeRequired/Invoke - that's what it's there for. You could just use an update method that invokes itself, which is almost the same as your code, but slightly less verbose:
public void WriteMessages(string message)
{
if (InvokeRequired)
{ this.Invoke(new Action<string>(WriteMessages), new object[] { message }); }
else
{ textBox_Messages.AppendText("SYSTEM: " + message + "\n"); }
}
There are a lot of posts already on Invoke/InvokeRequired. As a starting point, check:
Isn't blindly using InvokeRequired just bad practice?
I had a similar situation, where I had a class that was called from other classes with many separate threads and I had to update one specific form from all these other threads. So creating a delegate and an event in the class with a handler in the form was the answer. So I wanted to share it as it seems simpler (even if not necessarily a better solution).
The solution that worked for me:
I created an event in the class I wanted to do the update on another form. (First of course I instantiated the form (called SubAsstToolTipWindow) in the class.
Then I used this event (ToolTipShow) to create an event handler on the form I wanted to update the label on. Worked like a charm.
I used this description to devise my own code below in the class that does the update:
public static class SubAsstToolTip
{
private static SubAsstToolTipWindow ttip = new SubAsstToolTipWindow();
public delegate void ToolTipShowEventHandler();
public static event ToolTipShowEventHandler ToolTipShow;
public static void Show()
{
// This is a static boolean that I set here but is accessible from the form.
Vars.MyToolTipIsOn = true;
if (ToolTipShow != null)
{
ToolTipShow();
}
}
public static void Hide()
{
// This is a static boolean that I set here but is accessible from the form.
Vars.MyToolTipIsOn = false;
if (ToolTipShow != null)
{
ToolTipShow();
}
}
}
Then the code in my form that was updated:
public partial class SubAsstToolTipWindow : Form
{
public SubAsstToolTipWindow()
{
InitializeComponent();
// Right after initializing create the event handler that
// traps the event in the class
SubAsstToolTip.ToolTipShow += SubAsstToolTip_ToolTipShow;
}
private void SubAsstToolTip_ToolTipShow()
{
if (Vars.MyToolTipIsOn) // This boolean is a static one that I set in the other class.
{
// Call other private method on the form or do whatever
ShowToolTip(Vars.MyToolTipText, Vars.MyToolTipX, Vars.MyToolTipY);
}
else
{
HideToolTip();
}
}
long time ago, but I wanted you all know how I finally solved this to my full satisfaction (solved it with Events - of course ;-)):
I defined an EventArgs to pass all the Information I wanted to pass:
public class IncomingMessageEventArgs : EventArgs
{
private Message _message;
public Message Message
{
get
{
return _message;
}
}
public IncomingMessageEventArgs(Message message)
{
_message = message;
}
}
On the Class that publishes the information (to the WPF - Form) define the Event and its Handler:
public delegate void IncomingMessageEventHandler(object sender, IncomingMessageEventArgs e);
public event IncomingMessageEventHandler IncomingMessageEvent;
protected void OnIncomingMessageEvent(IncomingMessageEventArgs e)
{
if (IncomingMessageEvent != null)
IncomingMessageEvent(this, e);
}
and of course Raise the event, if the WPF Form needs to be updated (also on the "information sending class"):
OnIncomingMessageEvent(new IncomingMessageEventArgs(message));
on the WPF Class you need to listen to the events but first define a EventHandler because your information comes from a differen Thread!! :
private delegate void writeMessageToChatEventHandler(object sender, IncomingMessageEventArgs e);
now we write our method witch will handle the raised event:
// Write to Chat
private void writeMessageToChat(object sender, IncomingMessageEventArgs e)
{
try
{
if (!Dispatcher.CheckAccess())
{
Dispatcher.Invoke(new writeMessageToChatEventHandler(writeMessageToChat), new object[] { sender, e } );
return;
}
textBox_Chat.AppendText(e.Message.getFormatedMessageText() + "\n");
}
catch (Exception ex)
{
writeLogToChat(this, new IncomingLogEventArgs("ERROR: " + ex.Message));
}
}
and finally, we need to subscribe to the event of course (the first method, you can ignore, its just to meet the MS Nameing conventions:
private void ClientSocket_IncomingMessageEvent(object sender, IncomingMessageEventArgs e)
{
writeMessageToChat(sender, e);
}
ClientSocket.IncomingMessageEvent += ClientSocket_IncomingMessageEvent;
Hopefully I made this understandable :P
Thanks to all the people how helped me!
bye
I am trying to catch an event raised from the Shared DLL but in a different project
To explain more , I have got a Dll lets say "Common" which I am using in two separate projects. How Can I raise Events from My Library
In my Common DLL, I have a class A
public class MyCustomEvent : System.EventArgs
{
public string MyStatement;
}
public class A
{
public delegate void MyCustomEventHandler(object sender, MyCustomEvent e);
public EventHandler<MyCustomEvent> RaiseEvent;
public void DoSomeStuff()
{
var args = new MyCustomEvent { MyStatement = "ha ha ha" };
if(RaiseEvent != null) // This is always Null
{
RaiseEvent(this, args);
}
}
};
I am using this DLL in a Winforms application & on a button click it is raising this event , Say like this.
private void button1_click(object sender, EventArgs e)
{
A a = new A();
a.DoSomeStuff();
}
Now, the same DLL is used in Different Project, where I have subscribed to this event handler
public class B
{
A aObj = new A();
public B()
{
aObj.MyCustomEvent += CatchEvent;
}
private void CatchEvent(object sender, MyCustomEvent myEvent)
{
if (myEvent != null)
{
String str = myEvent.MyStatement;
}
}
}
But while raising Event only, My event is always null as if no one is subscribed to that handler.
I have this code below:
using System;
using System.Windows.Forms;
namespace MyCode
{
public partial class Main_GUI : Form
{
//Attributes
private Processes process;
//Constructor
public Main_GUI()
{
InitializeComponent(); //a form with a button named BUTTON_Start, and a label named LABEL_log
p = new Processes();
}
//OnClickStart
private void BUTTON_Start_Click(object sender, EventArgs e)
{
try
{
LABEL_log.Text = "Started...";
p.start();
}
catch (Exception ex)
{
//do something with the exception
}
}
}//End of Class
public class Processes
{
//Constructor
public Processes() { }
//Methods
public void start()
{
try
{
//Do something
//...
//when finished send an event the Main_GUI Class (Form) in order to change the LABEL_log.Text value to "finished !"
}
catch (Exception e)
{
//do something with the exception
}
}
}
}
I ve tried a lot to create some events, I even use this example :
http://www.codeproject.com/Articles/11541/The-Simplest-C-Events-Example-Imaginable
but I cant understant how to create an event with my classes...
I such a fool I know but I really need your help !
Thanks the team !!
Regards.
FB
Define the event in the Process class:
public event EventHandler Finished;
Then in the same class define a method that raises the event "safely":
protected void RaiseFinished()
{
// Make sure the event has at least one subscriber.
if(Finished != null)
{
Finished(this, EventArgs.Empty);
}
}
You call the method where you want your event to be raised, in your case the start method:
public void Start()
{
try
{
//Do something
//...
RaiseFinished();
}
catch (Exception e)
{
//do something with the exception
}
}
Then in your Main_GUI class constructor subscribe to the event defining an handler:
//Constructor
public Main_GUI()
{
InitializeComponent(); //a form with a button named BUTTON_Start, and a label named LABEL_log
p = new Processes();
// Subscribe to the event.
p.Finished += p_Finished;
}
// This will get called when the Finished event is raised.
private void p_Finished(object sender, EventArgs e)
{
LABEL_log.Text = "Finished!";
}
Goal: To change a image on a form when either udp or tcp uses its send method
Problem: I have no idea how to get the event, eventhandler and delegates set up correctly
Send Interface
interface ISendData
{
void Send();
}
Tcp Connection class
//Need some type of delegate??
public class TCPconnection : ISendData
{
void Send()
{
//how invoke/fire a send Event?
}
}
UDP Connection class
//Need some type of delegate??
public class UDPConnection : ISendData
{
void Send()
{
//how invoke/fire a send event?
}
}
the winform which 'should' subscribe to seeing the fired events
public class myForm
{
private DataWatcher datawatcher = new DataWatcher();
private Image statusIndicator = null;
public myform()
{
initComponents();
datawatcher.DataSendActive += new DataWatcherSendHandler(DataSending);
datawatcher.DataSendInactive += new DataWatcherSendHandler(NoDataSending);
}
public void DataSending(object sender, DataWatcherArgs e)
{
statusIndicator = Properties.resources.greenLight;
}
public void NoDataSending(object sender, DataWatcherArgs e)
{
statusIndicator = Properties.resources.redLight;
}
}
The Event/Event handler?? But I really have no Idea what I'm doing here to make this work
public delegate void EventHandler(object sender, EventArgs e);
class DataWatcher
{
public event EventHandler DataSendActive;
public event EventHandler DataSendInactive;
protected virtual void onDataSendActive(System.EventArgs e)
{
if (DataSendActive != null)
{
DataSendActive(this, e);
}
}
protected virtual void onDataSendInactive(System.EventArgs e)
{
if (DataSendInactive != null)
{
DataSendInactive(this, e);
}
}
}
There are many conventions used to do this. Here's my little implementation.
public enum ActivityState
{
Sending,
Receiving,
Idle
}
public interface IDataTransferManager
{
// This event will fire when the activity state changes.
// note that Action<T> is introduced in .NET 3.5
// if you're using .NET 2.0, you can use a delegate.
event Action<ActivityState> DataActivityStateChange;
void Send(byte[] data);
//byte[] Receive();
// ... more methods ... //
}
Now the TcpConnection class will implement this.
public class TcpConnection : IDataTransferManager
{
public event Action<ActivityState> DataActivityStateChange;
public void Send(byte[] data)
{
// we're sending data. fire the change event
FireDataActivityStateChange(ActivityState.Sending);
//TODO: send the data
// we're done sending. Fire the change event
FireDataActivityStateChange(ActivityState.Idle);
}
private void FireDataActivityStateChange(ActivityState state)
{
// helper method, so I don't have to check the event
// to avoid null reference exceptions.
if (DataActivityStateChange != null)
DataActivityStateChange(state);
}
}
Here's the setup for your Form.
class MyForm // :Form
{
IDataTransferManager dataManager;
public MyForm()
{ // here, usually an instance will be passed in,
// so there's only one instance throughout the application.
// let's new up an instance for explanation purposes.
dataManager = new TcpConnection();
dataManager.DataActivityStateChange += (state) =>
{
// NOTE: if you don't like inline,
// you can point this labda to a method.
switch (state)
{
case ActivityState.Sending:
// change the image to the spinning toilet ball
break;
case ActivityState.Receiving:
// change the image to the spinning toilet ball, but reverse :P
break;
case ActivityState.Idle:
// hide it ?
break;
}
};
}
}
Here is a simple example of how you could implement an event for sending and not sending and subscribe to it
public class Connection
{
//Set up an event
public event EventHandler DataSending;
public event EventHandler DataNotSending
//This method will trigger the event for sending
private void OnDataSending()
{
if (DataSending!= null) { DataSending(this, EventArgs.Empty); }
}
//this method will trigger the event for finished sending
private void OnDataNotSending()
{
if (DataNotSending!= null) { DataNotSending(this, EventArgs.Empty); }
}
//This method performs your send logic
public void Send()
{
//Call your method that tells the event to be raised
OnDataSending();
//Then put your send code
OnDataNotSending(); //we're done!
}
}
This is how you use it in a consuming program
public class myForm
{
//This method is the one that sets up the
//instance and subscribes to the event
public myForm()
{
Connection con = new Connection();
con.DataSending += new EventHandler(con_DataSending);
con.DataNotSending += new EventHander(con_DataNotSending);
}
void con_DataSending(object sender, EventArgs e)
{
//Put your subscription logic here.
//Whatever you want to do in response to a send
}
void con_DataNotSending(object sender, EventArgs e)
{
//Put your subscription logic here.
//Respond to it not sending
}
}
I have a repository that uses components that report events.
I want to show the reported events in the front end.
This is the repository:
public interface IXmlRepository
{
//irrelevant stuff removed
event EventHandler TraceEventHandler;
}
public class XmlPanelRepository : IXmlRepository
{
public XmlPanelRepository()
{
public event EventHandler TraceEventHandler;
var panelCom = new PanelCom(); // this is a COM object that connects to a device
// when something happens in the COM object it reports it.
panelCom.Trace += panelCom_Trace;
// I want to bubble the trace events up to my UI.
TraceEventHandler += TraceEventHandler_Tracing;
}
private void TraceEventHandler_Tracing(object sender, EventArgs e)
{
// what do I do here?
}
void panelCom_Trace(string message)
{
if (TraceEventHandler!= null) TraceEventHandler.Invoke(this, new EventArgs());
}
}
My UI uses a Service to interface with the repository. The service is defined as:
public interface IXmlConfigurationService
{
//irrelevant stuff removed
event EventHandler TraceEventHandler;
}
public class XmlConfigurationService : IXmlConfigurationService
{
public event EventHandler TraceEventHandler;
public XmlConfigurationService(IXmlRepository configurationRepository)
{
_configurationRepository.TraceEventHandler += ConfigurationRepository_TraceEventHandler;
}
void ConfigurationRepository_TraceEventHandler(object sender, EventArgs e)
{
// this never gets hit.
if (TraceEventHandler != null) TraceEventHandler.Invoke(sender, e);
}
}
If I can get this working, I presume I can follow the same steps to get the UI displaying event reports.
How can I get the Service to report the events that are occurring in the repository?
If I understand correctly, you would need to fulfil your event. This is akin to the Observable fulfilling all listening observers in the Observer Pattern. But for events written like this:
public XmlPanelRepository()
{
public event EventHandler TraceEventHandler;
var panelCom = new PanelCom(); // this is a COM object that connects to a device
// when something happens in the COM object it reports it.
panelCom.Trace += panelCom_Trace;
// I want to bubble the trace events up to my UI.
TraceEventHandler += TraceEventHandler_Tracing;
}
private void TraceEventHandler_Tracing(object sender, EventArgs e)
{
if (TraceEventHandler != null)
{
TraceEventHandler(this, e);
}
}
However, perhaps you should name the event something other than TraceEventHandler because you are now exposing an event (which usually is expressed in the past tense).
It is also worth noting that you can potentially change the event args as you bubble up (if you want to). EventHandler(TEventArgs) can help with this.
You're forgetting to use delegates...
Try something like this:
public interface IXmlRepository
{
//irrelevant stuff removed
event EventHandler TraceEventHandler;
}
public class XmlPanelRepository : IXmlRepository
{
public delegate void EventHandler(string parameter1, string parameter2);
public event EventHandler TraceEventHandler;
public XmlPanelRepository()
{
var panelCom = new PanelCom(); // this is a COM object that connects to a device
// when something happens in the COM object it reports it.
panelCom.Trace += panelCom_Trace;
}
void panelCom_Trace(string message)
{
if (EventHandler != null)
EventHandler("Event was hit, here's the message:", message);
}
}
public interface IXmlConfigurationService
{
//irrelevant stuff removed
}
public class XmlConfigurationService : IXmlConfigurationService
{
public XmlConfigurationService(IXmlRepository configurationRepository)
{
_configurationRepository.TraceEventHandler += ConfigurationRepository_EventHandler;
}
void ConfigurationRepository_EventHandler(string parameter1, string parameter2);)
{
// Do something with your parameters.
Response.Write(parameter1 + parameter2);
}
}