how to implement on change notification on a object - c#

I have a plain normal class, e.g.:
public class ObjectA
{
public string val {get;set;}
...
}
in another class, it holds an instance of ObjectA, e.g.:
public class ObjectB
{
private ObjectA objectA;
....
}
the instance "objectA" will be frequently changed.
i mean in ObjectB, some of the method will new and new instance of Object A and assign to "objectA"
is there a way to implement a trigger, whenever instance objectA is change, will allow me to do something, e.g.:
objectA += OnChanged_ObjectA
protected void OnOnChanged_ObjectA()
{
// do something
}

You can create a change event on ObjectA that you will fire for any of the changes you wish to track. This will allow you to subscribe to this event on any other object, including ObjectB.
In Object1.cs:
// Delegate type for the event handler
public delegate void MyEventHandler();
// Declare the event.
public event MyEventHandler MyEvent;
// In the properties or any place you what to notify of change:
if (MyEvent != null)
MyEvent();
And in Object2.cs you can subscribe:
objectA.MyEvent += OnChanged_ObjectA
protected void OnOnChanged_ObjectA()
{
// Action changes
}

How about :
INotifyPropertyChanged Interface
http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx

I had such problem recently, but unfortunately, I didn't find any another solution, but this:
public ObjectB
{
private ObjectA _objectA;
public ObjectA objectA
{
get
{
return _objectA;
}
set
{
if (value != _objectA)
{
_objectA = value;
RaiseObjectAChanged(/* sender, args */);
}
}
}
private RaiseObjectAChanged()
{
// raise event here
}
private OnObjectAChanged()
{
// event handler
}
}

Related

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.

Subscribe eventhandler to reference that is null

I'm currently writing an application in which I deserialize relatively large objects (which can also grow in size, depending on what the user adds to them). I don't want to load all of them into RAM since that might cause problems when there are many of them.
Anyway, I want to handle events raised by the loaded instance of that class if there is one which is already my problem.
How can I subscribe an event handler to an object that is still null?
I think of something like "if there is an object and it raises that event handle it with that method".
Here is some sample code and the only approach I could think of though I already thought it couldn't work..
public class MyClassA
{
public event EventHandler PropertyChanged;
private string someProperty
public string SomeProperty
{
set
{
someProperty = value;
PropertyChanged?.Invoke(this, EventArgs.Empty);
}
}
public static MyClassA Load(string path)
{
/*...*/
}
}
public class MyClassB
{
public MyClassA InstanceOfA { get; private set; }
public MyClassB
{
//InstanceOfA.PropertyChanged += MyEventHandler; Not working, NullReference
}
// Handle InstanceOfA.PropertyChanged here...
public void MyEventHandler(object sender, EventArgs e)
{
/*...*/
}
}
Of course you cannot subscribe an event handler to an object that is still null,but you can subscribe when you assign a non null value to it.
Just use a property and a backing field:
public class MyClassB
{
private MyClassA myVar;
public MyClassA InstanceOfA
{
get { return myVar; }
private set
{
myVar = value;
if (myVar != null)
myVar.PropertyChanged += MyEventHandler;
}
}
public void MyEventHandler(object sender, EventArgs e)
{
}
}

Return value of a Property from child ViewModel to parent ViewModel

