C# EventHandler returns null when called - c#

I have a two classes.In one class i am creating and raising an event as follows :
CustomerAdd Class
public class CustomerAdd
{
public delegate void Done(object Sender, EventArgs e);
public event Done ListUpdated;
public void UpdateNewList()
{
//adding items to a generic List<T>,code removed as not relevant to post
//and raising the event afterwards
if (ListUpdated != null)
{
ListUpdated(this, EventArgs.Empty);
}
}
}
MyWindow Class
public class MyWindow
{
private void SaveToDisk()
{
CustomerAdd cuss = new CustomerAdd();
cuss.ListUpdated += new CustomerAdd.Done(DisplayDetails);
cuss.UpdateNewList();
}
private void DisplayDetails()
{
//other codes here
}
}
Now, when i call the SaveToDisk method from MyWIndow class,(as i am subscribing DisplayDetails method to the ListUpDated event) , DisplayDetails is not called. The debugger shows that ListUpdated is null. I have searched for hours and failed to come up with a solution.I followed this link but still ListUpdated is null. Any guidance/help would be highly appreciated.

It works:
using System;
namespace ConsoleApp2
{
class Program
{
public class CustomerAdd1
{
public delegate void Done(object Sender, EventArgs e);
public event Done ListUpdated;
public void UpdateNewList()
{
//adding items to a generic List<T>,code removed as not relevant to post
//and raising the event afterwards
if (ListUpdated != null)
{
ListUpdated(this, EventArgs.Empty);
}
}
}
public class CustomerAdd
{
public void SaveToDisk()
{
CustomerAdd1 cuss = new CustomerAdd1();
cuss.ListUpdated += new CustomerAdd1.Done(DisplayDetails);
cuss.UpdateNewList();
}
private void DisplayDetails(object Sender, EventArgs e)
{
Console.WriteLine("Test");
}
}
static void Main(string[] args)
{
var c = new CustomerAdd();
c.SaveToDisk();
Console.ReadLine();
}
}
}

Try this:
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
CustomerReceive cr = new CustomerReceive();
cr.SaveToDisk();
}
}
public class CustomerAdd
{
public delegate void Done(object Sender, EventArgs e);
public event Done ListUpdated;
public void UpdateNewList()
{
//adding items to a generic List<T>,code removed as not relevant to post
//and raising the event afterwards
if (ListUpdated != null)
{
ListUpdated.Invoke(this, EventArgs.Empty);
}
}
}
public class CustomerReceive
{
public void SaveToDisk()
{
CustomerAdd cuss = new CustomerAdd();
cuss.ListUpdated += new CustomerAdd.Done(DisplayDetails);
cuss.UpdateNewList();
}
private void DisplayDetails(object Sender, EventArgs e)
{
int k = 0;
}
}
}
You need to do a good read on delegates and events because this is not working when there are more listeners

Related

Create EventHandler and listen to Event from another class

