I've tried looking at other topics on this but I haven't found a working implementation to my question. Basically, I have an ObservableCollection called "FruitBasket" that contains different kinds of fruit. FruitBasket itself contains ObservableCollections for each respective type of fruit that passes through so that they can be used as ItemSources for ListViews (Denoted by their names "AppleContainer" and "OrangeContainer"), each displaying one kind of fruit. Because the fruit classes themselves implement INotifyPropertyChanged, modifying their values triggers updates to the ListView controls just fine, however, FruitBasket has a "TotalWeight" property derived from the weights of all the other fruits in the collections. I want "TotalWeight" to update the Label control in the UI without me having to refresh the UI. Triggerering a notification on a property change of the actual ObservableCollection itself, and not simply its constituent members is more difficult and I haven't found any solutions that work so far (or that I've implemented correctly).
public class FruitBasket : ObservableCollection<IFruit>
{
private decimal _totalWeight;
public FruitBasket()
{
this.Add(new OrangeContainer(this));
this.Add(new AppleContainer(this));
}
public OrangeContainer Oranges
{
get { return (OrangeContainer)this.Items[0]; }
}
public AppleContainer Apples
{
get { return (AppleContainer)this.Items[1]; }
}
public decimal TotalWeight
{
get { return _totalWeight; }
set { _totalWeight = value; }
}
internal void UpdateWeight(IFruit caller)
{
_totalWeight = 0;
foreach (Orange orng in (OrangeContainer)this.Items[0])
{
_totalWeight += orng.Weight;
}
foreach (Apple appl in (AppleContainer)this.Items[1])
{
_totalWeight += appl.Weight;
}
}
You need to call INotifyPropertyChanged.PropertyChanged event of your FruitBasket whenever items are added, removed or Weight property of any item has changed.
Let's split it into two tasks:
TotalWeight should be recalculated when items are added, removed, or items' weight is changed. We need to handle those events.
Raise FruitBasket.PropertyChanged event
I have splitted these two tasks into two classes in order to follow Single Responsibility Principle:
1) - this handles items' PropertyChanged events:
public abstract class ExtendedObservableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged
{
protected override void ClearItems()
{
foreach (var item in Items) item.PropertyChanged -= ItemPropertyChanged;
base.ClearItems();
}
protected override void InsertItem(int index, T item)
{
item.PropertyChanged += ItemPropertyChanged;
base.InsertItem(index, item);
}
protected override void RemoveItem(int index)
{
this[index].PropertyChanged -= ItemPropertyChanged;
base.RemoveItem(index);
}
protected override void SetItem(int index, T item)
{
this[index].PropertyChanged -= ItemPropertyChanged;
item.PropertyChanged += ItemPropertyChanged;
base.SetItem(index, item);
}
abstract void ItemPropertyChanged(object sender, PropertyChangedEventArgs e);
}
2) - this recalculates TotalWeight when necessary
public class FruitBasket : ExtendedObservableCollection<IFruit>
{
protected override void ItemPropertyChanged(object sender, PropertyChangedEventArgs e){
UpdateWeight();
OnPropertyChanged("TotalWeight")
}
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
UpdateWeight();
OnPropertyChanged("TotalWeight")
base.OnCollectionChanged(e);
}
}
Of course your Fruit should implement INotifyPropertyChanged interface. You will find plenty of examples how to do it. It is very simple.
I found the root(s) of the problem(s). I'll start with the most obvious:
I wasn't as diligent in assigning datacontext in the UI for the Fruit Basket observable collection object itself as I was the for the members of its collection (OrangeContainer and AppleContainer). In the initialization of the UI window, assigning datacontext to the ListView objects is second nature. I wasn't quite matching the right node's datacontext in the XAML to the Fruit Basket object in the initialization method in the code behind (I really should have checked that earlier).
Because of the misaligned assignments of datacontext/binding, between the XAML and initialization method, the propertychanged event was never firing for my fruit basket observable collection like it was for the Apple and Orange objects inside the OrangeContainer and AppleContainer collections that were members of FruitBasket. So, in the Orange class declaration we'd have this:
public class Orange : INotifyPropertyChanged, IFruit
And the implementation like so
public event PropertyChangedEventHandler PropertyChanged;
public void PropChange(string prop)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
And when the PropChange method was called in the Weight property setter, this.PropertyChanged would not be null, and everything would work fine.
The FruitBasket class was a bit more tricky. Because of the aformentioned issue of improper matching in the UI Code, this.PropertyChanged would return null every time I tried to notify a change in property. However, it got a bit more confusing because unlike the Orange or Apple classes, it inherits ObservableCollection (ObservableCollection in the declaration if we want to be specific). I know ObservableCollection is really just a Collection class that implements INotifyPropertyChanged and INotifyCollectionChanged interfaces. It's really nice to see the plumbing now that .NET is open source (praise the lord)
http://referencesource.microsoft.com/#System/compmod/system/collections/objectmodel/observablecollection.cs
In any case, implementing this became more confusing, because I kept seeing this:
Warning 1 'TestingObsColNotify.FruitBasket.PropertyChanged' hides inherited member 'System.Collections.ObjectModel.ObservableCollection.PropertyChanged'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword. C:\Testing VS Project\TestingObsColNotify\TestingObsColNotify\FruitBasket.cs 60 50 TestingObsColNotify
I still see this, but my implementation works, because while it was a result of the inheritance from INotifyProperty changed via ObservableCollection as seen in my original class declaration
public class FruitBasket : ObservableCollection<IFruit>
This was just shy of the last element need to make everything work, which was adding the INotifyPropertyChanged to the class itself like so:
public class FruitBasket : ObservableCollection<IFruit>, INotifyPropertyChanged
It seems a bit redundant and inelegant but I didn't get very far trying to override and wrestle with the inheritance of INotifyPropertyChanged from ObservableCollection (Or as best as I can understand).
So there we have it, everything works now, sans MVVM. I'll certainly move on to that pattern later, but it's nice to have resolved this issue instead of lazily just re-assigning the contents of controls in the code behind methods on the UI side of things.
Thank you to those who came in here and contributed, I appreciate you taking the time to respond.
If using binding, Add the interface INotifyPropertyChanged to your class. If you have ReSharper installed, accept the recommendation to implement the interface. Then, whenever you want to update any text box, call PropertyChanged with the name of the property TotalWeight, see https://softwareengineering.stackexchange.com/questions/228067/where-do-put-inotifypropertychanged-interface-in-model-or-viewmodel. Whenever you update any of the ObservableCollections, manually update the TotalWeight, then call the aforementioned PropertyChanged to tell the UI to update itself. I've used this technique to push updates from the ViewModel into the View (i.e. from the class into the XAML) for some fairly complex scenarios, it works very well.
I'd also recommend following the learning curve for MVVM, projects written in that way tend to be more scalable, are easier to maintain, and just easier to work with.
Related
I have a class, "BaseClass" that implements INotifyPropertyChanged and has the following:
BaseClass:
private bool isOn;
public bool IsOn
{
get { return isOn; }
set
{
isOn = value;
RaisePropertyChanged("BaseClass:IsOn");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
I then have a class, "DIClass" that also implements INotifyPropertyChanged. It also has an ObservableCollection<BaseClass>:
DIClass:
public ObservableCollection<BaseClass> ClassesOfA;
private string iNPCTest;
public string INPCTest
{
get { return iNPCTest; }
set
{
iNPCTest = value;
RaisePropertyChanged("DIClass: INPCTest");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
My ViewModel holds an intance of "DIClass" and registers to it's PropertyChanged event. When I set the value of INPCTest in "DIClass", the ViewModel 'captures' the event correctly. However when I updated the IsOn property within the ObservableCollection, as below, the event is not picked up in the ViewModel.
ClassesOfA[0].IsOn = true;
Why is the INPC interface not working with the nested property? The question and answer here seems quite relevant, but I can't figure it out.
EDIT: additional explanation and code:
I can register to the PropetyChanged events of the ObservableCollection's items, as such:
ClassesOfA[0].PropertyChanged += DIClass_PropertyChanged;
ClassesOfA[1].PropertyChanged += DIClass_PropertyChanged;
However, this still does not bubble up to notify my ViewModel, that a property of my DIClass's ObservableCollection<BaseClass> has changed. I want to use INPC to bubble up event information / property updates up via MVVM layers. But I want to "wrap" them to make my classes cleaner/ less properties lying around
EDIT:
I add this "sketch" of my problem/scenario, with basic naming to make it easy:
To answer your question: This is by design.
ObservableCollection has two events:
CollectionChanged: Fires when the collection changes, e.g. collection.Add( item )
PropertyChanged: Fires when the property changes, e.g. collection = new ObservablecCollection<T>();
I think you need no ObservableCollection, because - as far as I understand your question - you want to observe the changes of the properties of the items in the collection. To achieve that you need to register to each observed item's PropertyChanged like this:
public List<BaseClass> Collection {get;set;}
public void InitializeCollection( IEnumerable<BaseClass> baseClassCollection){
Collection = new List<BaseClass>();
foreach(var item in baseClassCollection){
item.PropertyChanged += MethodToCallOnPropertyChanges;
Collection.Add( item );
}
}
public void MethodToCallOnPropertyChanges(object sender, PropertyChangedEventArgs e){
//react to any property changes
doSomething();
//react to specific properties
if(e != null && e.PropertyName.Equals("isOn"))
doSomethingOtherStuff();
}
This can be very annoying and can causes some other problems.
If I would come across this, I would think about redesigning the ViewModels and the UI. I would try to have an UI which is bound to each BaseClass item. For example, if I have an ListView I would provide an ItemTemplate in which the BaseClass item is bound. Doing so would prevent the need of registering to each item's PropertyChanged.
My suggestion is that you could create a customized ObservableCollection class that raises a Reset action when a property on a list item changes. It enforces all items to implement INotifyPropertyChanged.
I made a simple demo and you that you could check:
public class DIClass : INotifyPropertyChanged
{
public ExObservableCollection<BaseClass> ClassesOfA
... other code...
}
public sealed class ExObservableCollection<T> : ObservableCollection<T>
where T : INotifyPropertyChanged
{
public ExObservableCollection()
{
CollectionChanged += AllObservableCollectionCollectionChanged;
}
public ExObservableCollection(IEnumerable<T> pItems) : this()
{
foreach (var item in pItems)
{
this.Add(item);
}
}
private void AllObservableCollectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (Object item in e.NewItems)
{
((INotifyPropertyChanged)item).PropertyChanged += ItemPropertyChanged;
}
}
if (e.OldItems != null)
{
foreach (Object item in e.OldItems)
{
((INotifyPropertyChanged)item).PropertyChanged -= ItemPropertyChanged;
}
}
}
private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
NotifyCollectionChangedEventArgs args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, sender, sender, IndexOf((T)sender));
OnCollectionChanged(args);
}
}
Then you could use the ExObservableCollection class in the DIClass object. When the properties inside the BaseClass changes, the UI will be updated.
Update:
Finally, I found out the unexpected behavior you mentioned based on the complex sample. The ExObservableCollection class works well and fires the property changed event correctly.
The key point is you think if the property change event in baseclass is fired then it will
trigger the property change event in DIClass as well, right? I have to say that is not correct. The property change event only fires in the current class. It won't pass to the parent class unless you handle it in the parent class. It fired only once and notify the UI when the target property is changed.
If I understand your scenario correctly, you want to change the ToggleButton's status when the same property in BaseClassobject is changed. But the ToggleButtons are bind to VMData objects so that you need to get notified when the BaseClass objects are changed in the DIClass objects. So you want the the property change event of BaseCasss triggers the property change event of the DIClass.
Handling the property changed event of BaseClass in the DIClass object is the correct way to do what you want. It's the same like handling DIClass event in the ViewModel. But you don't want it since there might be many objects.
Then the first version of your sample is the recommended way to achieve what you want by triggering the property changed event of the DIClass on your own.
Lets say I have a model object
class ModelClass
{
public List<Element> eList;
public void MethodA()
{
doSomething();
}
}
I would like to use this object in an MVVM as well. The Viewmodel would then invoke methods like MethodA to manipulate the data and the elements in eList would be updated. Is there a way to do this without making eList an ObservableCollection? I'd like to do so in order to use this ModelClass in other places as well without too much code polution.
If we compare List and ObservableCollection then both are implemented from IList. There isn't much of a difference there. The most difference is ObservableCollection also implements INotifyCollectionChanged interface, which allows WPF to bind to it.
Therefore, if you don't want to use List instead of ObservableCollection in your model class then you need to implement the class with INotifyCollectionChanged:
class ModelClass:INotifyCollectionChanged
{
public List<Element> eList;// call OnCollectionChanged() when you set/add/remove...the list).
public void MethodA()
{
doSomething();
}
#region INotifyCollectionChanged Members
protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (CollectionChanged != null)
CollectionChanged(this, e);
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
#endregion
}
I have a hierarchy of items like the following:
MainClass
{
List<Configuration> MyList = new List<Configuration>;
}
Configuration
{
CustomObject MyObject = new CustomObject;
string Property = "";
}
CustomObject
{
string InnerProperty = "";
}
If I want that MainClass gets notified from every change made to InnerProperty and Property, am I correct to assume that I have to transform the List into an ObservableCollection and that both Configuration and CustomObject should derive from INotifyPropertyChanged, right?
If I want only to get a notify when InnerProperty gets changed, and NOT Property, should only CustomObject derive from INotifyPropertyChanged or Configuration too (since I would lose the notification transmission to the parent)?
To get notification about InnerProperty and Property you don't need ObservableCollection in general. ObservableCollection is only for notifications about added\removed items. So you need to implement INotifyPropertyChanged on both Configuration and CustomObject. If you are only interested in changes of InnerProperty, INotifyPropertyChanged on Configuration is not necessary in case your MyObject property never changes and assigned in constructor. Otherwise, you need again to implement INotifyPropertyChanged on both. Same story with ObservableCollection by the way - if your list contains fixed list of items - you don't need that to receive notifications from properties. Otherwise you do.
If I want only to get a notify when InnerProperty gets changed, and NOT Property, should only CustomObject derive from INotifyPropertyChanged or CustomObject too (since I would lose the notification transmission to the parent)?
(I assume that for the second CustomObject in that sentence you actually mean Configuration.)
If you only change InnerProperty and MyProperty doesn't change, then you only need to have CustomObject implement INotifyPropertyChanged. There is no sense of changes propagating up the chain.
If you have a binding path:
{Binding Path=A.B.C.D}
Then if any of those properties change and you want the binding to update, then the relevant level must implement INotifyPropertyChanged. If a property is immutable (doesn't change) then there's no need to support notification of changes. You can think that the binding is listening for changes on each object returned through the evaluation of the binding path.
I'll try to answer your conceptual question. But code is nice...
I'll first just point to C#:: When to use events or a collection of objects derived from an event handling Interface?, which I think is quite helpful.
ObservableCollection takes care of raising events when items are added or removed. There is no need for INotifyPropertyChanged, that is automatically there. If you bind to an ObservableCollection in your XAML, then your XAML will register for those events, and you don't need to do anything yourself. However, nothing else is listening to the events, unless you register. You can do that like this:
myObservablecollection.CollectionChanged += myHandler;
But I don't think that is what you want. If you want to now when something is added to, or removed from MainClass.MyList, then making it an ObservableCollection will do that for you. But you want to know when some particular item in your list is modified, and ObservableCollection does not help with that.
Let's suppose you want a Configuration to do something when its CustomObject changes. Perhaps it sets Property (not a good name?) to MyObject.ToString(). Then you make CustomObject implement INotifyPropertyChanged, like this:
Class CustomObject : INotifyPropertyChanged
{
private string _innerProperty;
public string InnerProperty
{get { return _innerProperty; }
{set
{
_innerProperty = value;
OnPropertyChanged("InnerProperty");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
{
PropertyChanged(this, e);
}
}
}
Then in Configuration:
Class Configuration
{
...
public Configuration(...)
{
... // set up stuff
MyObject.PropertyChanged += myObjectChanged_DoSomethingAboutIt;
}
private void myObjectChanged_DoSomethingAboutIt()
{
DoSomething();
// for example:
Property = MyObject.ToString();
}
}
I hope this helps a bit.
More here: http://www.codeproject.com/Articles/41817/Implementing-INotifyPropertyChanged
Why is ReadOnlyObservableCollection.CollectionChanged protected and not public (as the corresponding ObservableCollection.CollectionChanged is)?
What is the use of a collection implementing INotifyCollectionChanged if I can't access the CollectionChanged event?
Here's the solution: CollectionChanged events on ReadOnlyObservableCollection
You have to cast the collection to INotifyCollectionChanged.
I've found a way for you of how to do this:
ObservableCollection<string> obsCollection = new ObservableCollection<string>();
INotifyCollectionChanged collection = new ReadOnlyObservableCollection<string>(obsCollection);
collection.CollectionChanged += new NotifyCollectionChangedEventHandler(collection_CollectionChanged);
You just need to refer to your collection explicitly by INotifyCollectionChanged interface.
I know this post is old, however, people should take their time to understand the patterns used in .NET before commenting. A read only collection is a wrapper on an existing collection that prevents consumers from modifying it directly, look at ReadOnlyCollection and you will see that it is a wrapper on a IList<T> which may or may not be mutable. Immutable collections are a different matter and are covered by the new immutable collections library
In other words, read only is not the same as immutable!!!!
That aside, ReadOnlyObservableCollection should implicitly implement INotifyCollectionChanged.
There are definitely good reasons for wanting to subscribe to collection changed notifications on a ReadOnlyObservableCollection. So, as an alternative to merely casting your collection as INotifyCollectionChanged, if you happen to be subclassing ReadOnlyObservableCollection, then the following provides a more syntactically convenient way to access the a CollectionChanged event:
public class ReadOnlyObservableCollectionWithCollectionChangeNotifications<T> : ReadOnlyObservableCollection<T>
{
public ReadOnlyObservableCollectionWithCollectionChangeNotifications(ObservableCollection<T> list)
: base(list)
{
}
event System.Collections.Specialized.NotifyCollectionChangedEventHandler CollectionChanged2
{
add { CollectionChanged += value; }
remove { CollectionChanged -= value; }
}
}
This has worked well for me before.
You might vote for the bug entry on Microsoft Connect that describes this issue: https://connect.microsoft.com/VisualStudio/feedback/details/641395/readonlyobservablecollection-t-collectionchanged-event-should-be-public
Update:
The Connect portal has been shutdown by Microsoft. So the link above does not work anymore.
My Win Application Framework (WAF) library provides a solution: ReadOnlyObservableList class:
public class ReadOnlyObservableList<T>
: ReadOnlyObservableCollection<T>, IReadOnlyObservableList<T>
{
public ReadOnlyObservableList(ObservableCollection<T> list)
: base(list)
{
}
public new event NotifyCollectionChangedEventHandler CollectionChanged
{
add { base.CollectionChanged += value; }
remove { base.CollectionChanged -= value; }
}
public new event PropertyChangedEventHandler PropertyChanged
{
add { base.PropertyChanged += value; }
remove { base.PropertyChanged -= value; }
}
}
As answered already, you have two options: you can either cast the ReadOnlyObservableCollection<T> to the interface INotifyCollectionChanged to access the explicitly implemented CollectionChanged event, or you can create your own wrapper class that does that once in the constructor and just hooks up the events of the wrapped ReadOnlyObservableCollection<T>.
Some additional insights into why this issue has not been fixed yet:
As you can see from the source code, ReadOnlyObservableCollection<T> is a public, non-sealed (i. e. inheritable) class, where the events are marked protected virtual.
That is, there might be compiled programs with classes that are derived from ReadOnlyObservableCollection<T>, with overridden event definitions but protected visibility. Those programs would contain invalid code once the event's visiblity is changed to public in the base class, because it is not allowed to restrict the visibility of an event in derived classes.
So unfortunately, making protected virtual events public later on is a binary-breaking change, and hence it will not be done without very good reasoning, which I am afraid "I have to cast the object once to attach handlers" simply isn't.
Source: GitHub comment by Nick Guerrera, August 19th, 2015
This was top hit on google so I figured I'd add my solution in case other people look this up.
Using the information above (about needing to cast to INotifyCollectionChanged), I made two extension methods to register and unregister.
My Solution - Extension Methods
public static void RegisterCollectionChanged(this INotifyCollectionChanged collection, NotifyCollectionChangedEventHandler handler)
{
collection.CollectionChanged += handler;
}
public static void UnregisterCollectionChanged(this INotifyCollectionChanged collection, NotifyCollectionChangedEventHandler handler)
{
collection.CollectionChanged -= handler;
}
Example
IThing.cs
public interface IThing
{
string Name { get; }
ReadOnlyObservableCollection<int> Values { get; }
}
Using the Extension Methods
public void AddThing(IThing thing)
{
//...
thing.Values.RegisterCollectionChanged(this.HandleThingCollectionChanged);
}
public void RemoveThing(IThing thing)
{
//...
thing.Values.UnregisterCollectionChanged(this.HandleThingCollectionChanged);
}
OP's Solution
public void AddThing(IThing thing)
{
//...
INotifyCollectionChanged thingCollection = thing.Values;
thingCollection.CollectionChanged += this.HandleThingCollectionChanged;
}
public void RemoveThing(IThing thing)
{
//...
INotifyCollectionChanged thingCollection = thing.Values;
thingCollection.CollectionChanged -= this.HandleThingCollectionChanged;
}
Alternative 2
public void AddThing(IThing thing)
{
//...
(thing.Values as INotifyCollectionChanged).CollectionChanged += this.HandleThingCollectionChanged;
}
public void RemoveThing(IThing thing)
{
//...
(thing.Values as INotifyCollectionChanged).CollectionChanged -= this.HandleThingCollectionChanged;
}
Solution
ReadOnlyObservableCollection.CollectionChanged is not exposed (for valid reasons outlined in other answers), so let's make our own wrapper class that exposes it:
/// <summary>A wrapped <see cref="ReadOnlyObservableCollection{T}"/> that exposes the internal <see cref="CollectionChanged"/>"/>.</summary>
public class ObservableReadOnlyCollection<T> : ReadOnlyObservableCollection<T>
{
public new NotifyCollectionChangedEventHandler CollectionChanged;
public ObservableReadOnlyCollection(ObservableCollection<T> list) : base(list) { /* nada */ }
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs args) =>
CollectionChanged?.Invoke(this, args);
}
Explanation
People have asked why you would want to observe changes to a read-only collection, so I'll explain one of many valid situations; when the read-only collection wraps a private internal collection that can change.
Here's one such scenario:
Suppose you have a service that allows adding and removing items to an internal collection from outside the service. Now suppose you want to expose the values of the collection but you don't want consumers to manipulate the collection directly; so you wrap the internal collection in a ReadOnlyObservableCollection.
Note that in order to wrap the internal collection with ReadOnlyObservableCollection the internal collection is forced to derive from ObservableCollection by the constructor of ReadOnlyObservableCollection.
Now suppose you want to notify consumers of the service when the internal collection changes (and hence when the exposed ReadOnlyObservableCollection changes). Rather than rolling your own implementation you just want to expose the CollectionChanged of the ReadOnlyObservableCollection. Rather than forcing the consumer to make an assumption about the implementation of the ReadOnlyObservableCollection, you simply swap the ReadOnlyObservableCollection with this custom ObservableReadOnlyCollection, and you're done.
The ObservableReadOnlyCollection hides ReadOnlyObservableCollection.CollectionChanged with it's own, and simply passes on all the collection changed events to any attached event handler.
class Foo(){
public List<string> SomeCollection;
}
I need to implement an event which can fires when something added or removed from the Collection. How to do this?
List<T> has no notification support. You could look at BindingList<T>, which has events - or Collection<T>, which can be inherited with override methods.
If you want to expose the event at the Foo level, perhaps something like below - but it may be easier to leave it on the list:
class Foo{
public event EventHandler ListChanged;
private readonly BindingList<string> list;
public Foo() {
list = new BindingList<string>();
list.ListChanged += list_ListChanged;
}
void list_ListChanged(object sender, ListChangedEventArgs e) {
EventHandler handler = ListChanged;
if (handler != null) handler(this, EventArgs.Empty);
}
public IList<string> SomeCollection {get {return list;}}
}
Take a look at the BindingList and ObservableCollection classes (in the System.ComponentModel and System.Collections.ObjectModel namespaces respectively) - either one should do the job well for you.
Note that the two classes generally provide the same functionality, but they do differ slightly. BindingList is typically more suitable for data-binding/UI purposes (hence it's name), since it allows the option to cancel updates and such. However, ObservableCollection is possibly more appropiate in your case, since you're just interested in being notified of changes (it would seem), and the class was designed purely from that perspective. The fact that they exist in very different namespaces sort of hints at this. If you want the precise details on the similarities and differences, I recommend you inspect the linked MSDN docs.
You might take a look at this tutorial on making your own custom events.
You can do this by using an ObservableCollection instead of a List.
basic one...
here is a good link
public class Foo
{
private List<string> _SomeCollection;
public event EventHandler Added;
public void Add(string item)
{
SomCollection.Add(item);
OnAdd();
}
private void OnAdd()
{
if (Added != null)
{
Added.Invoke(this, EventArgs.Empty);
}
}
}