In my WPF MVVM app, using Caliburn.Micro, I have a ViewModel, CreateServiceViewModel that, on a button click, opens a GridView in a seperate window for the User to chose a Row from.
I created another ViewModel for this, MemberSearchViewModel which has two properties:
private Member selectedMember;
public Member SelectedMember
{
get { return selectedMember; }
set { selectedMember = value; }
}
private IList<Member> members;
public IList<Member> Members
{
get { return members; }
set { members = value; }
}
How do I get that SelectedMember value back to the calling ViewModel? That ViewModel has a property of Service.SelectedMember.
EventAggregator is what you could use... One of many solutions I am sure.
public class MessageNotifier{
public object Content{get;set;}
public string Message {get;set;}
}
//MEF bits here
public class HelloWorldViewModel: Screen, IHandle<MessageNotifier>{
private readonly IEventAggregator _eventAggregator
//MEF constructor bits
public YourViewModel(IEventAggregator eventAggregator){
_eventAggregator = eventAggregator;
}
public override OnActivate(){
_eventAggregator.Subscribe(this);
}
public override OnDeactivate(){
_eventAggregator.UnSubscribe(this);
}
//I Handle all messages with this signature and if the message applies to me do something
//
public void Handle(MesssageNotifier _notifier){
if(_notifier.Message == "NewSelectedItem"){
//do something with the content of the selectedItem
var x = _notifier.Content
}
}
}
//MEF attrs
public class HelloWorld2ViewModel: Screen{
private readonly IEventAggregator _eventAggregator
//MEF attrs
public HelloWorld2ViewModel(IEventAggregator eventAggregator){
_eventAggregator = eventAggregator;
}
public someobject SelectedItem{
get{ return _someobject ;}
set{ _someobject = value;
NotifyOfPropertyChange(()=>SelectedItem);
_eventAggregator.Publish(new MessageNotifier(){ Content = SelectedItem, Message="NewSelectedItem"});
}
}
One option is to utilize NotifyPropertyChanged. Since you are working with ViewModels, they most likely implement INotifyPropertyChanged, which you can make use of just as the framework does.
When your CreateServiceViewModel creates the MemberSearchViewModel, it would just subscribe to the PropertyChanged event:
//This goes wherever you create your child view model
var memberSearchViewModel = new MemberSearchViewModel(); //Or using a service locator, if applicable
memberSearchViewModel.PropertyChanged += OnMemberSearchPropertyChanged;
private void OnMemberSearchPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == "SelectedMember")
{
//Code to respond to a change in the Member
}
}
And then in your MemberSearchViewModel, you simply raise the NotifyPropertyChanged event when the user has selected a member from the grid.
EDIT:
As #DNH correctly notes in the comments, using event handlers like this can lead to memory leaks if not properly cleaned up. So when you are finished with the MemberSearchViewModel, make sure to unsubscribe to the PropertyChanged event. So for example, if you only need it until the user selects a member, you could put it inside the Property Changed Handler itself (I've switched it to use a class-level variable to hold the ViewModel):
private void OnMemberSearchPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == "SelectedMember")
{
//Code to respond to a change in the Member
//Unsubscribe so the view model can be garbage collected
_memberSearchViewModel.PropertyChanged -= OnMemberSearchPropertyChanged;
_memberSearchViewModel = null;
}
}
One option would be to store MemberSearchViewModel as a field of CreateServiceViewModel and define CreateServiceViewModel.SelectedMember property as follows:
public Member SelectedMember
{
get
{
return _memberSearchViewModel.SelectedMember;
}
set
{
_memberSearchViewModel.SelectedMember = value;
}
}
How about?
public interface INotifyMe<T>
{
T ResultToNotify { get; set; }
}
public class CreateServiceViewModel : ViewModelBase, INotifyMe<Member>
{
// implement the interface as you like...
}
public class MemberSearchViewModel : ViewModelBase
{
public MemberSearchViewModel(INotifyMe<Member> toBeNotified)
{
// initialize field and so on...
}
}
Now you could let listen CreateServiceViewModel to its own property and you won't have to think about the removal of the event listener.
Well of course to do the more classical way you could alternatively use an interface like this.
public interface INotifyMe<T>
{
void Notify(T result);
}
As a follow-up to my comment, here's an example using Prism - I've never used Caliburn.
Create an event - the event's payload will be your SelectedMember:
public class YourEvent:CompositePresentationEvent<YourEventPayload>{}
Publish the event:
EventAggregator.GetEvent<YourEvent>().Publish(YourEventPayload);
Subscribe to the event:
EventAggregator.GetEvent<YourEvent>().Subscribe((i) => ...);

Call a method in a class when a property of an injected object changes

If I have a member, constructor and method like so
//The injected object exposes a public property of type bool which will raise
//a NotifyPropertyChangedEvent
IInjectedObject _injectedObject;
public someClass(IInjectedObject injectedObject)
{
_injectedObject = injectedObject;
}
public void DoSomething()
{
}
Is there a way to call the method in my class when the property on the injected object changes?
You state that your interface inherits from INotifyPropertyChanged, so it can reasonably be expected to notify listeners of property changes through the "PropertyChanged" event. Assuming something like this:
public interface IInjectedObject : INotifyPropertyChanged
{
bool MyImportantProperty { get; }
}
Then, your dependant object must listen for the INotifyPropertyChanged.PropertyChanged event:
public class MyDependantClass
{
public MyDependantClass(IInjectedObject injectedObject)
{
MyInjectedObject = injectedObject;
}
// We wrap the private field in a protected property,
// to capture the event subscriptions
private IInjectedObject _myInjectedObject;
protected IInjectedObject MyInjectedObject
{
get { return _myInjectedObject; }
set
{
// unsubscribe from the old property's event
if(_myInjectedObject!= null)
_myInjectedObject.PropertyChanged -= OnPropertyChanged;
_myInjectedObject= value;
// subscribe to the new property's event
if(_myInjectedObject!= null)
_myInjectedObject.PropertyChanged += OnPropertyChanged;
}
}
private void OnPropertyChanged(object sender, PropertyChangedEventArgs args)
{
if(args.PropertyName == "MyImportantProperty")
{
//react to the changed property here!
}
}
}

How to make only farthest child receive shared event?

