473,322 Members | 1,188 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,322 software developers and data experts.

Dynamically raising an event in another class

I have just started to write a few business classes that are largely made up
of properties (getters and setters). For each setter I want to fire a
changed event - each event will have a unique name

e.g.

public class CBusinessObject
{
private CProperty<longm_propId;
private CProperty<stringm_propName;

public CBusinessObject()
{
m_propId = new CProperty<long>();
m_propName = new CProperty<string>();
}

public long Id
{
get
{
return m_propId.Value;
}
set
{
m_propId.Value = value;
}
}

public string Name
{
get
{
return m_propName.Value;
}
set
{
m_propName.Value = value;
}
}

public delegate void IdChangedHandler(long originalValue, long newValue);
public delegate void NameChangedHandler(string originalValue, string
newValue);

public event IdChangedHandler IdChanged;
public event NameChangedHandler NameChanged;
}

I could declare each property as a member variable of the appropriate type;
and for each setter write code that checks if the value has changed before
firing the event.

However this seems a bit repetitive (and error prone), so I came up with the
idea of using a property class. In principle this is fine, but what I would
like to do is get the property class to fire the changed event from the
setter, somehow invoking the event on the business object. Thus all
listeners to the event on the business class will recieve the appropriate
event.

The stub for my propery class is below. I have tried a number of things
including reflection and passing arround event delgates, but I have not had
any success. Any help would be much appreciated.

public class CProperty<T>
{
private T m_value;
//I suspect that I need a member variable(s) here to point to the event
in the calling class

public CProperty(/* some info from calling class */)
{
//set member variables
}

public virtual T Value
{
get
{
return m_value;
}
set
{
if (value.Equals(m_value) == false)
{
FireValueChangedEvent(m_value, value);
}

m_value = value;
}
}

private void FireValueChangedEvent(T originalValue, T newValue)
{
//What should I do here?
}
}
Oct 17 '06 #1
5 4387
I recommend using a generic delegate instead of different delegates for each
property's event.

public delegate void PropertyChangeHandler<T>(T originalValue, T newValue);

Pass an instance of the delegate into the constructor of your property class
and use it from the setter:

public class CProperty<T>
{
private T m_value;
private PropertyChangeHandler<Tm_event;

public CProperty(PropertyChangeHandler<Tevent)
{
m_event = event;
}

public virtual T Value
{
get { return m_value; }
set
{
if (value.Equals(m_value))
return;

T oldValue = m_Value;
m_value = value;

if (m_event != null)
m_event(oldValue, m_value);
}
}
}

Best Regards,
Dustin Campbell
Developer Express Inc.
Oct 17 '06 #2
See
http://msdn.microsoft.com/library/de...tml/BOAGag.asp

How to Expose Events in a Business Entity Component
"kmcmanus" <km******@discussions.microsoft.comwrote in message
news:AB**********************************@microsof t.com...
I have just started to write a few business classes that are largely made
up
of properties (getters and setters). For each setter I want to fire a
changed event - each event will have a unique name

e.g.

public class CBusinessObject
{
private CProperty<longm_propId;
private CProperty<stringm_propName;

public CBusinessObject()
{
m_propId = new CProperty<long>();
m_propName = new CProperty<string>();
}

public long Id
{
get
{
return m_propId.Value;
}
set
{
m_propId.Value = value;
}
}

public string Name
{
get
{
return m_propName.Value;
}
set
{
m_propName.Value = value;
}
}

public delegate void IdChangedHandler(long originalValue, long
newValue);
public delegate void NameChangedHandler(string originalValue, string
newValue);

public event IdChangedHandler IdChanged;
public event NameChangedHandler NameChanged;
}

I could declare each property as a member variable of the appropriate
type;
and for each setter write code that checks if the value has changed before
firing the event.

However this seems a bit repetitive (and error prone), so I came up with
the
idea of using a property class. In principle this is fine, but what I
would
like to do is get the property class to fire the changed event from the
setter, somehow invoking the event on the business object. Thus all
listeners to the event on the business class will recieve the appropriate
event.

The stub for my propery class is below. I have tried a number of things
including reflection and passing arround event delgates, but I have not
had
any success. Any help would be much appreciated.

public class CProperty<T>
{
private T m_value;
//I suspect that I need a member variable(s) here to point to the
event
in the calling class

public CProperty(/* some info from calling class */)
{
//set member variables
}

public virtual T Value
{
get
{
return m_value;
}
set
{
if (value.Equals(m_value) == false)
{
FireValueChangedEvent(m_value, value);
}

m_value = value;
}
}

private void FireValueChangedEvent(T originalValue, T newValue)
{
//What should I do here?
}
}

Oct 17 '06 #3
Well:
value.Equals(m_value) == false
This will break going from not-null to null; suggest:
if(!EqualityComparer<T>.Default.Equals(value, m_value))

For the actual issue; 3 options:
1: Place a ValueChanged event on CProperty<T>, and subscribe to this
from the parent; the parent would implement INotifyPropertyChanged,
identify the property name on catching the event, and raise it's own
PropertyChanged event with that name. I don't like the eventing model,
though. Getting the name could be a pain, though, as the propert
doesn't know.

