Implementing event handler in singleton class in C# wpf - c#

I have WebSocket class configured as a singleton:
public class ViSoftAdsHub : ViewModelBase
{
private static ViSoftAdsHub _instance;
ViSoftAdsHub()
{
ConnectAsync();
}
public static ViSoftAdsHub Instance
{
get
{
if (_instance == null)
{
_instance = new ViSoftAdsHub();
}
return _instance;
}
}
}
Multiple object instances of any type can add a notification to this singleton:
public void AddNotification(string name, ConfigurationsConfigSectionAdd sourceConfig,Type t)
{
NotificationObject no = new NotificationObject
{
ConnectionSettings = sourceConfig,
Name = name,
type = t
};
_Notifications.Add(name, no);
}
I need the callback only to be fired in the callback of the object who created the notification. Now, when a notification is received in the hub it fires on all callbacks on all objects.
This is the event implementation in the singleton:
protected virtual void OnNotification(ViSoftNotificationEventArgs e)
{
EventHandler<ViSoftNotificationEventArgs> handler = Notification;
if (handler != null)
{
handler(this, e);
}
}
public event EventHandler<ViSoftNotificationEventArgs> Notification;
public void OnMessage2(ViSoftNotificationEventArgs arg1, Type arg2)
{
OnNotification(arg1 as ViSoftNotificationEventArgs);
}
caller method of objects subscribing to the event:
hub = ViSoftAdsHub.Instance;
hub.Notification += new EventHandler<ViSoftNotificationEventArgs>(Hub_Notification);
hub.AddNotification(Name, SourceConfig, typeof(Sometype));
I also get a major memory leak.

Related

.NET c# - how to pass aditional data to PropertyChangedEventHandler

I have this code :
public void SomeMethod()
{
MyClass clss = new MyClass(); //note: MyClass implements INotifyPropertyChanged
clss.DoSomething();
clss.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(MyEventHandler);
}
static void MyEventHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
Debug.WriteLine("some property on MyClass has changed!");
}
This is working ok and when the property in SomeClass changes, MyEventHandler() is run.
But now I need to pass aditional data from SomeMethod() to MyEventHandler() , how can I do this?
* UPDATE *
ok I guess I should have explained better the whole problem: the method DoSomething() in MyClass makes a call to an external web service, passing it a callback so when the web service finish its work, it will call the callback, passing it a value with the result of the operation. Inside that callback, I am changing a property of the class to assign it the value received from the web service, thus triggering the propertyChanged event.
Then in the caller class, I subscribe to that event so I can do some things when it happens.
The final objective is, after calling DoSomething(), be able to wait until the web service has finished its job and returned a result, so I can then save some things in the database etc. and only then, return from SomeMethod()...
so this is MyClass, simplified:
public class MyClass : INotifyPropertyChanged
{
private long _wsReturnValue;
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
public long wsReturnValue
{
get { return _wsReturnValue; }
set {
_wsReturnValue = value;
OnPropertyChanged("wsReturnValue");
}
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new System.ComponentModel.PropertyChangedEventArgs(name));
}
public void DoSomething(object entity)
{
//here I just call external web service and returns, the webservice will call TheCallback() when finished
}
public void TheCallback(CommunicationEventArgs e)
{
this.wsReturnValue = e.res;
}
}
And this is the class that uses MyClass:
class MainClass
{
public void SomeMethod(object someObject)
{
MyClass clss = new MyClass(); //note: MyClass implements INotifyPropertyChanged
clss.DoSomething(someObject); //someObject contains data that I want to use later in the event handler
clss.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(MyEventHandler);
}
private static void MyEventHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
//here I need to use the object someObject...
}
}
Not sure if this is even close to what you mean, but here you go;
class EventClass
{
public void SomeMethod()
{
MyClass clss = new MyClass(); //note: MyClass implements INotifyPropertyChanged
clss.DoSomething(new object());
clss.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(MyEventHandler);
}
private static void MyEventHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
var customeEventArgs = (CustomEventArgs) e;
Debug.WriteLine("some property on MyClass has changed! Extra Data : {0}", customeEventArgs.ExtraData);
}
}
Implemented some more shell code to illustrate
internal class MyClass
{
public void DoSomething(object data)
{
var e = new CustomEventArgs("Property")
{
ExtraData = data
};
PropertyChanged?.Invoke(this, e);
}
public event PropertyChangedEventHandler PropertyChanged;
}
internal class CustomEventArgs : PropertyChangedEventArgs
{
public CustomEventArgs(string propertyName) : base(propertyName)
{
}
public object ExtraData { get; set; }
}
Any help? :)

