C# trigger event - c#

I use C# and I want to trigger an event from within a class :
So if the Price property of a class was changed then an event onPriceChanged (outside the class) should be fired.
However, I get an error:
The name 'onPriceChanged' does not exist in the current context
How could I fix this?
(I guess that I could pass the eventhandler to the class via constructor...but if possible I would prefer not to pass the eventhandler to the class)
Here is my code :
using System;
public delegate void delEventHandler();
class clsItem
{
//private static event delEventHandler _show;
private delEventHandler _show;
private int _price;
public clsItem() //Konstruktor
{
_show += new delEventHandler(Program.onPriceChanged); // error here : The name 'onPriceChanged' does not exist in the current context
}
public int Price
{
set
{
_price = value;
_show.Invoke(); //trigger Event when Price was changed
}
}
}
class Program
{
static void Main()
{
clsItem myItem = new clsItem();
myItem.Price = 123; //this should trigger Event "onPriceChanged"
}
//EventHandler
public static void onPriceChanged()
{
Console.WriteLine("Price was changed");
}
}

You're doing this the wrong way round - you're trying to attach the event handler from the class, and clearly that cannot have access to the Program.onPriceChanged method!
You should expose your event, and attach the event handler from the client code (Program).
class clsItem
{
//private static event delEventHandler _show;
private delEventHandler _show;
private int _price;
public clsItem() //Konstruktor
{
}
public event delEventHandler Show
{
add { _show += value; }
remove { _show -= value; }
}
public int Price
{
set
{
_price = value;
_show?.Invoke(); //trigger Event when Price was changed
}
}
}
And:
clsItem myItem = new clsItem();
myItem.Show += onPriceChanged;
myItem.Price = 123; //this now does trigger Event "onPriceChanged"
Live example: http://rextester.com/WMCQQ40264

The way you're dealing with events is not a good practice. the reason why we use Events is to decouple the objects we create from the methods they need to call.
For example if you want to create another object of the same type(clsItem) and get it to call another method once its price changed, you get into trouble. So I'd suggest this code rather than the current one:
using System;
public delegate void delEventHandler();
class clsItem
{
public event delEventHandler PriceChanged;
private int _price;
public clsItem() //Konstruktor
{
}
public int Price
{
set {
if(value!=_price) // Only trigger if the price is changed
{
_price = value;
if(PriceChanged!=null) // Only run if the event is handled
{
PriceChanged();
}
}
}
}
}
class Program
{
static void Main()
{
clsItem myItem = new clsItem();
myItem.PriceChanged += new delEventHandler(onPriceChanged);
myItem.Price = 123; //this should trigger Event "PriceChanged" and call the onPriceChanged method
}
//EventHandler
public static void onPriceChanged()
{
Console.WriteLine("Price was changed");
}
}

Here is the more traditional way of doing what you want:
public delegate void delEventHandler();
class clsItem
{
public event delEventHandler Show;
private int _price;
public clsItem() //Konstruktor
{
}
public int Price
{
set
{
_price = value;
Show?.Invoke(); //trigger Event when Price was changed
}
}
}
class Program
{
static void Main()
{
clsItem myItem = new clsItem();
myItem.Show += onPriceChanged;
myItem.Price = 123; //this should trigger Event "onPriceChanged"
}
//EventHandler
public static void onPriceChanged()
{
Console.WriteLine("Price was changed");
}
}
Notice that clsItem no longer knows who is subscribing to its event. All it cares about is notifying any listeners who happens to be subscribed. There is no longer a dependency between clsItem and the onPriceChanged method.

Related

Raise application level event

I'm trying to create an event handler, that when some button is tapped on Content Dialog, the main Page or the Page that has called the Content Dialog receive the event.
I have found some examples about it in Stackoverflow as in other forums, but the one I'm using to get what I've told is this one. I'm having some problemas to create the event raiser and because it's my first time trying to do something like that I'm a bit lost on the implementation.
This is my code:
someClass.cs
public class updatedDB
{
public enum updateType
{
Delete, Update, None
}
private updateType _updateType;
private bool _isUpdated;
private int _ID;
private bool IsUpdated
{
get { return _isUpdated; }
set
{
_isUpdated = value;
ValueChanged?.Invoke(value);
}
}
public void NotifyUpdate(int ID, updateType UpdateType)
{
if (UpdateType == updateType.None)
return;
else
{
IsUpdated = true;
_ID = ID;
_updateType = UpdateType;
}
}
public updateType GetUpdateType()
{
return _updateType;
}
public int GetUpdatedID()
{
return _ID;
}
public event ValueChangedEventHandler ValueChanged;
}
public delegate void ValueChangedEventHandler(bool value);
And this is the event handler in another .cs file (Page.cs):
public Page()
{
this.InitializeComponent();
HardwareButtons.BackPressed += HardwareButtons_BackPressed;
UpdateEvent.ValueChanged += UpdateSpots;
}
private ValueChangedEventHandler UpdateSpots(bool value)
{
ValueChangedEventHandler handler = new ValueChangedEventHandler(value);
return handler;
}
Currently I have two part of this code underlined in red and I don't know how to correct them:
UpdateEvent.ValueChanged += **UpdateSpots**;
UpdateSpots is giving me "has an incorrect type of value " (translated to english from my VS GUI language).
And,
ValueChangedEventHandler handler = new ValueChangedEventHandler(**value**);
value is giving me "waiting name of method" error.
Thank you in advance.

