EventHandlers & Multiple Class Instance & Overlapping variables C# - c#

For multiple instances, when event handlers are declared like below, do they tend to overlap and set all the instances of a variables
For say,
Something class = new Something();
is declared ~ 3 times and on all 3 times, the eventhandlers are declared and used.
public class something
{
public string str = "1";
public string str2 = "2";
public void onconnect(object sender, ConnectedEventArgs e)
{
if (e.Connected)
{
this.ses = e.NetworkSession;
this.ses.OnHandshakeHandler += new EventHandler<HSEventArgs>(OnHandshakeHandler);
this.ses.onreceive+= new EventHandler<PEventArgs>(onreceive);
return;
}
}
}
now lets say
public void onreceive(object sender, PEventArgs e)
{
str = "3";
}
Would str all be turned to "3" onrecieve? Because in my case, i'm starting to believe the eventhandler is shared between all instances of the class. Therefore rendering all variables in all instances of the class to be the same.
If this is not the case, could eventhandlers be the reason behind why my variables are all getting changed by the same event raised?
If so, how would you isolate the class and assign the handler to each individual class?
onconnect is called by
public void Connect(string ip, short port)
{
try
{
this.connector = new Connector();
this.connector.OnClientConnected += new EventHandler<ConnectedEventArgs>(onConnect);
this.connector.Connect(ip, port); //Logs into server
}
catch
{
updateLog("[Error]Servers exploded!!!", this);
}
}
and ^ is called when a button is pushed on a gui

