I have a class Animal. Within the class Animal I have a list of another class called Dogs.
class Animal
{
List<Dog> Dogs;
int CountNeutedDogs;
class Dog
{
// some properties
boolean neuted;
}
}
It's possible that the list can contain about 500 dogs at any one time. I want to have an event so that if the value of neuted property in a dog changes the CountNeutedDogs is informed and updated. How do I do this?
Edit
I should explain the list Dogs is bound to a datagrid. The user can change the neuted property from false to true and vice versa. I have a get & set for the property. So the neuted value can change and I need to update the CountNeutedDogs value which is why I was thinking of using an event but not sure how to do it.
If you make CountNeutedDogs a property like so, it will always be correct without events updating:
int CountNeutedDogs
{
get
{
return this.Dogs.Where(d => d.neuted).Count();
}
}
This is a follow-up on the Comments:
I made an example, (not tested!!) how you can solve this by implementing the ObservableCollection and INotifyPropertyChanged
public class Dog : INotifyPropertyChanged
{
private bool _isNeutered;
public bool IsNeutered
{
get { return _isNeutered; }
set
{
if (_isNeutered != value)
{
_isNeutered = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("IsNeutered"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class Animals : INotifyPropertyChanged
{
private ObservableCollection<Dog> _dogs = new ObservableCollection<Dog>();
public Animals()
{
_dogs.CollectionChanged += Dogs_CollectionChanged;
}
// NOTE, I haven't checked this!! But I think it should be something like this:
private void Dogs_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (INotifyPropertyChanged item in e.NewItems.OfType<INotifyPropertyChanged>())
item.PropertyChanged += Item_PropertyChanged;
break;
case NotifyCollectionChangedAction.Reset:
case NotifyCollectionChangedAction.Remove:
foreach (INotifyPropertyChanged item in e.OldItems.OfType<INotifyPropertyChanged>())
item.PropertyChanged -= Item_PropertyChanged;
break;
}
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("NeuteredDogsCount"));
}
private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("NeuteredDogsCount"));
}
public IEnumerable<Dog> Dogs
{
get { return _dogs; }
}
public int NeuteredDogsCount
{
get
{
return Dogs.Where(dog => dog.IsNeutered).Count();
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
So when the collection changes, the notify of the NeuteredDogsCount property is sent. This way the bounded controls will re-evaluate the NeuteredDogsCount property.
Instead of 'normal' properties, the IsNeutered can be changed to a DependencyProperty.
Related
I need to bind to a bool property, that is only true, when one of the properties in the collection is true.
This is the binding:
<tk:BusyIndicator IsBusy="{Binding Tabs, Converter={StaticResource BusyTabsToStateConverter}}">
And the viewmodel:
public class MainWindowViewModel : INotifyPropertyChanged
{
private ObservableCollection<Tab> _tabs;
public ObservableCollection<Tab> Tabs
{
get
{ return _tabs; }
set
{
if (value != _tabs)
{
_tabs = value;
NotifyPropertyChanged();
}
}
}
The Tab class also has property change notification:
public class Tab : INotifyPropertyChanged
{
public bool IsBusy { get{...} set{...NotifyPropertyChanged();} }
This is the converter:
public class BusyTabsToStateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var tabs = value as ObservableCollection<Tab>;
return tabs.Any(tab => tab.IsBusy);
}
}
The problem is, when Tab.IsBusy changes the binding source is not notified, because it is bound to the observable collection and not to the IsBusy property.
Is there a way to make the notification trigger correctly when the IsBusy property on any of the items in the collection changes?
Instead of a Binding Converter, you could have a AnyTabBusy property in MainWindowViewModel, for which a change notification is fired by a PropertyChanged event handler, which is attached or detached to individual elements from the Tabs collection when they are added to or removed from the collection.
In the example below, the Tabs property is readonly. If it has to be writeable, you would have to attach and detach the TabsCollectionChanged handler in the Tabs setter.
public class MainWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<Tab> Tabs { get; } = new ObservableCollection<Tab>();
public bool AnyTabBusy
{
get { return Tabs.Any(t => t.IsBusy); }
}
public MainWindowViewModel()
{
Tabs.CollectionChanged += TabsCollectionChanged;
}
private void TabsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (Tab tab in e.NewItems)
{
tab.PropertyChanged += TabPropertyChanged;
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (Tab tab in e.OldItems)
{
tab.PropertyChanged -= TabPropertyChanged;
}
break;
default:
break;
}
}
private void TabPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Tab.IsBusy))
{
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(nameof(AnyTabBusy)));
}
}
}
If you want to make this code reusable, you could put it into a derived collection class like shown below, where you could attach a handler for an ItemPropertyChanged event.
public class ObservableItemCollection<T>
: ObservableCollection<T> where T : INotifyPropertyChanged
{
public event PropertyChangedEventHandler ItemPropertyChanged;
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
base.OnCollectionChanged(e);
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (INotifyPropertyChanged item in e.NewItems)
{
item.PropertyChanged += OnItemPropertyChanged;
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (INotifyPropertyChanged item in e.OldItems)
{
item.PropertyChanged -= OnItemPropertyChanged;
}
break;
default:
break;
}
}
private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
ItemPropertyChanged?.Invoke(this, e);
}
}
The view model could now be reduced to this:
public class MainWindowViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ObservableItemCollection<Tab> Tabs { get; }
= new ObservableItemCollection<Tab>();
public bool AnyTabBusy
{
get { return Tabs.Any(t => t.IsBusy); }
}
public MainWindowViewModel()
{
Tabs.ItemPropertyChanged += TabPropertyChanged;
}
private void TabPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Tab.IsBusy))
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(AnyTabBusy)));
}
}
}
I've taken #Clemens' answer, and converted in to an extension method that could make it easier to use on multiple collections. It will take an PropertyChangedEventHandler and automatically add and remove it from the items in the collection as they are added and removed. If you up-vote this, please up-vote#Clemens' answer also, since it is based on his work.
Be careful not use use an anonymous method as your PropertyChanged handler (this goes for all event handlers in general, not just this solution) without taking special precautions, as they can be difficult to remove.
(Note: this requires C# 7, as it uses a local function to make dealing with the CollectionChanged handler's delegate easier.)
public static class ObservableCollectionExtensions
{
public static Hook<TList> RegisterPropertyChangeHook<TList>(this ObservableCollection<TList> collection, PropertyChangedEventHandler handler) where TList : INotifyPropertyChanged
{
void Collection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (TList item in e.NewItems)
{
item.PropertyChanged += handler;
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (TList item in e.OldItems)
{
item.PropertyChanged -= handler;
}
break;
default:
break;
}
}
return new Hook<TList>(collection, Collection_CollectionChanged);
}
public class Hook<TList> where TList : INotifyPropertyChanged
{
internal Hook(ObservableCollection<TList> collection, NotifyCollectionChangedEventHandler handler)
{
_handler = handler;
_collection = collection;
collection.CollectionChanged += handler;
}
private NotifyCollectionChangedEventHandler _handler;
private ObservableCollection<TList> _collection;
public void Unregister()
{
_collection.CollectionChanged -= _handler;
}
}
}
You can use it like this:
void Main()
{
var list = new ObservableCollection<Animal>();
list.RegisterPropertyChangeHook(OnPropertyChange);
var animal = new Animal(); // Has a "Name" property that raises PropertyChanged
list.Add(animal);
animal.Name="Charlie"; // OnPropertyChange called
list.Remove(animal);
animal.Name="Sam"; // OnPropertyChange not called
}
private void OnPropertyChange(object sender, PropertyChangedEventArgs e)
{
Console.WriteLine($"property changed: {e.PropertyName}");
}
If you want to be able to unregister the hook, do this:
var hook = list.RegisterPropertyChangeHook(OnPropertyChange);
hook.Unregister();
Unregistering ended up being trickier than I expected, due to extension method classes not supporting generics. It uses the "memento" pattern to return an object that you can use to unregister later.
To propagate notification from Model to Collection of Model, You need to have a Notifiable property in Collection itself.
Maybe you can extend the ObservableCollection and have a Property in that which can notify the UI
There's no way to get this for free unfortunately. I would create an IsBusy property on MainWindowViewModel. When Tabs is set, add a listener for collection changes and have that update the IsBusy property.
I have a Windows 8.1 application with a parent and child viewmodel in the following relationship
ParentViewModel
class ParentViewModel {
private double _parentAmount;
public double parentAmount
{
get { return _parentAmount; }
set
{
if (value != _parentAmount)
{
_parentAmount = value;
NotifyPropertyChanged("parentAmount");
}
}
}
private ObservableCollection<ChildViewModel> _children;
public ObservableCollection<ChildViewModel> children
{
get { return _children; }
set
{
if (value != _children)
{
_children = value;
NotifyPropertyChanged("children");
}
}
}
}
ChildViewModel
class ChildViewModel {
private double _ChildAmount;
public double ChildAmount
{
get { return _ChildAmount; }
set
{
if (value != _ChildAmount)
{
_ChildAmount = value;
NotifyPropertyChanged("ChildAmount");
}
}
}
}
In the XAML there is TextBlock that is bound to the "ParentAmount" and then there is a ListView bound to the Observable collection "Children". ListView's Itemtemplate is a datatemplate with a TextBox with a two way bind to the "ChildAmount". The user can modify the value in the child TextBox
Now my requriement is to update the ParentAmount with the sum of all its child amount on the fly when the user modifies one of the child amounts. How do I achieve this?
For illustration purpose I have simplified the code example pasted above, the ChildViewModel has more functionality than what can be seen hence I can't replace that ObservableCollection of ChildViewModel with a List of double for instance.
I would be very glad if someone can point me in the right direction. Thanks in Advance.
With a very small addition, this will do the trick.
The specific changes are adding a property change handler for each child object in the ObservableCollection.
Note that this is a crude example to set you on the right track - I haven't unhooked the event handlers, and I recalculate the parent amount on any change from the child (i.e. I don't check that it was the ChildAmount that changed, this means you end up with more action than is necessary). I also haven't put in any code to handle changes to the contents of the ObservableCollection so if new items are added to it they won't have a property change event handler attached - this is simple for you to do yourself.
Note my use of a BaseViewModel - this is just good practice, it saves you from reimplementing the INotifyPropertyChanged interface on every class that needs it.
class ParentViewModel : BaseViewModel
{
private double _parentAmount;
public double parentAmount
{
get { return _parentAmount; }
set
{
if (value != _parentAmount)
{
_parentAmount = value;
NotifyPropertyChanged("parentAmount");
}
}
}
private ObservableCollection<ChildViewModel> _children;
public ObservableCollection<ChildViewModel> children
{
get { return _children; }
set
{
if (value != _children)
{
_children = value;
foreach (var child in _children)
child.PropertyChanged += ChildOnPropertyChanged;
NotifyPropertyChanged("children");
}
}
}
private void ChildOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
{
parentAmount = children.Sum(p => p.ChildAmount);
}
}
class ChildViewModel : BaseViewModel
{
private double _ChildAmount;
public double ChildAmount
{
get { return _ChildAmount; }
set
{
if (value != _ChildAmount)
{
_ChildAmount = value;
NotifyPropertyChanged("ChildAmount");
}
}
}
}
public class BaseViewModel : INotifyPropertyChanged
{
protected void NotifyPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
A more elegant way is to use Reactive Extensions.
First you need to grab
Rx-Main
from Package Manager Console.
Then, create a static class to host your extension method implemented using Rx. Something like this -
public static class Extensions
{
public static IObservable<T> OnPropertyChanges<T>(this T source, string propertyName)
where T : INotifyPropertyChanged
{
return Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(
handler => handler.Invoke,
h => source.PropertyChanged += h,
h => source.PropertyChanged -= h)
.Where(p => p.EventArgs.PropertyName == propertyName)
.Select(_ => source);
}
}
Lastly, you call this method in your ParentViewModel's constructor (or anywhere necessary).
// whenever the ChildAmount property of any ChildViewModel has changed, do something
Observable.Merge(children.Select(c => c.OnPropertyChanges("ChildAmount")))
.Subscribe((c) =>
{
// update your parent amount here
NotifyPropertyChanged("parentAmount");
});
Lets say I have classes like this
public class R
{
protected string name;
protected List<S> listOfObjectS;
}
public class S
{
private string name, ID;
private A objectA;
}
public class A
{
private string name;
private int count;
}
If a user has two views open, one displaying instances of R and another allowing users to modify an instance of A, I need the view of R to change when the user changes any instance of A.
If the user changes a property of an instance of A, what is the best way to propagate that change (through instances of S) so that all instances of R display the new state of A?
EDIT: Overhauling this answer to be more specific to the question since the tags show you already knew about INotifyPropertyChanged.
You need to implement INotifyPropertyChanged in class A and in class S. Make it so objectA can only be set through a property that will raise the PropertyChanged event on S whenever a property is changed in A. Example:
public class A : INotifyPropertyChanged
{
private string name;
public string Name
{
get { return name; }
set { name = value; OnPropertyChanged("Name"); }
}
private int count;
public int Count
{
get { return count; }
set { count = value; OnPropertyChanged("Count"); }
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
... and class S...
public class S : INotifyPropertyChanged
{
private string name, ID;
private A objectA;
public A ObjectA
{
get { return objectA; }
set
{
var old = objectA;
objectA = value;
// Remove the event subscription from the old instance.
if (old != null) old.PropertyChanged -= objectA_PropertyChanged;
// Add the event subscription to the new instance.
if (objectA != null) objectA.PropertyChanged += objectA_PropertyChanged;
OnPropertyChanged("ObjectA");
}
}
void objectA_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
// Propagate the change to any listeners. Prefix with ObjectA so listeners can tell the difference.
OnPropertyChanged("ObjectA." + e.PropertyName);
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
For class R, use ObservableCollection<S> instead of List<S>, and subscribe to its CollectionChanged event, and monitor when objects are added or removed to listOfObjectS. When they are added, subscribe to S's PropertyChanged events. Then updated R's view. Example:
public class R
{
protected string name;
protected System.Collections.ObjectModel.ObservableCollection<S> ListOfObjectS { get; private set; }
public R()
{
// Use ObservableCollection instead.
ListOfObjectS = new ObservableCollection<S>();
// Subscribe to all changes to the collection.
ListOfObjectS.CollectionChanged += listOfObjectS_CollectionChanged;
}
void listOfObjectS_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Remove)
{
// When items are removed, unsubscribe from property change notifications.
var oldItems = (e.OldItems ?? new INotifyPropertyChanged[0]).OfType<INotifyPropertyChanged>();
foreach (var item in oldItems)
item.PropertyChanged -= item_PropertyChanged;
}
// When item(s) are added, subscribe to property notifications.
if (e.Action == NotifyCollectionChangedAction.Add)
{
var newItems = (e.NewItems ?? new INotifyPropertyChanged[0]).OfType<INotifyPropertyChanged>();
foreach (var item in newItems)
item.PropertyChanged += item_PropertyChanged;
}
// NOTE: I'm not handling NotifyCollectionChangedAction.Reset.
// You'll want to look into when this event is raised and handle it
// in a special fashion.
}
void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName.StartsWith("ObjectA."))
{
// Refresh any dependent views, forms, controls, whatever...
}
}
}
Let's say you have a form1 where you use an instance of class R to display a list of instances from class A. You than press edit and you send the instance of that same class A from the class R instance towards the new form.
This will than be a reference to the object contained in the instance of R and therefore be updated within form2. The only thing you than have to do is refresh the instance of class A in the list of form1.
To explain: when you are calling a form or method with the an object instance of a class, this will create a reference, not a clone and therefore can be updated from the second form2.
I have a list box:
<ListBox x:Name="lbxAF" temsSource="{Binding}">
that gets its data from this from this modified Observable Collection:
public ObservableCollectionEx<FileItem> folder = new ObservableCollectionEx<FileItem>();
which is created within a class that uses FileSystemWatcher to monitor a specific folder for addition, deletion and modification of files.
The ObservableCollection was modified (hence the Ex at the end) so that I can modify it from an outside thread (code is not mine, I actually did some searching through this website and found it, works like a charm):
// This is an ObservableCollection extension
public class ObservableCollectionEx<T> : ObservableCollection<T>
{
// Override the vent so this class can access it
public override event System.Collections.Specialized.NotifyCollectionChangedEventHandler CollectionChanged;
protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
using (BlockReentrancy())
{
System.Collections.Specialized.NotifyCollectionChangedEventHandler eventHanlder = CollectionChanged;
if (eventHanlder == null)
return;
Delegate[] delegates = eventHanlder.GetInvocationList();
// Go through the invocation list
foreach (System.Collections.Specialized.NotifyCollectionChangedEventHandler handler in delegates)
{
DispatcherObject dispatcherObject = handler.Target as DispatcherObject;
// If the subscriber is a DispatcherObject and different thread do this:
if (dispatcherObject != null && dispatcherObject.CheckAccess() == false)
{
// Invoke handler in the target dispatcher's thread
dispatcherObject.Dispatcher.Invoke(DispatcherPriority.DataBind, handler, this, e);
}
// Else, execute handler as is
else
{
handler(this, e);
}
}
}
}
}
The collection is made up of these:
public class FileItem
{
public string Name { get; set; }
public string Path { get; set; }
}
which allow me to store names and paths of files.
Everything works great as far as deletion and addition of files, and the List Box gets updated flawlessly with respect to those two... however, if I change the name of any of the files, it doesn't update the list box.
How would I notify list box of the changes in FileItem's properties? I assumed that ObservableCollection would handle that, but apparently it raises flag only when FileItem is added or deleted, not when its contents are changed.
Your FileItem class should implement INotifyPropertyChanged. Below is a simple working implementation of it.
public class FileItem : INotifyPropertyChanged
{
private string _Name;
public string Name
{
get { return _Name; }
set {
if (_Name != value)
{
_Name = value;
OnPropertyChanged("Name");
}
}
}
private string _Path;
public string Path
{
get { return _Path; }
set {
if (_Path != value)
{
_Path = value;
OnPropertyChanged("Path");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
That's how the ObservableCollection works - it monitors only insertion/deletion/moving of items.
To update the View when each item (or FileItem, in your case) changes, the FileItem must implement INotifyPropertyChanged and fire the appropriate event when you set each property that you want to observe.
Here's an example of how to do this: http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx
Try this simple one:
public class NotifyObservableCollection<TItem> : ObservableCollection<TItem>
where TItem : class , INotifyPropertyChanged, new()
{
#region Fields
private Action _itemPropertyChanged;
#endregion
#region Constructor
public NotifyObservableCollection(Action itemPropertyChanged)
{
_itemPropertyChanged = itemPropertyChanged;
}
#endregion
#region Methods
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
foreach (var item in e.NewItems)
{
var notifyItem = item as INotifyPropertyChanged;
if (notifyItem != null)
{
notifyItem.PropertyChanged += ItemPropertyChanged;
}
}
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach (var item in e.OldItems)
{
var notifyItem = item as INotifyPropertyChanged;
if (notifyItem != null)
{
notifyItem.PropertyChanged -= ItemPropertyChanged;
}
}
}
base.OnCollectionChanged(e);
}
#endregion
#region Private Methods
private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(_itemPropertyChanged!=null)
{
_itemPropertyChanged();
}
}
#endregion
}
I have a converter that accepts an ObservableCollection as a parameter, and I'd like to re-evaluate it whenever a specific property on any item in the collection changes
For example: lets say I have bound a label to a collection of Person objects with a converter. The job of the converter is to count the number of Persons in the list that are female, and return "valid" for 1 female or "accepted" for 2. I'd like the converter to get called again anytime the Gender property on any Person object gets changed.
How can I accomplish this?
That's a classic problem you end up having if you play around WPF long enough.
I've tried various solutions, but the one that works best is to use a BindingList like so:
public class WorldViewModel : INotifyPropertyChanged
{
private BindingList<Person> m_People;
public BindingList<Person> People
{
get { return m_People; }
set
{
if(value != m_People)
{
m_People = value;
if(m_People != null)
{
m_People.ListChanged += delegate(object sender, ListChangedEventArgs args)
{
OnPeopleListChanged(this);
};
}
RaisePropertyChanged("People");
}
}
}
private static void OnPeopleListChanged(WorldViewModel vm)
{
vm.RaisePropertyChanged("People");
}
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged(String prop)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(prop));
}
}
}
Then just bind to the People collection like you would do with an ObservableCollection, except bindings will be re-evaluated when any property in its items change.
Also, please note that OnPeopleListChanged is static, so no memory leaks.
And Person should implement INotifyPropertyChanged.
A CollectionChanged event is only thrown when an item is added or removed from the collection (not when an item in the collection is changed). So the converter is not called when an item is changed.
One option:
In the Gender Property Set include logic to evaluate the collection and set a string Property that you bind the label to.
Wrote generic version of the answer from Baboon
public class ObservalbeList<T>: INotifyPropertyChanged
{
private BindingList<T> ts = new BindingList<T>();
public event PropertyChangedEventHandler PropertyChanged;
// This method is called by the Set accessor of each property.
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
private void NotifyPropertyChanged( String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public BindingList<T> Ts
{
get { return ts; }
set
{
if (value != ts)
{
Ts = value;
if (Ts != null)
{
ts.ListChanged += delegate(object sender, ListChangedEventArgs args)
{
OnListChanged(this);
};
}
NotifyPropertyChanged("Ts");
}
}
}
private static void OnListChanged(ObservalbeList<T> vm)
{
vm.NotifyPropertyChanged("Ts");
}
public ObservalbeList()
{
ts.ListChanged += delegate(object sender, ListChangedEventArgs args)
{
OnListChanged(this);
};
}
}