Forwarding Events of Different Type

I'm trying to forward events from one class to objects contained within it (as described here: Forwarding events in C#). However, the events are of different type.
For example, I have a class Item which exposes a ValueChanged event handler of type EventHandler. The class ItemHaver exposes an EventHandler<StatusEventArgs>, which should fire whenever Item.ValueChanged does, but should also provide additional information. How do I properly implement add/remove to the ItemValueChanged event declaration?
In the below code, would the lambda function in the add method perform the correct action, and if so, what's the proper way to handle the remove?
class Item
{
public event EventHandler ValueChanged;
}
class ItemHaver
{
private int _status;
private Item _item;
public event EventHandler<StatusEventArgs> ItemValueChanged
{
add
{
_item.ValueChanged += value; // Wrong type
_item.ValueChanged +=
(obj, e) => value(obj, new StatusEventArgs(this._status));
}
remove
{
_item.ValueChanged -= // Does this even work?
(obj, e) => value(obj, new StatusEventArgs(this._status));
}
}
}
class StatusEventArgs : EventArgs
{
int Status { get; private set; }
StatusEventArgs(int status) { Status = status; }
}
I'd try using a dictionary in which I map the handlers.
class ItemHaver
{
private int _status;
private Item _item;
private Dictionary<EventHandler<StatusEventArgs>, EventHandler> handlersMap = new Dictionary<EventHandler<StatusEventArgs>, EventHandler>();
public event EventHandler<StatusEventArgs> ItemValueChanged
{
add
{
// _item.ValueChanged += value; // Wrong type
handlersMap.Add(value, (obj, e) => value(obj, new StatusEventArgs(this._status)));
_item.ValueChanged += handlersMap[value];
}
remove
{
_item.ValueChanged -= handlersMap[value];
}
}
}

I can't register event CollectionChanged of ObservableCollection

I try to run some code when collection is changed. I keep collection as property in Data class:
public static ObservableCollection<OfferedConfiguration> DeviceAdjustedConfigurations
{
get { return deviceAdjustedConfigurations; }
set { deviceAdjustedConfigurations = value; }
}
and register it in code like that:
Data.DeviceAdjustedConfigurations.CollectionChanged += new NotifyCollectionChangedEventHandler(DeviceAdjustedConfigurationsCollectionChanged);
But after registration CollectionChanged is null and the appropriate code in delegated method is not run. In this place DeviceAdjustedConiguration already contains some data. What am I doing wrong?
You should avoid having a set property accessor for collection types, one reason being the one you experienced here with events. Another problem is if someone caches the collection and adds items to it later.
var old = obj.DeviceAdjustedConfigurations;
obj.DeviceAdjustedConfigurations = new ObservableCollection<OfferedConfiguration>();
old.Add(new OfferedConfiguration()); // what should happen here?
instead, remove the set-accessor and use the existing collection directly.
obj.DeviceAdjustedConfigurations.Add(new OfferedConfiguration());
If you really need to set the collection, you need to handle this with for instance a property change event from the class that owns the DeviceAdjustedConfigurations.
public class Item
{
public static ObservableCollection<OfferedConfiguration> DeviceAdjustedConfigurations
{
get { return deviceAdjustedConfigurations; }
set
{
if (deviceAdjustedConfigurations != value)
{
onDeviceConfigurationsChanging(deviceAdjustedConfigurations, value);
deviceAdjustedConfigurations = value;
}
}
}
public static event EventHandler<ConfigurationChangedEventArgs> DeviceConfigurationsChanging;
private static void onDeviceConfigurationsChanging(
ObservableCollection<OfferedConfiguration> oldList,
ObservableCollection<OfferedConfiguration> newList)
{
var handler = DeviceConfigurationsChanging;
if (handler != null)
{
handler(null, new ConfigurationChangedEventArgs(oldList, newList));
}
}
}
public class ConfigurationChangedEventArgs : EventArgs
{
public ConfigurationChangedEventArgs(
ObservableCollection<OfferedConfiguration> oldList,
ObservableCollection<OfferedConfiguration> newList)
{
OldList = oldList;
NewList = newList;
}
public ObservableCollection<OfferedConfiguration> OldList { get; private set; }
public ObservableCollection<OfferedConfiguration> NewList { get; private set; }
}
public class Consumer
{
public void foo()
{
Item.DeviceConfigurationsChanging += updateEvents;
}
private void updateEvents(object sender, ConfigurationChangedEventArgs args)
{
args.OldList.CollectionChanged -= onCollectionChanged;
args.NewList.CollectionChanged += onCollectionChanged;
}
private void onCollectionChanged(object sender, NotifyCollectionChangedEventArgs args) { }
}

