I have a controller class and a manager class.
I want my manager class to call a function from my controller to trigger an event.
My controller looks something like this:
public class Controller{
public Controller(Mgr mgr)
{
m_mgr = mgr;
m_mgr.schedulerReload += reloadScheduler;
}
void reloadScheduler(object sender, EventArgs e)
{
ReloadSchedulerQueue();
}
}
where ReloadSchedulerQueue is the function I want to trigger from my event.
my manager class looks like this
public class Manager{
public event EventHandler schedulerReload;
public void somefunction() {
//do something
schedulerReload(this, EventArgs.Empty);
}
}
Whenever I run this I can see that the schedulerReload event is getting a null reference exception, im assuming because there is no one subscribed to my event. However, I can clearly see while stepping through my code that the constructor, and the line
m_mgr.schedulerReload += reloadScheduler;
is clearly hit multiple times before somefunction() is called. I know I can handle this exception by checking my eventhandler before calling it, but I don't know why my eventhandler is not getting subscribed to.
What am I missing here?
Related
Here is an example...
public class CodeGenerator
{
public delegate void GeneratorCalculatorEventHandler(decimal Fond);
public event GeneratorCalculatorEventHandler eventName;
public CodeGenerator()
{
eventName?.Invoke(0);
}
}
How could I catch the event? If I do this:
CodeGenerator CodeGen = new CodeGenerator();
CodeGen.eventName += CodeGen_eventName;
The event is fired when the handler is not subscribed to it yet. Is it possible to subscribe to an event on initialiazation?
As the comments said, this is a bad code smell. It sounds like you're doing something very unusual here and you should consider trying to find a different way to solve your problem.
One of the reasons it smells bad is: if the calling code knows to pass the handler to the constructor, then that code already knows that the constructor is being invoked. The caller could simply invoke the handler itself with the constructed instance! Events are typically for situations where something happens that the handler could not predict or control, like the user clicking a button.
I would not pass the handler to the constructor, were I in your situation. I would use a static event.
You should pass the handler to the constructor and attach it to the event, something like:
public class CodeGenerator
{
public delegate void GeneratorCalculatorEventHandler(decimal Fond);
public event GeneratorCalculatorEventHandler eventName;
public CodeGenerator(GeneratorCalculatorEventHandler listener)
{
eventName += listener;
eventName?.Invoke(0);
}
}
public class Test
{
public Test()
{
CodeGenerator gen = new CodeGenerator((sen) => { return; });
}
}
I'm writing down a customized Timer, that extends DispatcherTimer. It has a method called TimerSetUp, in which I associate the Tick event to an EventHandler.
public class MyTimer : DispatcherTimer
{
public MyTimer(){}
public void TimerSetUp(EventHandler<EventArgs> _EventHandler)
{
base.Tick += _EventHandler;
}
}
I have now another couple of classes, StopwatchTimer and CountdownTimer, that extend MyTimer. Let's look at CountdownTimer.
public class CountdownTimer : MyTimer
{
public CountdownTimer()
{
base.TimerSetUp(CountdownTimer_Tick);
}
public void CountdownTimer_Tick(object sender, EventArgs e)
{
//...do something
}
}
When either of them is declared, the constructor must call the base class method TimerSetUp and just set up the event handler.
The problem is that, in the signature of the TimerSetUp function, it gives me this error
Cannot implicitly convert type 'System.EventHandler<System.EventArgs>'
to'System.EventHandler<object>
And I can't get rid of it. If I just put TimerSetUp inside CountdownTimer, and just assign directly the event handler, like this
base.Tick += CountdownTimer_Tick;
it works, but I'd really like to make it work the other way.
So I'd like to know if
1) There's a way I can resolve this
2) Is this a good approach to extensibility of the code?
Nevermind, I made it. I just casted a generic object in the function signature and wrapped a new eventHandler inside the code.
public void TimerSetUp(EventHandler<object> _EventHandler)
{
base.Tick += new EventHandler<object>(_EventHandler);
}
DispatchTimer.Tick seems to be the non generic EventHandler rather than EventHandler<EventArgs>. Since you are using the base EventArgs anyway, they are functionally equivalent:
public void TimerSetUp(EventHandler _EventHandler)
{
base.Tick += _EventHandler;
}
See: https://msdn.microsoft.com/en-us/library/system.windows.threading.dispatchertimer.tick(v=vs.110).aspx
This has been asked probably many times, but looking through all the other questions I still was not able to solve my issue. I want to update a Datagridview on a form using an update function on this form. The Update function is called by a subscriber.
Overview:
static class MainClass
{
static void Main()
{
// The Main form is called.
MainForm = new frmMain();
Application.Run(MainForm);
//Application.Run(new frmMain());
}
}
A Delegate
public delegate void Delagate_UpdateDataView();
The subscriber that subscribed to publisher that fires an event every 500 ms.
public class SubscriberFrmMain
{
// Constructor
public SubscriberFrmMain()
{
}
// Subscribe to the Publisher
public void Subscribe(PublisherTimedEvent mUpdateHMIData)
{
//attach listener class method to publisher class delegate object
mUpdateHMIData.TickUpdateHMIData += UpdateHMIData;
}
// The Event, fired when the Publisher raises an event.
private void UpdateHMIData(PublisherTimedEvent mUpdateHMIData,EventArgs e)
// Calling the Update function on the Form MainForm.
{
MainClass.MainForm.Process_UpdateDataView(new
Delagate_UpdateDataView(MainClass.MainForm.UpdateDataView));
}
}
The Update function in the Form
public void Process_UpdateDataView(Delagate_UpdateDataView update)
{
update();
}
public void UpdateDataView()
{
try
{
TagTableAdapter.Fill(uDataSet.PLC_Tag);
}
catch
{
}
}
Updating the TagTableAdapter manually works without any problem. Updating using the subscriber does nothing.
Probably there are easier ways to achieve this but I would like to use this type of construction also for other parts of the program.
Thanks for your suggestions.
Event's can only be risen from inside the class. If you could do that it would defeat the purpose of events.You can subscribe to this event from other class tho.
public event EventHandler someEvent;
EventContainer obj = new EventContainer();
obj.someEvent += handler;
where handler is a method according to the signature of someEvent. One is able to subscribe to the event from the outside just fine, but it can only be risen from inside the class defining it.
I am new to C# and programming in general and am trying to figure out how to use events. Previously I have been programming with ActionScript3, and there events are a special class that you inherit from if you want to create your own events, and then that event can be called by any other class.
With C# I have tried to do something similar, like so:
public class EventManager
{
public delegate void TempDelegate();
public static event TempDelegate eSomeEvent;
}
public class SomeOtherClass
{
//doing some stuff, then:
if (EventManager.eSomeEvent != null)
{
EventManager.eSomeEvent();
}
}
This gives me a compiler error CS0070: The event 'EventManager.eSomeEvent' can only appear on the left hand side of += or -= (except when used from within the type 'EventManager')
The information about this error over on the msdn indicates that I should use += instead of trying to call the event, but I don't really understand this. I'm not trying to subscribe anything from SomeOtherClass to the event delegate, I am just trying to call this event so that it starts executing those functions that are already subscribed to that event.
So is it possible to do it this way? If not, is it at all possible to call an event that is of one class, from another class? I simply wish to reuse certain events in my classes rather than creating many similar ones in multiple classes.
Any advice with this would be greatly appreciated!
You can wrap the event call in a public method and use that from your other classes.
public void OnSomeEvent()
{
var handler = eSomeEvent;
if (handler != null) handler(this, null);
}
However you might want to look at the design again, if you are really sure the event should be on a different class than the one triggering it.
Well, the typical solution is to put eSomeEvent invocation into the EventManager class
public class EventManager
{
public delegate void TempDelegate();
public static event TempDelegate eSomeEvent;
// Not thread safe as well as your code
// May be internal, not public is better (if SomeOtherClass is in the same namespace)
public static void PerformSomeEvent() {
if (!Object.ReferenceEquals(null, eSomeEvent))
eSomeEvent(); // <- You can do it here
}
}
public class SomeOtherClass
{
//doing some stuff, then:
EventManager.PerformSomeEvent();
}
I am getting stumped with my plug-in architecture that I am trying to develop with respect to events. I can do this just fine, in a single application: (Obviously this is a very simplified version of what I am trying to accomplish, and if this were my code there are easier ways to accomplish this, just try to follow the logic ;)
public Form1()
{
public event EventHandler OnValueOver5Chars;
Main()
{
OnValueOver5Chars+= new EventHandler(WarnUser);
....
}
private void textBox_Changed( object sender, EventArgs e )
{
if( sender.Text.count() > 5 )
OnValueOver5Chars(sender, e); // WORKS HERE
}
private void WarnUser(object sender, EventArgs e)
{
...
}
}
However, now I have a plug-in architecture, where the plugin implements an interface which houses my event:
// Interface.cs
public interface IPlugin
{
event EventHandler OnValueOver5Chars;
...
}
// Plugin1.cs
public class Plugin1 : IPlugin
{
public event EventHandler OnValueOver5Chars;
Plugin1()
{
OnValueOver5Chars += new EventHandler(Plugin1WarnUser);
}
private void Plugin1WarnUser(object sender, EventArgs e)
{
...
}
}
// Form.cs
public class Form1 : Form
{
public Form1()
{
Assembly SampleAssembly = Assembly.LoadFrom("Plugin1.dll");
Type myType = SampleAssembly.GetTypes()[0];
if (myType.GetInterfaces().Contains(typeof(IPlugin)))
{
IPlugin myInstance = Activator.CreateInstance(myType) as IPlugin;
myInstance.OnValueOver5Chars(this, new EventArgs());
// Compiler Error CS0079 - The event 'event' can only appear on the left hand side of += or -=
}
}
????
You're trying to hook up an event to another event, and that won't work. You need to hook the plug-ins event to a method/delegate. Once you do that, have the method/delegate call the other event.
myInstance.OnValueOver5Chars += OnValueOver5CharsFunc;
...
/*In Form1*/
void OnValueOver5CharsFunc( object sender, EventArgs args )
{
OnValueOver5Chars( sender, args );
}
Events in C# have the property that they are not "callable" directly as methods (or as such as delegates) outside of the class where they are defined.
In your first example you are calling the event from within the class in which you define it. In the second example, however, you are trying to call OnValueOver5Chars from outside the class - hence the error.
To solve this you could consider adding a method to your IPlugin interface (e.g. ValueOver5Chars) that performs OnValueOver5Chars. Note that it is more common to name the event ValueOver5Chars (say), and provide a method OnValueOver5Chars to raise it (i.e. the other way round). See for example the Windows Forms Button class and its Click event.