If I read the documentation correctly (http://msdn.microsoft.com/en-us/library/bb975820.aspx) there will be one NetworkSession per user. You are one user, so you have one NetworkSession.
You created three instances of Something, and I get the feeling they are all called by the same event: the software os connected to the game network.
All 3 onconnect methods get in e the same instance of NetworkSession and you connect your eventhanlder onreceive to NetworkSession.onreceive.
So if the NetworkSession receives something, all the 3 eventhandlers of your 3 instances are called.
The creating a seperate NetworkSession per instance by using NetworkSession.BeginCreate (http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.net.networksession.begincreate.aspx).

Related

Need to implement "Scan" method in dll (non blocking)

Sorry for the title, i didn't find it easy to resume.
My issue is that I need to implement a c# dll that implements a 'scan' method, but this scan, when invoked, must not block the main thread of the application using the dll. Moreover, it is a duty that after the scan resolves it rises an Event.
So my issue (in the deep) is that i'm not so experienced at c#, and after very hard investigation i've come up with some solutions but i'm not very sure if they are the "right" procedures.
In the dll i've come up with:
public class Reader
{
public delegate void ReaderEventHandler(Object sender, AlertEventArgs e);
public void Scan(String ReaderName)
{
AlertEventArgs alertEventArgs = new AlertEventArgs();
alertEventArgs.uuiData = null;
//Code with blocking scan function here
if (ScanFinnished)
{
alertEventArgs.uuiData = "Scan Finnished!";
}
alertEventArgs.cardStateData = readerState[0].eventState;
ReaderEvent(new object(), alertEventArgs);
}
public event ReaderEventHandler ReaderEvent;
}
public class AlertEventArgs : EventArgs
{
#region AlertEventArgs Properties
private string _uui = null;
private uint cardState = 0;
#endregion
#region Get/Set Properties
public string uuiData
{
get { return _uui; }
set { _uui = value; }
}
public uint cardStateData
{
get { return cardState; }
set { cardState = value; }
}
#endregion
}
While in the main app I do:
Reader reader;
Task polling;
String SelectedReader = "Some_Reader";
private void bButton_Click(object sender, EventArgs e)
{
reader = new Reader();
reader.ReaderEvent += new Reader.ReaderEventHandler(reader_EventChanged);
polling = Task.Factory.StartNew(() => reader.Scan(SelectedReader));
}
void reader_EventChanged(object sender, AlertEventArgs e)
{
MessageBox.Show(e.uuiData + " Estado: " + e.cardStateData.ToString("X"));
reader.Dispose();
}
So here, it works fine but i don't know if it's the proper way, in addition i'm not able to handle possible Exceptions generated in the dll.
Also tried to use async/await but found it difficult and as I understand it's just a simpler workaround Tasks.
What are the inconvinients of this solution? how can i capture Exceptions (are they in other threads and that's why i cant try/catch them)? Possible concept faults?
When your class sends events, the sender usually is that class, this. Having new object() as sender makes absolutely no sense. Even null would be better but... just use this.
You shouldn't directly raise events as it might result in race conditions. Might not happen easily in your case but it's just a good guideline to follow. So instead of calling ReaderEvent(new object(), alertEventArgs); call RaiseReaderEvent(alertEventArgs); and create method for it.
For example:
private void RaiseReaderEvent(AlertEventArgs args)
{
var myEvent = ReaderEvent; // This prevents race conditions
if (myEvent != null) // remember to check that someone actually subscribes your event
myEvent(this, args); // Sender should be *this*, not some "new object()".
}
Though I personally like a bit more generic approach:
private void Raise<T>(EventHandler<T> oEvent, T args) where T : EventArgs
{
var eventInstance = oEvent;
if (eventInstance != null)
eventInstance(this, args);
}
Which can then be used to raise all events in same class like this:
Raise(ReaderEvent, alertEventArgs);
Since your scan should be non-blocking, you could use tasks, async/await or threads for example. You have chosen Tasks which is perfectly fine.
In every case you must understand that when you are not blocking your application, your application's main thread continues going like a train. Once you jump out of that train, you can't return. You probably should declare a new event "ErrorEvent" that is raised if your scan-procedure catches an exception. Your main application can then subscribe to that event as well, but you still must realize that those events are not (necessarily) coming from the main thread. When not, you won't be able to interact with your GUI directly (I'm assuming you have one due to button click handler). If you are using WinForms, you'll have to invoke all GUI changes when required.
So your UI-thread safe event handler should be something like this:
void reader_EventChanged(object sender, AlertEventArgs e)
{
if (InvokeRequired) // This true for others than UI Thread.
{
Invoke((MethodInvoker)delegate
{
Text = "My new title!";
});
}
else
Text = "My new title!";
}
In WPF there's Dispather that handles similar invoking.

Understanding Delegates & Callbacks

Using this C# TCP Server example within a Unity project
https://www.codeproject.com/articles/488668/csharp-tcp-server
The notes mention There are 3 callback events OnConnect, OnDataAvailable and OnError.
There are 2 callback examples with the following signatures
private void tcpServer1_OnDataAvailable(tcpServer.TcpServerConnection connection)
Do I need to do anything special or in addition to enable these callbacks or is tcpServer1_OnDataAvailable consdiered a reserved handler name that is automatically called?
TcpServer tcpServer1 = new TcpServer(); //in constructor (auto added if added as a component)
private void openTcpPort(int port)
{
tcpServer1.Port = port;
tcpServer1.Open();
}
private void closeTcpPort()
{
tcpServer1.Close();
}
You'll need to register the event handlers delegates to the specific events.
TcpServer tcpServer1 = new TcpServer();
// register event handler
tcpServer1.OnDataAvailable += tcpServer1_OnDataAvailable;
private void tcpServer1_OnDataAvailable(tcpServer.TcpServerConnection connection)
{
// do work
}
Callbacks are methods that are called when an event you are interested in occurs. You do in fact need to set them up, like this:
tcpServer1.OnConnect += serverConnection =>
{
//code to do stuff when a connection happens goes here
}
tcpServer1.OnDataAvailable += serverConnection =>
{
//code to do stuff when data is available here
}
tcpServer1.OnError += serverConnection =>
{
//code to do stuff when an error happens here
}
You should put this code in the constructor, after the point in time when tcpServer1's variable is instantiated with operator new.

Indexer created to look at array doesn't see changes made to array

I am very new to c#, and I'm creating a serial port class for a board I have designed. In which this class contains methods to open/close a serial port connected to the board. It should also read messages from the board and write messages from the UI to the board (I am using a forms application to input and display values).
I read the internal input buffer and place the bytes into my own software buffer, when a message is complete, this will prompt the form to analyse the message...
For this I have created an indexer to point to the array (from the form) and take the bytes that it desires.
uint[] serialPortReceiveBuffer = new uint[3];
public delegate void Del();
Del promptFormAction = Form1.MsgReceived;
public void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
for (int i = 0; i <= 2; i++)
{
serialPortReceiveBuffer[i] = (uint)serialPort1.ReadByte();
}
promptFormAction();
}
public uint this[uint i]
{
get { return serialPortReceiveBuffer[i]; }
}
this is the code within my pcbSerialPort class, and the code related to it in the Form1 class is as follows:
public static void MsgReceived()
{
Form1 _frm = new Form1();
_frm.analyzeIncomingMessage();
}
public void analyzeIncomingMessage()
{
if (PCB[0] == 63)
{
setBoardDesignator(PCB[1], PCB[2]);
}
}
My problem is that the when I use the indexer to access the serialPortReceiveBuffer, it doesn't see the changes that I made to it when placing received bytes into the same array. For example, when I receive a string of my own protocol --> "?10" the buffer is filled with [63][49][48]
Though when I try to access this buffer using the indexer I get [0][0][0]
Please can anyone help? Also, I'm aware there is probably a few other things I could have done better so if you have any general tips that would be great. Also in a language I may understand. I am just getting my head around many of the c# aspects, I have been doing embedded software for the past year but I wouldn't consider my self to be a competent programmer.
Thank you
From your code I'm not quite sure that the PCB object you're working with in your form is actually the one that receives the data. Might well be that you're working with two different instances, especially as you're creating a new instance of Form1 whenever data comes in!
(EDIT: From your comment to the question it is clear that this is exactly the problem. Follow these instructions to get closed to what you want).
I suggest that you redesign your code to pass the received message as an event to the existing form instance instead of how you do it now. Another problem you might run into will be that data you think you get will be overridden by the next message coming in, das the DataReceived event is asynchronous.
I'd declare an event that the form instance can subscribe to, passing the data to be analyzed into the event:
public class MessageReceivedEventArgs: EventArgs
{
public MessageReceivedEventArgs(byte[] data) : base()
{
Data = data;
}
public byte[] Data
{
get;
private set;
}
}
public event EventHandler<MessageReceivedEventArgs> MessageReceived;
Then, I'd change your DataReceivedevent as follows:
public void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
for (int i = 0; i <= 2; i++)
{
serialPortReceiveBuffer[i] = (uint)serialPort1.ReadByte();
}
byte[] dataCopy = new byte[serialPortReceiveBuffer.Length];
Array.Copy(serialPortReceiveBuffer, dataCopy, dataCopy.Length);
promptFormAction(dataCopy);
}
private void promptForAction(byte[] data)
{
if (MessageReceived != null)
MessageReceived(this, new MessageReceivedEventArgs(data));
}
Also I'd keep the serialPortReceiveBuffer totally private to that class, as I said, you may run into synchronization issues if you don't. That'y why I copy the array before passing it to the event.
This change allows any subscriber to register for notifications whenever you realize that new data came in.
To use this, Form1 should look like this (roughly);
public class Form1
{
pcbSerialPort PCB; // The name of that class I don't know from your code
public Form1()
{
PCB = new pcbSerialPort();
PCB.MessageReceived += MessageReceived;
}
private void MessageReceived(object sender, pcbSerialPort.MessageReceivedEventArgs e)
{
analyzeIncomingMessage(e.Data);
}
private void analyzeIncomingMessage(byte[] data)
{
if (data[0] == 63)
{
setBoardDesignator(data[1], data[2]);
}
}
}
Another piece of advice on how you handle serial data: You need to decide whether you read from a serial port in a loop or whether you rely on the DataReceived event. Putting a loop into the event is not a good idea, as the event may be called upon arriving data again while you're waiting.
What you need to do is create a buffer that takes all the information from the serial port that's available. If you don't have enough data, don't wait for it. Instead add to the buffer whenever DataReceived is called and handle a message when enough data is present.
I think Thorsten's answer is good and it would make a lot of sense to redesign it along those lines, but as an absolute minimum, if you want to have it such that you create a new Form1 instance for every received message, then you will need to pass the instance of pcbSerialPort to MessageReceived and then to the constructor of your Form1 class. Something like:
Action<pcbSerialPort> promptFormAction = Form1.MsgReceived;
public void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
// as Thorsten noted, you need to rethink this loop anyway
// what if there aren't at least three bytes to read?
for (int i = 0; i <= 2; i++)
{
serialPortReceiveBuffer[i] = (uint)serialPort1.ReadByte();
}
promptFormAction(this);
}
And your static method:
public static void MsgReceived(pcbSerialPort pcb)
{
Form1 _frm = new Form1(pcb);
_frm.analyzeIncomingMessage();
}
And you constructor for Form1:
public Form1(pcbSerialPort pcb)
{
PCB = pcb;
}

