using delegate to send string - c#

I'am having a very annoying problem in my code, when I try to send a string from Form B to form a. I get the error message:
Object reference not set to an instance of an object.
I'am familiar with this error and normally I know how to solve this problem, but this one is different.
I need to send a Clockname from one form to the main form, I'am trying to achieve this using the code below:
delegate void ClockClocknameReceivedEventHandler(object sender, Clock.ClocknameReceivedEventArgs e);
internal class ClocknameReceivedEventArgs : EventArgs
{
string _clockname;
public string Clockname
{
get { return _clockname; }
}
public ClocknameReceivedEventArgs(string clockname)
{
_clockname = clockname;
}
}
// An event that clients can use to be notified whenever the
// elements of the list change.
public event ClockClocknameReceivedEventHandler ClocknameReceived;
// Invoke the Changed event; called whenever list changes
protected void OnClocknameReceived(Clock.ClocknameReceivedEventArgs e)
{
ClocknameReceived(this, e);
}
And the following code gets fired when pressing a button, the form will close after that:
OnClocknameReceived(new Clock.ClocknameReceivedEventArgs(ClockName));
The error(Object reference not set to an instance of an object.) I receive occurs at
ClocknameReceived(this, e);
I'am using the exact same code, from another class to the main form to send a byte array which works fine, but this one give me that error.
Anyone any ideas?
Thanks in advance!

The delegate can be null. Invoke it only if it's not null:
protected void OnClocknameReceived(Clock.ClocknameReceivedEventArgs e)
{
ClockClocknameReceivedEventHandler handler = ClocknameReceived;
if (handler != null)
{
handler(this, e);
}
}
The delegate is null when you haven't subscribed an event handler to the event yet. Subscribe an event handler:
formB.ClocknameReceived += FormB_ClocknameReceived;
with
void FormB_ClocknameReceived(object sender, Clock.ClocknameReceivedEventArgs e)
{
MessageBox.Show(e.Clockname);
}

Your not checking whether the ClocknameReceived event has been assigned (i.e. has any subscribers). Typical event handling code generally looks like:
var handler = ClocknameReceived;
if (handler != null)
{
handler(this, e);
}
This type of approach also mitigates (to an extent) race conditions with your event handler as it could be unassigned by the time you go to trigger it.
Looking at your code you could definitely tidy this up a bit. For one, your EventArgs class could be re-written with less code:
internal class ClocknameEventArgs : EventArgs
{
public ClockNameEventArgs(string name)
{
Name = name;
}
public string Name { get; private set; }
}
Then in your form, there's no need for a delegate if you have a particular type of EventArgs, your event can be declared as:
public event EventHandler<Clock.ClocknameEventArgs> ClocknameReceived;
You then hook up to this event somewhere (maybe in the FormCreate event?):
ClocknameReceived += (sender, args) {
FormB.PassName(args.Name);
};

You have to check if the event has a delegate or not
if( ClocknameReceived != null)
ClocknameReceived(this, e);

Related

C# "System.StackOverflowException:" when assigning event handler

I have an initialization routine called from the Form's Show event.
When the initialization is done, it fires an Initialized event.
In this event I assign the event handlers to the initialized objects. But as soon I try to assign this event, I get "System.StackOverflowException:". I have put a break point in the event to see if it was called recursively, but it isn't.
SCD.OCV.OnCard += OCV_OnCard;
The event handler in the SCD.OCV.OnCard is defined like this in the TOCV class:
public class CardEventArgs : EventArgs
{
public CardEventArgs(TCard card, ECardStatus status)
{
Card = card;
Status = status;
}
public ECardStatus Status { get; }
public TCard Card { get; }
}
public event CardHandler OnCard;
public delegate void CardHandler(object sender, CardEventArgs e);
protected virtual void FireCard(CardEventArgs e)
{
OnCard?.Invoke(this, e);
}
The event handler I try to assign is defined like this:
private void OCV_OnCard(object sender, TOCV.CardEventArgs e)
{
BeginInvoke((Action)delegate
{
});
}
And now to the assignment where all crash:
SCD.OCV.OnCard += OCV_OnCard; // Here I get the StackOverflowException
C# is not my major programming language (I'm more familiar with C/C++) so I'm not 100% sure if all is done correctly.
[EDIT]
Managed to track down the issue. It was a third party C/C++ DLL not terminating a string correctly. Hence a char* went wild in the memory.