How to raise an event on other instances of the same class

I have a class with an EventHandler for TimeChanged. A couple of instances of this class are created. In one of the instances of the class, the time can be changed. I would like all instances to react to the event of changed time.
Example:
public class MainClass
{
public MainClass()
{
}
public event EventHandler TimeChanged;
private virtual void OnTimeChanged()
{
EventHandler handler = TimeChanged;
if(handler != null)
{
handler(this, eventArgs.Empty);
}
}
}
public class AnotherClass
{
public AnotherClass()
{
MainClass _mainClass = new MainClass();
}
private void OnLoaded()
{
_mainClass.TimeChanged += HandleTimeChanged;
}
private void HandleTimeChanged
{
//Some stuff happens with new time, etc.
}
}
public class TimeClass
{
MainClass _class = new MainClass();
TimeSpan _timeValue;
private void ChangeTime()
{
// This is where the _timeValue is changed
// All instances of MainClass, subscribed to TimeChanged event to be notified with the new value selected.
}
}
So, basically when I change the time in TimeClass, which contains an instance of MainClass, I want to fire the TimeChanged event and all instances of MainClass (like in AnotherClass) should respond to the TimeChanged event to which they subscribed.
Hope this explains the situation. Any suggestions are welcome. Thanks.

PropertyChanged Event Trigger only occurs once