How to return data from void function?

So, around a week ago I asked a question about activex and UDP. Here it is:
C# UDP Socket client and server
Now, I created two applications, one (the sender) to send pre-defined strings via UDP. The other is activex component that is called from a webpage, and it's thread is working in the background. Once an UDP message arrives, then it's doing it's stuff (writing in database, writing in log.txt, and so on).
The last thing i need is to return data (it's yet to be said if it will be string or something else). However, the method in the activex which is called must be a void, because if it's made to be string, the threading wont work, and only the first message will arrive.
My question is, how to do that? How to return data from a void function? For example, the web app now is calling the activex DLL like this:
ClassLibrary1.Class1 activex = new ClassLibrary1.Class1();
activex.StartThread();
And the StartThread() calls the listening thread and it's working in the background, and once UDP msg arrives, its doing some stuff like i said above.
How can i return value with the threads (events) and the web app will catch it and use it?
Thanks a lot.
You can use events (which implement the Observable pattern) to alert any listener that a new message has arrived:
public class NewMessageArgs : EventArgs
{
public string Message { get; private set; }
public NewMessageArgs(string message)
{
Message = message;
}
}
public class ActiveXComponent
{
public event EventHandler<NewMessageArgs> OnMessage;
public void StartThread()
{
while (true)
{
//do stuff
//raise "message received" event
if (OnMessage != null)
OnMessage(this, new NewMessageArgs("hi"));
}
}
}
You can then listen to these events like so:
ActiveXComponent activex = new ActiveXComponent();
activex.OnMessage += ProcessMessage;
activex.StartThread();
public void ProcessMessage(object sender, NewMessageArgs args)
{
var msg = args.Message;
//process
}
Basically you have to store some data in a spot where you can access it from both places (from the thread, and from the place where you started the thread). So you have a couple of options from the top of my head.
Store it in a database
Create a specific object (whatever type you need), and store it in a place where it is accessible from both places. For example, a singleton. A simpler better solution is to create a property on your ClassLibrary.Class1 class: set it from within the Class1-class, and get it from the place where you created an instance of your Class1-class.
Add an event to your Class1-class which fires when it is finished doing its job. And add some data to the EventArgs.
I'm assuming here you get notified when your thread is done doing whatever it is doing.
Edit: added events
The threading function can change the fields values of the class and you can access those fields, also your thread can fire events that other classes can subcribe to and then act on it.
Class1
{
private string value;
public string Value{get{return value;} set{value=value; FireTheEvent();}}
}

How to change an event handler callback dynamically

I've a serial port communication class which has the following code inside (among others but only the relevant part is shown):
public Form1 m_parent;
private delegate void ProcessPacketDelegate(byte[] packet);
public SerialPort comPort = new SerialPort();
//Constructor code
....setting baudrate, portname etc.
... setting m_parent as the main form
...setting other things
//add an event handler
comPort.DataReceived += new SerialDataReceivedEventHandler(comPort_DataReceived);
//constructor code end
void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int bytes = comPort.BytesToRead;
byte[] comBuffer = new byte[bytes];
comPort.Read(comBuffer, 0, bytes);
comPort.DiscardInBuffer();
m_parent.Invoke(new ProcessPacketDelegate(m_parent.ProcessPacket), comBuffer);
}
I'm instantiate this class from my main form, which address is stored in m_parent. The main form has a method called ProcessPacket, which processes the incoming packet. So far so good.
Now, I want to handle 2 serial ports so I need 2 instances of this class. However, I don't want them to use the same ProcessPacket method which could lead to packet collisions. I'd like to modify the serial port communication class in such way that in the constructor or by getsets I'd set callback method dynamically so instance #1 would invoke m_parentProcessPacket_A, instance #2 would invoke m_parentProcessPacket_B. Unfortunately this seems to be beyond my .NET skills, so any help would be great!
Thank you!
You can define a variable in constructor and use that.
if(condition)
handler = comPort_DataReceived;
else
handler = comPort_SomeElseMethod;
And then bind this
comPort.DataReceived += handler
Have a constructor like that:
YourClass(ProcessPacketDelegate process_packet)
{
// ...
this.process_packet = process_packet;
}
In your class, have also:
ProcessPacketDelegate process_packet;
Then in your comPort_DataReceived do:
m_parent.Invoke(this.process_packet, comBuffer);
In you main form when your instantiating your class do:
instance1 = new YourClass(new ProcessPacketDelegate(this.ProcessPacket_A));
instance2 = new YourClass(new ProcessPacketDelegate(this.ProcessPacket_B));

Categories