Null Reference Exception When Raising Event in C#

What would be the equivalent C# code against following VB.Net code:
Public Event EndOfVideo()
Private Sub RaiseEndOfVideo()
RaiseEvent EndOfVideo()
End Sub
EDIT
Here is the equivalent C# code that telerik converter generated for me.
public event EndOfVideoEventHandler EndOfVideo;
public delegate void EndOfVideoEventHandler();
private void RaiseEndOfVideo()
{
if (EndOfVideo != null) {
EndOfVideo();
}
}
Calling RaiseEndOfVideo doesn't trigger/invoke EndOfVideo event, and Null Reference Exception is raised.
Consider you have class VideoPlayer which has event EndOfVideo and you want to raise this event and when someone calls method EndVideo on object of VideoPlayer.
Now, like any other member of a class event also initialized to null and gets the value when some handler is attached to it.
Attaching an handler to an event happens using += operator.
public class VideoPlayer
{
public event EndOfVideoEventHandler EndOfVideo;
// Following delegate indicates that the a method accepting no parameter
// and returning void can be attached as an handler to this event.
public delegate void EndOfVideoEventHandler();
public void EndVideo()
{
RaiseEndOfVideo();
}
private void RaiseEndOfVideo()
{
if (EndOfVideo != null)
{
// Following line of code executes the event handler which is
// attached to the event.
EndOfVideo();
}
}
}
public class WebPage
{
public void VideoStopped()
{
Console.WriteLine("Video Stopped");
}
}
Now in Main method of program.cs
static void Main(string[] args)
{
VideoPlayer player = new VideoPlayer();
WebPage page = new WebPage();
player.EndOfVideo += page.VideoStopped;
// Following method call on player object will call internally
// RaiseEndOfVideo which will Raise event and event will execute
// VideoStopped method of page object which is attached in previous line
// and display "Video Stopped" message in Console.
player.EndVideo();
Console.WriteLine("Completed!!! Press any key to exit");
Console.ReadKey();
}
I hope this would help you start understanding how events and delegates work in C#. For further reading you can go thru https://msdn.microsoft.com/en-us/library/edzehd2t(v=vs.110).aspx
This is the generally accepted way to write an event with no parameters:
public class Foo
{
public event EventHandler EndOfVideo;
protected virtual void OnEndOfVideo()
{
var handler = EndOfVideo;
if (handler != null)
handler(this, EventArgs.Empty);
}
}
Your code is what was needed in the old days: creating a delegate and yada yada.
To state the obvious, though, you need to subscribe to an event with something like:
public class Bar
{
public void DoAllTheThings()
{
var foo = new Foo();
foo.EndOfVideo += foo_EndOfVideo;
}
void foo_EndOfVideo(object sender, EventArgs e)
{
Console.WriteLine("EndOfVideo");
}
}
For the sake of completeness, the EventHandler delegate has a generic counterpart, EventHandler<T>, which you would use when you want an event that does have parameters, where T should be a class inheriting from System.EventArgs which holds the information you want your event to expose.
To do that, you will need to create a custom eventHandler to specify the method signatures of the handlers for your event

Adding events to a class using +=