I've created event as bellow and want to listen to it and execute method in another class when it fires
but saveEvent always comes to be null and it doesn't fire
I don't know what I've missed
here's my first class has button
internal partial class OpenSaveReportWizardForm : Form
{
public event EventHandler saveEvent;
private void saveButton_Click(object sender, EventArgs e)
{
saveEvent?.Invoke(this, e);
}
}
and here's the second class where I want to listen to saveEvent
internal class Database
{
public Database()
{
Program._wizardForm.saveEvent += (sender, e) => HandleSaveMethod( );
}
public void HandleSaveMethod()
{
// do something
}
here's where I open the form
internal class Program
{
public static OpenSaveReportWizardForm _wizardForm;
private static void Main()
{
OpenFileCommandHandler();
}
void OpenFileCommandHandler()
{
_wizardForm = new OpenSaveReportWizardForm( );
_wizardForm.ShowDialog();
}
}
Because you disposed wizardForm, after that event is cleared.
You should write next code:
internal class Database
{
private bool _isDisposed;
private OpenSaveReportWizardForm _wizardForm;
public Database()
{
_wizardForm = new OpenSaveReportWizardForm(m_Opening,m_ConnectionProperties,m_ColumnProperties))
_wizardForm.saveEvent += (sender, e) => HandleSaveMethod( );
}
public void HandleSaveMethod()
{
// do something
}
public void Dispose()
{
if(_isDisposed)
return;
_isDisposed = true;
_wizardForm.saveEvent -= HandleSaveMethod;
_wizardForm.Dispose();
}

Mixing Covariance and Contravariance

Goal:
Iterate over the following collection
var collection = new IImportTrigger<EventArgs>[]
{
new FileSystemImportTrigger()
, new TimerImportTrigger()
};
in this way
foreach (var trigger in collection)
{
trigger.Import += trigger.OnImport;
}
This is what I have so far
public delegate void ImportTriggerEventHandler<in T>(object sender, T args) where T : EventArgs;
public interface IImportTrigger<out T> where T : EventArgs
{
event ImportTriggerEventHandler<T> Import;
void OnImport<T1>(object sender, T1 args) where T1 : EventArgs;
}
public class FileSystemImportTrigger : IImportTrigger<FileSystemEventArgs>
{
public event ImportTriggerEventHandler<FileSystemEventArgs> Import;
public void OnImport<T>(object sender, T args) where T : EventArgs { }
}
public class TimerImportTrigger : IImportTrigger<ElapsedEventArgs>
{
public event ImportTriggerEventHandler<ElapsedEventArgs> Import;
public void OnImport<T>(object sender, T args) where T : EventArgs { }
}
Expectations:
I would like to define the IImportTrigger with only one generic parameter.
Problem:
If I change my Interface definition to the following (notice the generic argument T is not covariant any more).
public interface IImportTrigger<T> where T : EventArgs
{
event ImportTriggerEventHandler<T> Import;
void OnImport(object sender, T args);
}
and hence
public class FileSystemImportTrigger : IImportTrigger<FileSystemEventArgs>
{
public event ImportTriggerEventHandler<FileSystemEventArgs> Import;
public void OnImport(object sender, FileSystemEventArgs args) { }
}
public class TimerImportTrigger : IImportTrigger<ElapsedEventArgs>
{
public event ImportTriggerEventHandler<ElapsedEventArgs> Import;
public void OnImport(object sender, ElapsedEventArgs args) { }
}
I wont be able to create a common type for my collection
var collection = new IImportTrigger<EventArgs>[]
{
new FileSystemImportTrigger()
, new TimerImportTrigger()
};
because the Generic parameter is not output-safe any more.
Question:
Is there any way to accomplish my scenario?
By switching OnImport to be not generic at all then use a explicit interface, then make another more derived interface that is not covariant that has the generic verson of OnImport you could pull it off.
internal class Program
{
private static void Main(string[] args)
{
var collection = new IImportTriggerBase<EventArgs>[]
{
new FileSystemImportTrigger()
, new TimerImportTrigger()
};
foreach (var trigger in collection)
{
trigger.Import += trigger.OnImport;
}
}
}
public delegate void ImportTriggerEventHandler<in T>(object sender, T args) where T : EventArgs;
public interface IImportTriggerBase<out T> where T : EventArgs
{
event ImportTriggerEventHandler<T> Import;
void OnImport(object sender, EventArgs args);
}
public interface IImportTrigger<T> : IImportTriggerBase<T> where T : EventArgs
{
void OnImport(object sender, T args);
}
public class FileSystemImportTrigger : IImportTrigger<FileSystemEventArgs>
{
public event ImportTriggerEventHandler<FileSystemEventArgs> Import;
public void OnImport(object sender, FileSystemEventArgs args) { }
void IImportTriggerBase<FileSystemEventArgs>.OnImport(object sender, EventArgs args)
{
OnImport(sender, (FileSystemEventArgs)args);
}
}
public class TimerImportTrigger : IImportTrigger<ElapsedEventArgs>
{
public event ImportTriggerEventHandler<ElapsedEventArgs> Import;
public void OnImport(object sender, ElapsedEventArgs args) { }
void IImportTriggerBase<ElapsedEventArgs>.OnImport(object sender, EventArgs args)
{
OnImport(sender, (ElapsedEventArgs)args);
}
}
However this does give you the extra cruft of the OnImport(object sender, EventArgs args) method which is visible on IImportTrigger<T>.
That was to solve your problem, if I where going to do this and I am assuming correctly you just want derived classes to be able to pick up on the fact that Import is getting fired and you actually do not need OnImport exposed I would just do
internal class Program
{
private static void Main(string[] args)
{
var collection = new IImportTrigger<EventArgs>[]
{
new FileSystemImportTrigger()
, new TimerImportTrigger()
};
}
}
public delegate void ImportTriggerEventHandler<in T>(object sender, T args) where T : EventArgs;
public interface IImportTrigger<out T> where T : EventArgs
{
event ImportTriggerEventHandler<T> Import;
}
public abstract class OnImportBase<T> : IImportTrigger<T> where T: EventArgs
{
public event ImportTriggerEventHandler<T> Import;
protected virtual void OnImport(object sender, T args)
{
var tmp = Import;
if (tmp != null)
{
tmp(this, args);
}
}
}
public class FileSystemImportTrigger : OnImportBase<FileSystemEventArgs>
{
protected override void OnImport(object sender, FileSystemEventArgs args)
{
DoSomeExtraStuffBeforeImport();
base.OnImport(sender, args);
}
private void DoSomeExtraStuffBeforeImport()
{
}
}
public class TimerImportTrigger : OnImportBase<ElapsedEventArgs>
{
protected override void OnImport(object sender, ElapsedEventArgs args)
{
base.OnImport(sender, args);
DoSomeExtraStuffAfterImport();
}
private void DoSomeExtraStuffAfterImport()
{
}
}
This gets rid of the event subscription and instead handles it as a override (Which is the normal pattern in .NET events).

How to access the event handler in another class

I have a click event handler in class A with some logic. And now i want to access class A event handler from class B and do some logic so that class B event hadler logic fires first followed by class A event handler.
Example:
Class A
private void calculate_Click(object sender, System.EventArgs e)
{ this.MyMethod(); }
Class B
private void calculate_Click(object sender, System.EventArgs e)
{ // My new code.. (This should trigger first) this.MyMethod(); }
You may use event exposed by class A and consumed by class B like we do with Button class. Button exposes click event and in our form class we subscribe for click event being exposed by Button class.
I found this simple example for understanding here
using System;
namespace wildert
{
public class Metronome
{
public event TickHandler Tick;
public EventArgs e = null;
public delegate void TickHandler(Metronome m, EventArgs e);
public void Start()
{
// while (true) //uncomment this line if you want event to fire repeatedly
{
System.Threading.Thread.Sleep(3000);
if (Tick != null)
{
Tick(this, e);
}
}
}
}
public class Listener
{
public void Subscribe(Metronome m)
{
m.Tick += new Metronome.TickHandler(HeardIt);
}
private void HeardIt(Metronome m, EventArgs e)
{
System.Console.WriteLine("HEARD IT");
}
}
class Test
{
static void Main()
{
Metronome m = new Metronome();
Listener l = new Listener();
l.Subscribe(m);
m.Start();
}
}
}
Assuming class B has instance member A instanceOfClassA initilized properly with an instance of A:
private void calculate_Click(object sender, System.EventArgs e)
{
// My new code.. (This should trigger first)
instanceOfClassA.MyMethod();
// other code
}
You may also consider inheriting class B from A:
class B:A
{
private void calculate_Click(object sender, System.EventArgs e)
{
// My new code.. (This should trigger first)
this.MyMethod(); // will come from base class A implementation.
// other code
}
}

WinForm events in another class .NET2 Simplify delegate

Any way to make this working code simpler ie the delegate { }?
public partial class Form1 : Form
{
private CodeDevice codeDevice;
public Form1()
{
InitializeComponent();
codeDevice = new CodeDevice();
//subscribe to CodeDevice.ConnectionSuccessEvent and call Form1.SetupDeviceForConnectionSuccessSate when it fires
codeDevice.ConnectionSuccessEvent += new EventHandler(SetupDeviceForConnectionSuccessState);
}
private void SetupDeviceForConnectionSuccessState(object sender, EventArgs args)
{
MessageBox.Show("It worked");
}
private void button1_Click(object sender, EventArgs e)
{
codeDevice.test();
}
}
public class CodeDevice
{
public event EventHandler ConnectionSuccessEvent = delegate { };
public void ConnectionSuccess()
{
ConnectionSuccessEvent(this, new EventArgs());
}
public void test()
{
System.Threading.Thread.Sleep(1000);
ConnectionSuccess();
}
}
WinForm event subscription to another class
How to subscribe to other class' events in c#?
If don't think you could simplyfy:
public event EventHandler ConnectionSuccessEvent = delegate { }
even in c#3 + you could only do
public event EventHandler ConnectionSuccessEvent = () => { }
However you could simplify
codeDevice.ConnectionSuccessEvent += new EventHandler(SetupDeviceForConnectionSuccessState);
to
codeDevice.ConnectionSuccessEvent += SetupDeviceForConnectionSuccessState;

C# Progress Bar based on event and delegate not working

I need help in troubleshooting my code. I have 3 classes. Class 1 is a WinForm with Progressbar on it. Class 2 is where the event is fired. Class 3 is the EventArg for the progress. The program compiles with out any errors, but when I click the button, the progress bar does not move!.
namespace WindowsFormsApplication1
{
class Class1
{
//Declaring a delegate
public delegate void StatusUpdateHandler(object sender, ProgressEventArgs e);
//Declaraing an event
public event StatusUpdateHandler OnUpdateStatus;
public int recno;
public void Func()
{
//time consuming code
for (recno = 0; recno <= 100; recno++)
{
UpdateStatus(recno);
}
}
public void UpdateStatus(int recno)
{
// Make sure someone is listening to event
if (OnUpdateStatus == null) return; <--------------OnUpdateStatus is always null not sure why?
ProgressEventArgs args = new ProgressEventArgs(recno);
OnUpdateStatus(this, args);
}
}
}
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private Class1 testClass;
public Form1()
{
InitializeComponent();
testClass = new Class1();
testClass.OnUpdateStatus += new Class1.StatusUpdateHandler(UpdateStatus);
}
public void button1_Click(object sender, EventArgs e)
{
Class1 c = new Class1();
c.Func();
}
public void UpdateStatus(object sender, ProgressEventArgs e)
{
progressBar1.Minimum = 0;
progressBar1.Maximum = 100;
progressBar1.Value = e.Recno;
}
}
}
namespace WindowsFormsApplication1
{
public class ProgressEventArgs : EventArgs
{
public int Recno { get; private set; }
public ProgressEventArgs(int recno)
{
Recno = recno;
}
}
}
You're using two different objects of Class1.
In button click handler, the object c is not the same as member object testClass. Use testClass in place of c and it shud work
public void button1_Click(object sender, EventArgs e)
{
testClass.Func();
}
You never added an event handler to c's event.
You did add a handler to testClass' event, but testClass is never used.

Categories