I have run into a bit of a design issue with my code.
I have a object that creates a child object (the child could then create another child, etc), and both objects subscribe to the same event.
But, I only want the most child object to receive the event.
Overview of what my project is:
I am creating a IVR system. When a user calls into the system, the user will have X menu choices. Based on what the user chooses they will have a sub menu of choices, and so on and so on. I am using State Machines for this. Every State Machine needs to "listen" for when the user presses a number on their phone. But only the current State Machine needs to process the entered number. Each State Machine can create a new State Machine to represent the sub menu.
Here is some sample code:
Base class:
public delegate void DoSomething(object sender, EventArgs data);
public class Base
{
public event DoSomething myEvent;
private IObject foo;
public Base ()
{
foo = new myObjectA(this);
}
public void SomeAction()
{
((myObjectA)foo).CreateChild();
}
public void EventFired()
{
if (myEvent != null)
{
myEvent(this, new EventArgs());
}
}
}
ObjectA:
class myObjectA : IObject
{
private Base theCallingObject;
private IObject child;
public myObjectA (Base _base)
{
theCallingObject = _base;
theCallingObject.myEvent += new DoSomething(theCallingObject_myEvent);
}
public void CreateChild()
{
child = new myObjectB(theCallingObject);
}
void theCallingObject_myEvent(object sender, EventArgs data)
{
// Handle event
MessageBox.Show("myObjectA");
}
}
ObjectB:
class myObjectB : IObject
{
private Base theCallingObject;
public myObjectB (Base _base)
{
theCallingObject = _base;
theCallingObject.myEvent += new DoSomething(theCallingObject_myEvent);
}
void theCallingObject_myEvent(object sender, EventArgs data)
{
// Handle event
MessageBox.Show("myObjectB");
}
}
Now when I do this:
Base blah = new Base();
blah.SomeAction();
blah.EventFired();
I get message boxes for both A and B.
I need to implement Base so that only myObjectB gets the event.
I will have hundreds of myObject's so I need a implementation at the Base level and NOT the myObject level. Plus, handling it at the myObject level would still require the event to be fired causing performance issues if there are hundreds of objects.
One solution I have considered is when myObjectA creates the child, unsubscribe from the event, then resubscribe when we get back to the myObjectA level. However I feel something better could be done.
Anyone have any ideas?
Edit: Using payo's input I have come up with this:
public delegate void DoSomething(object sender, EventArgs data);
public class Base
{
private IObject foo;
private List<DoSomething> _myEventStorage;
public event DoSomething myEvent
{
add
{
_myEventStorage.Insert(0, value);
}
remove
{
_myEventStorage.Remove(value);
}
}
public Base ()
{
_myEventStorage = new List<DoSomething>();
foo = new myObjectA(this);
}
public void SomeAction()
{
((myObjectA)foo).CreateChild();
}
public void EventFired()
{
_myEventStorage[0].Invoke(this, new EventArgs());
}
}
you would need to explicitly implement myEvent (add/remove) handlers and track the "farthest" independently of the registered observers. then you can send the notification to that single instance.
For events, each subscriber is queued up (put at end of list), a FIFO model. You want the most-child object to 'own' the event, not just subscribe and be part of some abstract list of other unknown objects.
I would provide a new model that represents what you are trying to do. This might be what Jason recommended: (he posted his answer as I was typing this out)
public class Base
{
private DoSomething _myEventStorage;
public event DoSomething myEvent
{
add
{
_myEventStorage = value;
}
remove
{
_myEventStorage -= value;
}
}
...
public void EventFired()
{
if (_myEventStorage != null)
{
_myEventStorage(this, new ChainEventArgs());
}
}
}
This calls last ONLY. Another option (to add to this custom add/remove) would be to provide a derived EventArgs:
public class ChainEventArgs : EventArgs
{
public bool Handled { get; set; }
}
public delegate void DoSomething(object sender, ChainEventArgs data);
...
public event DoSomething myEvent
{
add
{
var temp = _myEventStorage;
_myEventStorage = null;
_myEventStorage += value;
_myEventStorage += temp; // now all are called, but FILO
}
remove
{
_myEventStorage -= value;
}
}
At this point, you can either check Handled on each IObject
void theCallingObject_myEvent(object sender, ChainEventArgs data)
{
if (data.Handled)
return;
if (I_want_to_block_parents)
data.Handled = true;
// else leave it false
}
Or, add some complexity to your Base class and stop calling up the chain (let's the children have no need to check Handled). I'll show the solution with a List<> of delegates, but some MulticaseDelegate casts and calls could do the same. I just feel the List<> code might be more readable/maintainable.
public class Base
{
private List<DoSomething> _myEventStorage;
public event DoSomething myEvent
{
add
{
_myEventStorage.Insert(0, value);
}
remove
{
_myEventStorage.Remove(value);
}
}
...
public void EventFired()
{
var args = new ChainEventArgs();
foreach (var handler in _myEventStorage)
{
handler(this, args);
if (args.Handled)
break;
}
}
}

Categories