Please forgive my little knowledge!
I have the following class in HIDNewDeviceEventMonitor.cs:
public class HIDNewDeviceEventMonitor : IDisposable
{
// used for monitoring plugging and unplugging of USB devices.
private ManagementEventWatcher watcherAttach;
public HIDNewDeviceEventMonitor()
{
// Catch USB HID plugged instance event watching
watcherAttach = new ManagementEventWatcher();
watcherAttach.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
watcherAttach.Query = new WqlEventQuery(#"SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_PNPEntity' AND TargetInstance.DeviceID LIKE 'HID\\VID_04D8%'");
watcherAttach.Start();
}
void watcher_EventArrived(object sender, EventArrivedEventArgs e)
{
Debug.WriteLine("my device is inserted..");
}
public void Dispose()
{
watcherAttach.Stop();
watcherAttach.Dispose();
}
~HIDNewDeviceEventMonitor()
{
this.Dispose();
}
}
Now, how can I change this class to be able to add an event handler that the class can call from within watcher_EventArrived where someNewEvent is outside the class file, actually in the form.cs:
// code in the form
HIDNewDeviceEventMonitor ok = new HIDNewDeviceEventMonitor();
ok.Inserted += someNewEvent; // <-- my problem, I don't know how to add an event to the class this way
private void someNewEvent()
{
//Enumerate and add to listbox1
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
ok.Dispose();
}
I 've seen this thing with other classes, how can I make my class like that?
Your Inserted event should look like this:
public event EventHandler Inserted;
You invoke it like this:
private void OnInserted()
{
if (this.Inserted != null)
{
this.Inserted(this, EventArgs.Empty);
}
}
The signature for the event handler is this:
void someNewEvent(object sender, EventArgs e)
{
//
}
Then you should wrap that code in the constructor of the class:
HIDNewDeviceEventMonitor ok;
public ClassName()
{
ok = new HIDNewDeviceEventMonitor();
ok.Inserted += someNewEvent; // <-- my problem
}
Declare the ok variable outside the constructor, and instantiate it inside. Then add the event handler.
Pro tip: You could use the generic EventHandler<T> if you need to supply a custom implementation of e.
Simply put, you're trying to add events to your HIDNewDeviceMonitor class.
To do this, first you'll need to define a delegate.
public delegate void InsertedHandler;
Next, you'll need to define the event in your HIDNewDeviceMonitor class.
// Notice how the event uses the delegate that's been defined
// v
public event InsertedHandler Inserted;
Now you'll need something that "fires" the event, which could easily be put in your watcher_EventArrived method.
void watcher_EventArrived(object sender, EventArrivedEventArgs e)
{
Debug.WriteLine("my device is inserted..");
// Notice how we check the event handler for null.
// If you don't, it could throw a NullReferenceException.
// Irritating, but easy to debug.. Usually..
if (Inserted != null)
Inserted(); // Or whatever parameters you need.
}
We're all done with the HIDNewDeviceMonitor class.
Now whatever class that uses the HIDNewDeviceMonitor can use the EventHandler code that you provided.
However, it'll have to be the same delegate.
public class MyClass
{
HIDNewDeviceMonitor monitor;
public MyClass()
{
monitor = new HIDNewDeviceMonitor();
monitor.Inserted += DeviceInserted;
}
private void DeviceInserted()
{
// Execute code here
}
}
You need to do following in the HIDNewDeviceEventMonitor class:
1.) First define a public event inside the class like this-
public event EventHandler Inserted;
2.) Then fire this event within the code where you detect the changes in events. Like this-
if(Inserted != null)
Inserted(this,null);
The if condition checks if the event is registered by any listener. It's fired in case it is.
Hope this helps.

CA1009: Declare event handlers correctly?