Unable to remove cast event handler

I have a design pattern (not sure if this is a commonly used DP, if someone has a name for it please let me know) where I have have a non-generic and a generic interface for a class. The implementation stores generic values and implements the generics interface implicitly. It also explicitly implements the non-generic interface with each property returning the value of the generic property suitably cast to its non-generic form. This works really well for properties, but I am having a few issues getting it to work quite as nicely for events.
Below is a greatly simplified version of what I am doing. The idea is that adding handlers to either interfaces version of Event should add it to the same event so that when the event fires it doesn't matter how it was subscribed to. The test code in Main shows that the event handler is not being removed as I would expect. What is the correct code for adding to/removing from Event using INormalInterface.Event's add/remove blocks?
class Program
{
static void Main(string[] args)
{
INormalInterface x = new ImplementingClass<int>();
Console.WriteLine("Created x and invoking...");
x.InvokeEvent();
Console.WriteLine("Adding event and invoking...");
x.Event += x_Event;
x.InvokeEvent();
Console.WriteLine("Removing event and invoking...");
x.Event -= x_Event;
x.InvokeEvent();
Console.WriteLine("Done.");
Console.ReadKey(true);
}
static void x_Event(object sender, NormalEventArgs e)
{
Console.WriteLine("Event Handled!");
}
}
interface INormalInterface
{
event EventHandler<NormalEventArgs> Event;
void InvokeEvent();
}
interface IGenericInterface<T> : INormalInterface
{
new event EventHandler<GenericEventArgs<T>> Event;
}
class ImplementingClass<T> : IGenericInterface<T>
{
public event EventHandler<GenericEventArgs<T>> Event;
event EventHandler<NormalEventArgs> INormalInterface.Event
{
add { Event += new EventHandler<GenericEventArgs<T>>(value); }
remove { Event -= new EventHandler<GenericEventArgs<T>>(value); }
}
public void InvokeEvent()
{
if (Event != null)
{
Event(this, new GenericEventArgs<T>());
}
}
}
class NormalEventArgs : EventArgs
{
}
class GenericEventArgs<T> : NormalEventArgs
{
}
I figure the issue is because I am 'new'ing the delegate each time so it won't resolve to the same value when adding/removing, is there a way to cast delegates? I do have one solution but it requires having a field for each event, so would appreciate any solutions that avoids this:
class ImplementingClass<T> : IGenericInterface<T>
{
private readonly Dictionary<EventHandler<NormalEventArgs>, EventHandler<GenericEventArgs<T>>> m_eventDictionary = new Dictionary<EventHandler<NormalEventArgs>, EventHandler<GenericEventArgs<T>>>();
public event EventHandler<GenericEventArgs<T>> Event;
event EventHandler<NormalEventArgs> INormalInterface.Event
{
add { Event += m_eventDictionary[value] = new EventHandler<GenericEventArgs<T>>(value); }
remove { Event -= m_eventDictionary[value]; }
}
public void InvokeEvent()
{
if (Event != null)
{
Event(this, new GenericEventArgs<T>());
}
}
}
This does the trick, but I wouldn't call it pretty:
event EventHandler<NormalEventArgs> INormalInterface.Event
{
add
{
var handler = (EventHandler<GenericEventArgs<T>>)Delegate.CreateDelegate(typeof(EventHandler<GenericEventArgs<T>>), value.Target, value.Method);
Event += handler;
}
remove
{
var handler = (EventHandler<GenericEventArgs<T>>)Delegate.CreateDelegate(typeof(EventHandler<GenericEventArgs<T>>), value.Target, value.Method);
Event -= handler;
}
}
The issue with
add { Event += new EventHandler<GenericEventArgs<T>>(value); }
is that it creates a delegate for the Delegate.Invoke method, so it cannot find a match in the event's multicast delegate. Is that, and not the creation of a new object itself, that prevents you from removing the handler.
New Answer
Not the prettiest, but this seems to do the trick:
event EventHandler<NormalEventArgs> INormalInterface.Event
{
add { Event += new EventHandler<GenericEventArgs<T>>(value); }
remove
{
var d = Event.GetInvocationList().First(x => x.Target.GetHashCode() == value.GetHashCode());
Event -= (EventHandler<GenericEventArgs<T>>) d;
}
}
Original Answer:
It seems to me that you have your interfaces around the wrong way - unless you have an existing reason for it, I would change it to be like this:
class Program
{
static void Main(string[] args)
{
IGenericInterface<int> x = new ImplementingClass<int>();
Console.WriteLine("Created x and invoking...");
x.InvokeEvent();
Console.WriteLine("Adding event and invoking...");
x.Event += x_Event;
x.InvokeEvent();
Console.WriteLine("Removing event and invoking...");
x.Event -= x_Event;
x.InvokeEvent();
Console.WriteLine("Done.");
Console.ReadKey(true);
}
static void x_Event(object sender, NormalEventArgs e)
{
Console.WriteLine("Event Handled!");
}
}
interface IBaseInterface<T> where T : EventArgs
{
event EventHandler<T> Event;
void InvokeEvent();
}
interface INormalInterface : IBaseInterface<NormalEventArgs>
{
}
interface IGenericInterface<T> : IBaseInterface<GenericEventArgs<T>>
{
}
class ImplementingClass<T> : IGenericInterface<T>
{
public event EventHandler<GenericEventArgs<T>> Event;
public void InvokeEvent()
{
if (Event != null)
{
Event(this, new GenericEventArgs<T>());
}
}
}
class NormalEventArgs : EventArgs
{
}
class GenericEventArgs<T> : NormalEventArgs
{
}
I think that the observer pattern could be used here http://www.dofactory.com/Patterns/PatternObserver.aspx
using System;
using System.Collections.Generic;
namespace DoFactory.GangOfFour.Observer.RealWorld
{
/// <summary>
/// MainApp startup class for Real-World
/// Observer Design Pattern.
/// </summary>
class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
static void Main()
{
// Create IBM stock and attach investors
IBM ibm = new IBM("IBM", 120.00);
ibm.Attach(new Investor("Sorros"));
ibm.Attach(new Investor("Berkshire"));
// Fluctuating prices will notify investors
ibm.Price = 120.10;
ibm.Price = 121.00;
ibm.Price = 120.50;
ibm.Price = 120.75;
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Subject' abstract class
/// </summary>
abstract class Stock
{
private string _symbol;
private double _price;
private List<IInvestor> _investors = new List<IInvestor>();
// Constructor
public Stock(string symbol, double price)
{
this._symbol = symbol;
this._price = price;
}
public void Attach(IInvestor investor)
{
_investors.Add(investor);
}
public void Detach(IInvestor investor)
{
_investors.Remove(investor);
}
public void Notify()
{
foreach (IInvestor investor in _investors)
{
investor.Update(this);
}
Console.WriteLine("");
}
// Gets or sets the price
public double Price
{
get { return _price; }
set
{
if (_price != value)
{
_price = value;
Notify();
}
}
}
// Gets the symbol
public string Symbol
{
get { return _symbol; }
}
}
/// <summary>
/// The 'ConcreteSubject' class
/// </summary>
class IBM : Stock
{
// Constructor
public IBM(string symbol, double price)
: base(symbol, price)
{
}
}
/// <summary>
/// The 'Observer' interface
/// </summary>
interface IInvestor
{
void Update(Stock stock);
}
/// <summary>
/// The 'ConcreteObserver' class
/// </summary>
class Investor : IInvestor
{
private string _name;
private Stock _stock;
// Constructor
public Investor(string name)
{
this._name = name;
}
public void Update(Stock stock)
{
Console.WriteLine("Notified {0} of {1}'s " +
"change to {2:C}", _name, stock.Symbol, stock.Price);
}
// Gets or sets the stock
public Stock Stock
{
get { return _stock; }
set { _stock = value; }
}
}
}

listener c# like java

I have field string in struct,
and i want learn real-time changed this field.
struct example {
public string ex;
}
examp = new example();<BR>
examp.ex = "test";
////// then program work and eamp.ex = "bing";
I need method
on_ex_changed()
{
if examp.ex changed then .....
}
online and simple plz
You can put an event at the setter as follows.
The event will be fired every time the setter is called.
public class MyObj
{
private RectangleF mRectangle;
public event EventHandler RectangleChanged;
public RectangleF Rectangle
{
get
{
return mRectangle;
}
set
{
mRectangle = value;
OnRectangleChanged();
}
}
protected virtual void OnRectangleChanged()
{
if (RectangleChanged != null)
{
RectangleChanged(this, EventArgs.Empty);
}
}
}

Categories