I Have a base Class that Implements INPC named Bindable this is my Event
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var eventHandler = this.PropertyChanged;
if (eventHandler != null)
{
eventHandler(this, new PropertyChangedEventArgs(propertyName));
}
}
Everything Works fine but if I have two delegates for my PropertyChangedEventHandler, only once is fired.
public class FirstClass : Bindable
{
public FirstClass()
{
PropertyChanged += Delegate1;
}
Void Delegate1 ....
}
public class SecondClass : Bindable
{
private FirstClass _MyFirstClass
public FirstClass MyFirstClass
{
get { return _MyFirstClass; }
set { SetProperty(ref _MyFirstClass, value); }
}
public SecondClass()
{
MyFirstClass = new FirstClass();
MyFirstClass.PropertyChanged += Delegate2;
}
Void Delegate2 ....
}
In this simple only Delegate1 runs Delegate2 never happens.
How Can I do implment my method properly for trigger any delegate?
EDIT 1: Corrected some code and instantiation of Firsrtclass.
EDIT 2: Full Implementation
public class Bindable : INotifyPropertyChanged //, INotifyPropertyChanging
{
#region BindableBase
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
{
if (object.Equals(storage, value)) return false;
storage = value;
this.OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var eventHandler = this.PropertyChanged;
if (eventHandler != null)
{
eventHandler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
} // Clase que implementa INotifyPropertyChanged
The problem is that when you create a new instance of FirstClass and set it, the event already fires, before giving you a chance to subscribe to it.
You could move the contents of FirstClass' constructor to a new method and call that method after the events are bound.
Here is your code, fixed:
public class FirstClass : Bindable
{
public void Init()
{
PropertyChanged += Delegate1;
// other stuff
}
Void Delegate1 ....
}
public class SecondClass : Bindable
{
private FirstClass _MyFirstClass
public FirstClass MyFirstClass
{
get { return _MyFirstClass; }
set { SetProperty(ref _MyFirstClass, value); }
}
public SecondClass()
{
MyFirstClass = new FirstClass();
MyFirstClass.PropertyChanged += Delegate2;
MyFirstClass.Init();
}
Void Delegate2 ....
}
Your code is set up wrong for this to run correctly, at all.
If you just instantiate a FirstClass, you would expect just Delegate1 to fire, as no SecondClass object was created.
If you instantiate a SecondClass, the reference to FirstClass is null, so it should throw a NullReferenceException right away on the event registration. You need to either create a FirstClass when you create a SecondClass, or pass SecondClass a FirstClass instance in its constructor that you can then use to register for the event.

C# constructor event

i created a class and when i create an employee object via form , i want to give a message;
this is my class, event and delegate
public delegate void ctorDel();
class Employee
{
private int empID;
private string empName;
public event ctorDel myEvent;
public Employee(int empID,string empName)
{
this.empID = empID;
this.empName = empName;
**if (myEvent != null)
{
myEvent();
}**
}
and in form
int id = Convert.ToInt16(textBox1.Text);
string name = textBox2.Text;
Employee emp = new Employee(id, name);
emp.myEvent += new ctorDel(showMessage);
and function
public void showMessage()
{
MessageBox.Show("An employee is created");
}
What is it you're trying to accomplish? The reason what you've tried doesn't work is because you're attaching your delegate after the ctor. Once you've called "new Employee" the event is long since fired.
If you really need such an event, create a factory class:
public delegate void EmpCreated();
public EmployeeFactory {
public event EmpCreated myEvent;
public Employee Create(int empId, string empName){
var result = new Employee(empId, empName);
if(myEvent != null) myEvent();
return result;
}
}
Subscribe to the event on the factory class and you'll get the event.
You're attaching the event after the constructor has already run.
It doesn't make sense to raise an instance event in the constructor, because since the initialization of the instance is not yet complete, there can't be any handler attached to the event...
However, you could create a static event:
public static event ctorDel myEvent;
...
Employee.myEvent += new ctorDel(showMessage);
(but don't subscribe to the event every time you create an Employee, or the handler will be invoked as many times as there are instances...)
Solution
Here's a generic approach to your problem
public class EventFactory
{
public U Create<U, V>(V constructorArgs)
{
var instance = (U)Activator.CreateInstance(typeof(U), constructorArgs);
OnCreated?.Invoke();
return instance;
}
public delegate void CreatedEventHandler();
public event CreatedEventHandler OnCreated;
}
You can then do
var ef = new EventFactory();
ef.OnCreated += myEventHandler;
var instance = ef.Create<Employee>(employeeArgs);
.. Going further
It is possible to adjust my code to provide greater flexiblity when you need to pass event arguments or when the constructor is parameterless. I haven't tested it but it should look somewhere along the lines of
public class EventFactory<T>
{
public U Create<U, V>(V constructorArgs, T eventArgs)
{
var instance = (U)Activator.CreateInstance(typeof(U), constructorArgs);
OnCreated?.Invoke(eventArgs);
return instance;
}
public U Create<U>(T eventArgs)
{
return Create<U, object>(null, eventArgs);
}
public delegate void CreatedEventHandler(T args);
public event CreatedEventHandler OnCreated;
}
public class EventFactory
{
public U Create<U, V>(V constructorArgs)
{
var instance = (U)Activator.CreateInstance(typeof(U), constructorArgs);
OnCreated?.Invoke();
return instance;
}
public U Create<U>() where U : new()
{
var instance = new U();
OnCreated?.Invoke();
return instance;
}
public delegate void CreatedEventHandler();
public event CreatedEventHandler OnCreated;
}
You can pass the handler when creating the Employee:
private Employee(ctorDel construcEvent)
{
if (construcEvent != null)
this.myEvent += construcEvent;
}
public Employee(int empID,string empName, ctorDel construcEvent)
: this(construcEvent)
{
this.empID = empID;
this.empName = empName;
if (myEvent != null)
{
myEvent();
}
}
And then:
Employee emp = new Employee(id, name, new ctorDel(showMessage));
By the time you subscribe for this event the instance is already constructed.
I would recommend using Factory pattern to hide the constructor.
class EmployeeFactory
{
public Employee Create(int id, string name)
{
Employee instance = new Employee(id, name);
var handler = EmployeeCreated;
if (handler != null)
{
EmployeeEventArgs e = new EmployeeEventArgs(instance);
handler(e);
}
return instance;
}
public event EventHandler<EmployeeEventArgs> EmployeeCreated;
}
Event subscription:
factory.EmployeeCreated += MyHandler;
Instance construction:
var emp = factory.Create(id, name);

How to raise parent class events with Expression (C#)

I'm writing a class library for a Web API.
I have a base class and an interface with 30 blocks like this:
interface ISomethingApi {
void AuthenticateAsync(string username, string password);
event AsyncResponseHandler AuthenticateEnded;
void GetMemberAsync(string username);
event AsyncResponseHandler<Member> GetMemberEnded;
// more...
}
The base class called BaseHttpClient contains the implementation and all methods are empty and virtual.
class BaseHttpClient : ISomethingApi {
public virtual void GetMemberAsync(string username) {
throw new NotImplementedException();
}
public event AsyncResponseHandler<Member> GetMemberEnded;
// more...
}
Because the API is pretty non-standard, I am inheriting the base class with a XmlClient class. This class overrides virtual methods and do the job.
class XmlClient : BaseHttpClient {
public override void GetMemberAsync(string username) {
Member member;
// process here
// raising the event
GetMemberEnded(this, new AsyncResponseArgs<Member>(member));
// error: LogoffEnded can only appear on the left hand side of += or -=
}
}
The problem is I can't raise the events:
The event 'BaseHttpClient.LogoffEnded' can only appear on the left hand side of += or -=
A basic solution is to create methods in the base class like
protected void RaiseLogoffEnded(AsyncResponseArgs args) {
if (LogoffEnded != null) {
LogoffEnded(this, args);
}
}
But there are too many methods to create. I'd like to do something like:
public override void GetMemberAsync(string username) {
Member member;
// work done here
RaiseEvent(x => x.GetMemberEnded, new AsyncResponseArgs<Member>(member));
}
I suppose this is about reflection and expressions.
Is it a right way to do? (performace)
What documentation could I read to make this?
could you show me a valid code for this?
You could use a couple of static extension methods:
static class Extensions
{
public static void Raise(this EventHandler #event, object sender, EventArgs e)
{
if (#event != null)
#event(sender, e);
}
public static void Raise<T>(this EventHandler<T> #event, object sender, T e) where T : EventArgs
{
if (#event != null)
#event(sender, e);
}
}
Whereby you could do:
public class MyClass
{
public event EventHandler MyEvent;
public void DoSomething()
{
MyEvent.Raise(this, EventArgs.Empty);
}
}
While you can in fact use an expression, e.g.:
public void Raise<T>(Expression<Func<EventHandler<T>>> expr, T eventArgs)
where T : EventArgs
{
EventHandler<T> handler = expr.Compile().Invoke();
handler(this, eventArgs);
}
You probably want to do away with the redundant expression, and just use a Func<T> instead, as you are raising the event from the class directly. Through expressions, you would need to compile the expression, whereas Func<T> you don't:
public void Raise<T>(Func<EventHandler<T>> func, T eventArgs)
where T : EventArgs
{
EventHandler<T> handler = func();
handler(this, eventArgs);
}
You can make use of System.ComponentModel.EventHandlerList which will net you two advantages:
1) You will have your FireEvent mechanism.
2) The Events member doesn't use memory unless there are delegates subscribed. If you have a class with 30 events, you have 30 pointers in your class' footprint, whether or not there are any subscribers. EventHandlerList is a single object that contains any and all delegates subscribed. It's a very light-weight map (not a Dictionary). Notice that the event keys are static objects so as not to add to the class' footprint.
class AsyncResponseArgs : EventArgs
{
public Member Member { get; private set; }
public AsyncResponseArgs(Member m)
{
Member = m;
}
}
interface ISomethingApi
{
void AuthenticateAsync(string username, string password);
event EventHandler<AsyncResponseArgs> AuthenticateEnded;
void GetMemberAsync(string username);
event EventHandler<AsyncResponseArgs> GetMemberEnded;
}
class BaseHttpClient : ISomethingApi
{
private EventHandlerList Events = new EventHandlerList();
public virtual void AuthenticateAsync(string username, string password)
{
throw new NotImplementedException();
}
protected static object AuthenticateEndedEvent = new object();
public event EventHandler<AsyncResponseArgs> AuthenticateEnded
{
add { Events.AddHandler(AuthenticateEndedEvent, value); }
remove { Events.RemoveHandler(AuthenticateEndedEvent, value); }
}
public virtual void GetMemberAsync(string username)
{
throw new NotImplementedException();
}
protected static object GetMemberEndedEvent = new object();
public event EventHandler<AsyncResponseArgs> GetMemberEnded
{
add { Events.AddHandler(GetMemberEndedEvent, value); }
remove { Events.RemoveHandler(GetMemberEndedEvent, value); }
}
protected void FireEvent(object key, AsyncResponseArgs e)
{
EventHandler<AsyncResponseArgs> handler = (EventHandler<AsyncResponseArgs>)Events[key];
if (handler != null)
handler(this, e);
}
}
class XmlClient : BaseHttpClient
{
public override void GetMemberAsync(string username)
{
Member member;
// process here
FireEvent(GetMemberEndedEvent, new AsyncResponseArgs(member));
}
}
Added:
You can save yourself some typeing in BaseHttpClient by writing a code snippet.
You have to move your RaiseXXX methods to parent class, where you have your events defined. Make sure these methods are at least protected.
And don't forget to call your events via local variable to minimize error field.
var e = MyEvent;
if (e != null) e(this, EventArgs.Empty);
You could add a method to the base class that takes the event name as a String and raises the corresponding event via reflection like
public void Raise(String eventName, object source, EventArgs eventArgs)
{
var field = this.GetType().GetField(eventName, BindingFlags.Instance | BindingFlags.NonPublic);
if (field == null)
throw new ArgumentException("No such event: " + eventName);
var eventDelegate = (MulticastDelegate)field.GetValue(this);
if (eventDelegate != null)
foreach (var handler in eventDelegate.GetInvocationList())
handler.Method.Invoke(handler.Target, new object[] { source, eventArgs });
}
I don't know anything about performance, though.

Categories