I have the following event that consumers of my class can wire up with to get internal diagnostic messages.
public event EventHandler<string> OutputRaised;
I raise the event with this function
protected virtual void OnWriteText(string e)
{
var handle = this.OutputRaised;
if (handle != null)
{
var message = string.Format("({0}) : {1}", this.Port, e);
handle(this, message);
}
}
Why am I getting CA1009 Declare event handlers correctly? All the answers I found don't seem really applicable to my scenario... Just trying to understand, I don't have a real solid grasp of events and delegates yet.
Reference on CA1009: http://msdn.microsoft.com/en-us/library/ms182133.aspx
According to 'the rules', the type-parameter of EventHandler should inherit from EventArgs:
Event handler methods take two parameters. The first is of type
System.Object and is named 'sender'. This is the object that raised
the event. The second parameter is of type System.EventArgs and is
named 'e'. This is the data that is associated with the event. For
example, if the event is raised whenever a file is opened, the event
data typically contains the name of the file.
In your case, that could be something like this:
public class StringEventArgs : EventArgs
{
public string Message {get;private set;}
public StringEventArgs (string message)
{
this.Message = message;
}
}
and your eventhandler:
public event EventHandler<StringEventArgs> OutputRaised;
When you raise the event, you should offcourse create an instance of the StringEventArgs class:
protected virtual void OnWriteText( string message )
{
var handle = this.OutputRaised;
if (handle != null)
{
var message = string.Format("({0}) : {1}", this.Port, e);
handle(this, new StringEventArgs(message));
}
}
I also would like to add, that theoretically, there's nothing wrong with your code. The compiler doesn't complain and your code will work. The EventHandler<T> delegate does not specify that the type parameter should inherit from EventArgs.
It's FxCop that signals that you're violating the 'design rules' for declaring an event.
Events in .NET should usually contain some derivative of EventArgs which yours does not so I'd guess that's the problem.
Define the event args to be published by the event:
public class StringEventArgs : EventArgs
{
public StringEventArgs(string message) { this.Message = message; }
public string Message { get; private set; }
}
Change your Event declaration and publish method:
public event EventHandler<StringEventArgs> OutputRaised;
protected virtual void OnWriteText(string e)
{
var handle = this.OutputRaised;
if (handle != null)
{
var message = string.Format("({0}) : {1}", this.Port, e);
handle(this, new StringEventArgs(message));
}
}

What will be displayed by the MessageBox?

I Have Code for EventHandler like this below.
I do not know what is meant by e.Value, can someone explain and show approximately what will be displayed by the MessageBox?
void ConnectionManager_Error(object sender, EventArgs<string> e)
{
BeginInvoke((MethodInvoker)delegate()
{
State = ConnectState.NotFound;
MessageBox.Show(e.Value);
});
}
Note:
I have this code that I thought would trigger ConnectionManager Error EventHandler.
private void LogError(string error)
{
if (Error != null)
Error(this, new EventArgs<string>(error));
}
I also have this code that gives an error message containing the string to LogError method.
int lasterror = Marshal.GetLastWin32Error();
if (lasterror != 0)
LogError("Bluetooth API returned: " + lasterror.ToString());
or
if (BluetoothSetServiceState(IntPtr.Zero, ref device, ref HumanInterfaceDeviceServiceClass_UUID, BLUETOOTH_SERVICE_ENABLE) != 0)
LogError("Failed to connect to wiimote controller");
Another Hint
To be more specific, I also already have the code below:
public event EventHandler<EventArgs<string>> Error;
and
ConnectionManager.Error += new EventHandler<EventArgs<string>>(ConnectionManager_Error);
And also this class:
public class EventArgs<T> : EventArgs
{
public T Value
{
get;
set;
}
public EventArgs(T value)
: base()
{
Value = value;
}
}
But MessageBox never appears even when the device is not connected to the computer.
I think that comes MassageBox supposed that show error messages.
Can someone show me what is wrong?
Your ConnectionManager has Error event, which passes instance of EventArgs<string> to event handlers. I believe generic event argument looks like:
public class EventArgs<T> : EventArgs
{
public EventArgs(T value)
{
Value = value;
}
public T Value { get; private set; }
}
So, ConnectionManager sets some string value to this argument of event and passes it to ConnectionManager_Error event handler. You should see value which was passed. From event name I can assume it should be error message.
NOTE: ConnectState enum, State property of ConnectionManager and its StateChanged event is not related to code you work with.
A Message Box is shown with the value provided by the EventArgs. I can only assume that your EventArgs class is a generic EventArgs implementation where the type parameters defines the type of the value.
So whatever the value is, that is what you will see in the MessageBox.

Categories