2: Like 1, but the property knows it's parent (via a common interface
or similar), and call something like parent.OnPropertyChanged(....);
again, the problem is knowing the property name.

{aside: perhaps let the property in on the secret? solves problems for
1 & 2}

3: if this is for WinForm binding, you could also virtualise this to
the component mode via ICustomPropertyDescriptor, a bespoke
GetProperties, and custom AddHandler / RemoveHandler code; then the
parent doesn't even need to get involved in the events.

4: different model (code via notepad, so don't assume 100%; should be
close, though):

public abstract class SomeBaseClass : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged
protected bool UpdateField<T>(ref T field, T value, string
propertyName) {
if(EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true; // notify caller of change for more processing
}
protected void OnPropertyChanged(string propertyName) {
PropertyChangedEventHandler handler = PropertyChanged;
if(handler!=null) handler(this, new
PropertyChangedEventArgs(propertyName));
}
}
public class SomeClass : SomeBaseClass {
private int someValue;
public int SomeValue {
get {return someValue;}
set {UpdateField(ref someValue, value, "SomeValue");}
}
// etc
}

etc

I use variants of both 3 & 4 happily.

Marc

Oct 18 '06 #4
Thanks for all your responses. Some were ideas that I had already tried and
others were new to me.

The solution that I used in the end was based upon Dustin's suggestion.
Unfortunaetly (as I had already seen) Dustin's approach will not work as
expected - When creating the property you pass in a delegate, and unless this
delegate has any subscribers this will be null. If you later add some
subscribers, and set the value, the delegate is still null.

To get around the above issue, I made the property read only, and created a
SetValue() method that takes in the delegate. I can then call the
DynamicInvoke() method on delegate.

public virtual void SetValue(T value, DValueChanged changedEvent)
{
if (value.Equals(m_value) == false)
{
if (changedEvent != null)
{
object[] colParams = new object[3];
colParams[0] = m_owner;
colParams[1] = m_value;
colParams[2] = value;

changedEvent.DynamicInvoke(colParams);
}
}

m_value = value;
}

public delegate void DValueChanged(object sender, T originalValue, T
newValue);
For those that are interested I also did some more investigation using
reflection. The results are not as friendly as the approach used above, but
it is another option for those that want it.

Instead of using a common base class / interface as suggested by Marc, when
you create the property class you can pass in the instance of the class that
owns the property, and the name of a method to call that will fire the event.
e.g.

CProperty<stringpropName = new CProperty(this, "OnNameChanged");

Your on NameChanged method would then be responsible for firing the event.

This doesn't really add anything new, I was simply curious. What I really
wanted to do was pass in the name of the event (or its type), and then using
reflection fire the event with this name. There is a method on EventInfo
called GetRaiseMethod(), which you should be able call to raise your event.
Unfortunatly (and this is documented by microsoft) this will always return
null for an event writen in c#.

P.S. Cheers Marc for the equality suggestion, I have not fixed this yet but
I will do so now.
>value.Equals(m_value) == false
This will break going from not-null to null; suggest:
if(!EqualityComparer<T>.Default.Equals(value, m_value))
Oct 23 '06 #5
The solution that I used in the end was based upon Dustin's
suggestion. Unfortunaetly (as I had already seen) Dustin's approach
will not work as expected - When creating the property you pass in a
delegate, and unless this delegate has any subscribers this will be
null. If you later add some subscribers, and set the value, the
delegate is still null.
Yeah, such is the danger of typing code directly into my news reader. My
apologies for the land mine in that solution but I'm glad you got it working.

Best Regards,
Dustin Campbell
Developer Express Inc.
Oct 23 '06 #6

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
by: Santhoshi | last post by:
I have an event declared in class1 Now i want to raise the event in the my class2 or anywhere other than class1 Is it possible? If so how Thank you
6
by: Dan | last post by:
I've created a pocketpc app which has a startup form containing a listview. The form creates an object which in turn creates a System.Threading.Timer. It keeps track of the Timer state using a...
4
by: rawCoder | last post by:
Hi all, How Can You Raise Events Asynchronously ? Now for the details ... I want to do inter modular communication using events in such a way that the contributing modules need not...
2
by: Sam | last post by:
I have a custom control (MyTextBox - taken from Microsoft website) that implements the IPostBackDataHandler interface. It is added to the controls collection of a placeholder control during the...
15
by: Amit D.Shinde | last post by:
I am adding a new picturebox control at runtime on the form How can i create click event handler for this control Amit Shinde
4
by: Dave A | last post by:
I am developing a somewhat complex component at the moment and coincidently I am also reading the Framework Design Guidelines book. After reading the section about event raising I have re-written...
2
by: Gman | last post by:
Hi, I have created a usercontrol, a grid control essentially. Within it I have a class: clsGridRecord. I have coded the events such that when a user clicks on the grid, say, the events occur on...
3
by: George | last post by:
Hi, I have searched on the net quite a bit, but the more I read, the more confused I get. I want to see if I can raise an event out side of the class. I believe this can be done in VB (at...
1
by: Asko Telinen | last post by:
Hi all. I ran into quite strange problem concerning the event raising inside FileSystemWatcher Delete event. First, i would like to describe a bit my environment. I have main GUI...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.