I want to show the data in a listview, the data stored in a Queue and data type is user defined type(including two string and one int type).
How can i show the data inside after every process of enqueue and dequeue, what could be the command lines and syntax?
Queue<Customer> aCustomerQueue =new Queue<Customer>();// its the queue
class Customer// its the user defined type variable class
{
public string name;
public string complain;
public int serialNo;
}
Stored data will be user input.
You can try this code.
int count;
Queue<Customer> customers = new Queue<Customer>();
ListViewItem item;
private void enqueueButton_Click(object sender, EventArgs e)
{
Customer customer = new Customer();
count++;
customer.serialNo += count;
customer.name = nameTextBox.Text;
customer.complain = complainTextBox.Text;
customers.Enqueue(customer);
foreach (Customer custm in customers)
{
item = new ListViewItem(custm.serialNo.ToString());
item.SubItems.Add(custm.name);
item.SubItems.Add(custm.complain);
}
customerQueueListView.Items.Add(item);
}
for dequeue
private void dequeueButton_Click(object sender, EventArgs e)
{
if (customers.Count != 0)
{
customers.Dequeue();
customerQueueListView.Items[0].Remove();
}
}
Take a look at binding-to-queuestring-ui-never-updates.
The proposed implementation is a good way to go (code taken from the linked question):
public class ObservableQueue<T> : INotifyCollectionChanged, IEnumerable<T>
{
public event NotifyCollectionChangedEventHandler CollectionChanged;
private readonly Queue<T> queue = new Queue<T>();
public void Enqueue(T item)
{
queue.Enqueue(item);
if (CollectionChanged != null)
CollectionChanged(this,
new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Add, item));
}
public T Dequeue()
{
var item = queue.Dequeue();
if (CollectionChanged != null)
CollectionChanged(this,
new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Remove, item));
return item;
}
public IEnumerator<T> GetEnumerator()
{
return queue.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Related
I'd like an ISet<T> with two additional events ItemAdded and ItemRemoved.
One option I considered was deriving MyHashSet<T> from HashSet<T> but since Add and Remove are not virtual, it would require the use of new. Maybe this is a valid use of the keyword?
Another option I thought would be to implement ISet<T> and delegate everything to a private instance of HashSet<T>. This feels like a bulky solution.
Is there a pattern or framework class that gets me the same result but doesn't require less than elegant/ideal coding?
Based on the comments I received (thanks) here's what I've got:
public class NotifyingHashSet<T>
{
private HashSet<T> hashSet = new HashSet<T>();
public bool Add(T item)
{
bool added = hashSet.Add(item);
if(added && ItemAdded != null)
{
ItemAdded(this, new NotifyingHashSetEvent<T>(item));
}
return added;
}
public bool Remove(T item)
{
bool removed = hashSet.Remove(item);
if(removed && ItemRemoved != null)
{
ItemRemoved(this, new NotifyingHashSetEvent<T>(item));
}
return removed;
}
public event EventHandler<NotifyingHashSetEvent<T>> ItemAdded;
public event EventHandler<NotifyingHashSetEvent<T>> ItemRemoved;
}
public class NotifyingHashSetEvent<T> : EventArgs
{
public NotifyingHashSetEvent(T item)
{
Item = item;
}
public T Item { get; set; }
}
I would recommend inheriting rather than composing in this case.
This will ensure that you get all that HashSet offers like:
Other collection methods such as Contains and other Set operations such as IsSubsetOf
Collection initializers
You could assign it to base type, HashSet<int> foo = new NotifyingHashSet<int>()
My implementation looks like this:
public class NotifyingHashSet<T> : HashSet<T>
{
public new void Add(T item)
{
OnItemAdded(new NotifyHashSetChanged<T>(item));
base.Add(item);
}
public new void Remove(T item)
{
OnItemRemoved(new NotifyHashSetChanged<T>(item));
base.Remove(item);
}
public event EventHandler<NotifyHashSetChanged<T>> ItemAdded;
public event EventHandler<NotifyHashSetChanged<T>> ItemRemoved;
protected virtual void OnItemRemoved(NotifyHashSetChanged<T> e)
{
if (ItemRemoved != null) ItemRemoved(this, e);
}
protected virtual void OnItemAdded(NotifyHashSetChanged<T> e)
{
if (ItemAdded != null) ItemAdded(this, e);
}
}
public class NotifyHashSetChanged<T> : EventArgs
{
private readonly T _item;
public NotifyHashSetChanged(T item)
{
_item = item;
}
public T ChangedItem
{
get { return _item; }
}
}
Some tests to check stuff:
[TestClass]
public class NotifyingHashSetTests
{
[TestMethod]
public void ShouldAddToNotifyingHashSet()
{
var notifyingHashSet = new NotifyingHashSet<int>();
notifyingHashSet.ItemAdded += (sender, changed) => Assert.AreEqual(changed.ChangedItem, 1);
notifyingHashSet.Add(1);
}
[TestMethod]
public void ShouldRemoveFromNotifyingHashSet()
{
//can use collection initializer
var notifyingHashSet = new NotifyingHashSet<int> { 1 };
notifyingHashSet.ItemRemoved += (sender, changed) => Assert.AreEqual(changed.ChangedItem, 1);
notifyingHashSet.Remove(1);
}
[TestMethod]
public void ShouldContainValueInNotifyingHashSet()
{
//can use collection initializer
var notifyingHashSet = new NotifyingHashSet<int> { 1 };
Assert.IsTrue(notifyingHashSet.Contains(1));
}
[TestMethod]
public void ShouldAssignToHashSet()
{
HashSet<int> notifyingHashSet = new NotifyingHashSet<int> { 1 };
Assert.IsTrue(notifyingHashSet.IsSubsetOf(new List<int>{ 1,2 }));
}
}
Your own answer demonstrates how you can wrap a HashSet<T> and Srikanth's answer demonstrates how you can derive from HashSet<T>. However, when you derive from HashSet<T> you have to make sure the new class also correctly implements the Add and Remove methods of the ICollection<T> interface. So I have modified Srikanth's answer to properly create an ISet<T> implementation with notifications that derives from HashSet<T> by using explicit interface implementation of the relevant methods of ICollection<T>:
public class NotifyingHashSet<T> : HashSet<T>, ICollection<T> {
new public void Add(T item) {
((ICollection<T>) this).Add(item);
}
new public Boolean Remove(T item) {
return ((ICollection<T>) this).Remove(item);
}
void ICollection<T>.Add(T item) {
var added = base.Add(item);
if (added)
OnItemAdded(new NotifyHashSetEventArgs<T>(item));
}
Boolean ICollection<T>.Remove(T item) {
var removed = base.Remove(item);
if (removed)
OnItemRemoved(new NotifyHashSetEventArgs<T>(item));
return removed;
}
public event EventHandler<NotifyHashSetEventArgs<T>> ItemAdded;
public event EventHandler<NotifyHashSetEventArgs<T>> ItemRemoved;
protected virtual void OnItemRemoved(NotifyHashSetEventArgs<T> e) {
var handler = ItemRemoved;
if (handler != null)
ItemRemoved(this, e);
}
protected virtual void OnItemAdded(NotifyHashSetEventArgs<T> e) {
var handler = ItemAdded;
if (handler != null)
ItemAdded(this, e);
}
}
public class NotifyHashSetEventArgs<T> : EventArgs {
public NotifyHashSetEventArgs(T item) {
Item = item;
}
public T Item { get; private set; }
}
This class also behaves the same way as your class by only firing events when an element actually is added or removed from the set. E.g., adding the same element twice in succession will only fire one event.
I have a list like this:
List<Controls> list = new List<Controls>
How to handle adding new position to this list?
When I do:
myObject.myList.Add(new Control());
I would like to do something like this in my object:
myList.AddingEvent += HandleAddingEvent
And then in my HandleAddingEvent delegate handling adding position to this list. How should I handle adding new position event? How can I make this event available?
I believe What you're looking for is already part of the API in the ObservableCollection(T) class. Example:
ObservableCollection<int> myList = new ObservableCollection<int>();
myList.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(
delegate(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
MessageBox.Show("Added value");
}
}
);
myList.Add(1);
You could inherit from List and add your own handler, something like
using System;
using System.Collections.Generic;
namespace test
{
class Program
{
class MyList<T> : List<T>
{
public event EventHandler OnAdd;
public new void Add(T item) // "new" to avoid compiler-warnings, because we're hiding a method from base-class
{
if (null != OnAdd)
{
OnAdd(this, null);
}
base.Add(item);
}
}
static void Main(string[] args)
{
MyList<int> l = new MyList<int>();
l.OnAdd += new EventHandler(l_OnAdd);
l.Add(1);
}
static void l_OnAdd(object sender, EventArgs e)
{
Console.WriteLine("Element added...");
}
}
}
Warning
Be aware that you have to re-implement all methods which add objects to your list. AddRange() will not fire this event, in this implementation.
We did not overload the method. We hid the original one. If you Add() an object while this class is boxed in List<T>, the event will not be fired!
MyList<int> l = new MyList<int>();
l.OnAdd += new EventHandler(l_OnAdd);
l.Add(1); // Will work
List<int> baseList = l;
baseList.Add(2); // Will NOT work!!!
What you need is a class that has events for any type of modification that occurs in the collection. The best class for this is BindingList<T>. It has events for every type of mutation which you can then use to modify your event list.
http://msdn.microsoft.com/en-us/library/ms132679.aspx
You can't do this with List<T>. However, you can do it with ObservableCollection<T>. See ObservableCollection<T> Class.
To be clear: If you only need to observe the standard-functionalities you should use ObservableCollection(T) or other existing classes. Never rebuild something you already got.
..But.. If you need special events and have to go deeper, you should not derive from List! If you derive from List you can not overloead Add() in order to see every add.
Example:
public class MyList<T> : List<T>
{
public void Add(T item) // Will show us compiler-warning, because we hide the base-mothod which still is accessible!
{
throw new Exception();
}
}
public static void Main(string[] args)
{
MyList<int> myList = new MyList<int>(); // Create a List which throws exception when calling "Add()"
List<int> list = myList; // implicit Cast to Base-class, but still the same object
list.Add(1); // Will NOT throw the Exception!
myList.Add(1); // Will throw the Exception!
}
It's not allowed to override Add(), because you could mees up the functionalities of the base class (Liskov substitution principle).
But as always we need to make it work. But if you want to build your own list, you should to it by implementing the an interface: IList<T>.
Example which implements a before- and after-add event:
public class MyList<T> : IList<T>
{
private List<T> _list = new List<T>();
public event EventHandler BeforeAdd;
public event EventHandler AfterAdd;
public void Add(T item)
{
// Here we can do what ever we want, buffering multiple events etc..
BeforeAdd?.Invoke(this, null);
_list.Add(item);
AfterAdd?.Invoke(this, null);
}
#region Forwarding to List<T>
public T this[int index] { get => _list[index]; set => _list[index] = value; }
public int Count => _list.Count;
public bool IsReadOnly => false;
public void Clear() => _list.Clear();
public bool Contains(T item) => _list.Contains(item);
public void CopyTo(T[] array, int arrayIndex) => _list.CopyTo(array, arrayIndex);
public IEnumerator<T> GetEnumerator() => _list.GetEnumerator();
public int IndexOf(T item) => _list.IndexOf(item);
public void Insert(int index, T item) => _list.Insert(index, item);
public bool Remove(T item) => _list.Remove(item);
public void RemoveAt(int index) => _list.RemoveAt(index);
IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator();
#endregion
}
Now we've got all methods we want and didn't have to implement much. The main change in our code is, that our variables will be IList<T> instead of List<T>, ObservableCollection<T> or what ever.
And now the big wow: All of those implement IList<T>:
IList<int> list1 = new ObservableCollection<int>();
IList<int> list2 = new List<int>();
IList<int> list3 = new int[10];
IList<int> list4 = new MyList<int>();
Which brings us to the next point: Use Interfaces instead of classes. Your code should never depend on implementation-details!
One simple solution is to introduce an Add method for the list in your project and handle the event there. It doesn't answer the need for an event handler but can be useful for some small projects.
AddToList(item) // or
AddTo(list,item)
////////////////////////
void AddTo(list,item)
{
list.Add(item);
// event handling
}
instead of
list.Add(item);
You cannot do this with standard collections out of the box - they just don't support change notifications. You could build your own class by inheriting or aggregating a existing collection type or you could use BindingList<T> that implements IBindingList and supports change notifications via the ListChanged event.
To piggy-back off Ahmad's use of Extension Methods, you can create your own class where the list is private with a public get method and a public add method.
public class MyList
{
private List<SomeClass> PrivateSomeClassList;
public List<SomeClass> SomeClassList
{
get
{
return PrivateSomeClassList;
}
}
public void Add(SomeClass obj)
{
// do whatever you want
PrivateSomeClassList.Add(obj);
}
}
However, this class only provides access to List<> methods that you manually expose...hence may not be useful in cases where you need a lot of that functionality.
No need for adding an event just add the method.
public class mylist:List<string>
{
public void Add(string p)
{
// Do cool stuff here
base.Add(p);
}
}
//List overrider class
public class ListWithEvents<T> : List<T>
{
public delegate void AfterChangeHandler();
public AfterChangeHandler OnChangeEvent;
public Boolean HasAddedItems = false;
public Boolean HasRemovedItems = false;
public bool HasChanges
{
get => HasAddedItems || HasRemovedItems;
set
{
HasAddedItems = value;
HasRemovedItems = value;
}
}
public new void Add(T item)
{
base.Add(item);
HasAddedItems = true;
if(OnChangeEvent != null) OnChangeEvent();
OnChange();
}
public new void AddRange(IEnumerable<T> collection)
{
base.AddRange(collection);
HasAddedItems = true;
if (OnChangeEvent != null) OnChangeEvent();
OnChange();
}
public new void Insert(int index,T item)
{
base.Insert(index, item);
HasAddedItems = true;
if (OnChangeEvent != null) OnChangeEvent();
OnChange();
}
public new void InsertRange(int index, IEnumerable<T> collection)
{
base.InsertRange(index, collection);
HasAddedItems = true;
if (OnChangeEvent != null) OnChangeEvent();
OnChange();
}
public new void Remove(T item)
{
base.Remove(item);
HasRemovedItems = true;
if (OnChangeEvent != null) OnChangeEvent();
OnChange();
}
public new void RemoveAt(int index)
{
HasRemovedItems = true;
if (OnChangeEvent != null) OnChangeEvent();
OnChange();
}
public new void RemoveRange(int index,int count)
{
HasRemovedItems = true;
if (OnChangeEvent != null) OnChangeEvent();
OnChange();
}
public new void Clear()
{
base.Clear();
HasRemovedItems = true;
if (OnChangeEvent != null) OnChangeEvent();
OnChange();
}
public virtual void OnChange()
{
}
}
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) { }
}
I created a Class EventList inheriting List which fires an Event each time something is Added, Inserted or Removed:
public class EventList<T> : List<T>
{
public event ListChangedEventDelegate ListChanged;
public delegate void ListChangedEventDelegate();
public new void Add(T item)
{
base.Add(item);
if (ListChanged != null
&& ListChanged.GetInvocationList().Any())
{
ListChanged();
}
}
...
}
At the Moment I use it as a Property like this:
public EventList List
{
get { return m_List; }
set
{
m_List.ListChanged -= List_ListChanged;
m_List = value;
m_List.ListChanged += List_ListChanged;
List_ListChanged();
}
}
Now my Problem is, can I somehow handle if a new Object is referred to it or prevent that, so I do not have to do the event wiring stuff in the setter?
Of course, I can change the property to "private set" but I would like to be able to use the class as variable as well.
You seldom create a new instance of a collection class in a class. Instantiate it once and clear it instead of creating a new list. (and use the ObservableCollection since it already has the INotifyCollectionChanged interface inherited)
private readonly ObservableCollection<T> list;
public ctor() {
list = new ObservableCollection<T>();
list.CollectionChanged += listChanged;
}
public ObservableCollection<T> List { get { return list; } }
public void Clear() { list.Clear(); }
private void listChanged(object sender, NotifyCollectionChangedEventArgs args) {
// list changed
}
This way you only have to hook up events once, and can "reset it" by calling the clear method instead of checking for null or equality to the former list in the set accessor for the property.
With the changes in C#6 you can assign a get property from a constructor without the backing field (the backing field is implicit)
So the code above can be simplified to
public ctor() {
List = new ObservableCollection<T>();
List.CollectionChanged += OnListChanged;
}
public ObservableCollection<T> List { get; }
public void Clear()
{
List.Clear();
}
private void OnListChanged(object sender, NotifyCollectionChangedEventArgs args)
{
// react to list changed
}
ObservableCollection is a List with a CollectionChanged event
ObservableCollection.CollectionChanged Event
For how to wire up the event handler see answer from Patrick. +1
Not sure what you are looking for but I use this for a collection with one event that fires on add, remove, and change.
public class ObservableCollection<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(ObservableCollection<T> vm)
{
// this will fire on add, remove, and change
// if want to prevent an insert this in not the right spot for that
// the OPs use of word prevent is not clear
// -1 don't be a hater
vm.NotifyPropertyChanged("Ts");
}
public ObservableCollection()
{
ts.ListChanged += delegate(object sender, ListChangedEventArgs args)
{
OnListChanged(this);
};
}
}
If you do not want to or can not convert to an Observable Collection, try this:
public class EventList<T> : IList<T> /* NOTE: Changed your List<T> to IList<T> */
{
private List<T> list; // initialize this in your constructor.
public event ListChangedEventDelegate ListChanged;
public delegate void ListChangedEventDelegate();
private void notify()
{
if (ListChanged != null
&& ListChanged.GetInvocationList().Any())
{
ListChanged();
}
}
public new void Add(T item)
{
list.Add(item);
notify();
}
public List<T> Items {
get { return list; }
set {
list = value;
notify();
}
}
...
}
Now, for your property, you should be able to reduce your code to this:
public EventList List
{
get { return m_List.Items; }
set
{
//m_List.ListChanged -= List_ListChanged;
m_List.Items = value;
//m_List.ListChanged += List_ListChanged;
//List_ListChanged();
}
}
Why? Setting anything in the EventList.Items will call your private notify() routine.
I have a Solution for when someone calls the Generic method from IList.add(object). So that you also get notified.
using System;
using System.Collections;
using System.Collections.Generic;
namespace YourNamespace
{
public class ObjectDoesNotMatchTargetBaseTypeException : Exception
{
public ObjectDoesNotMatchTargetBaseTypeException(Type targetType, object actualObject)
: base(string.Format("Expected base type ({0}) does not match actual objects type ({1}).",
targetType, actualObject.GetType()))
{
}
}
/// <summary>
/// Allows you to react, when items were added or removed to a generic List.
/// </summary>
public abstract class NoisyList<TItemType> : List<TItemType>, IList
{
#region Public Methods
/******************************************/
int IList.Add(object item)
{
CheckTargetType(item);
Add((TItemType)item);
return Count - 1;
}
void IList.Remove(object item)
{
CheckTargetType(item);
Remove((TItemType)item);
}
public new void Add(TItemType item)
{
base.Add(item);
OnItemAdded(item);
}
public new bool Remove(TItemType item)
{
var result = base.Remove(item);
OnItemRemoved(item);
return result;
}
#endregion
# region Private Methods
/******************************************/
private static void CheckTargetType(object item)
{
var targetType = typeof(TItemType);
if (item.GetType().IsSubclassOf(targetType))
throw new ObjectDoesNotMatchTargetBaseTypeException(targetType, item);
}
#endregion
#region Abstract Methods
/******************************************/
protected abstract void OnItemAdded(TItemType addedItem);
protected abstract void OnItemRemoved(TItemType removedItem);
#endregion
}
}
If an ObservableCollection is not the solution for you, you can try that:
A) Implement a custom EventArgs that will contain the new Count attribute when an event will be fired.
public class ChangeListCountEventArgs : EventArgs
{
public int NewCount
{
get;
set;
}
public ChangeListCountEventArgs(int newCount)
{
NewCount = newCount;
}
}
B) Implement a custom List that inherits from List and redefine the Count attribute and the constructors according to your needs:
public class CustomList<T> : List<T>
{
public event EventHandler<ChangeListCountEventArgs> ListCountChanged;
public new int Count
{
get
{
ListCountChanged?.Invoke(this, new ChangeListCountEventArgs(base.Count));
return base.Count;
}
}
public CustomList()
{ }
public CustomList(List<T> list) : base(list)
{ }
public CustomList(CustomList<T> list) : base(list)
{ }
}
C) Finally subscribe to your event:
var myList = new CustomList<YourObject>();
myList.ListCountChanged += (obj, e) =>
{
// get the count thanks to e.NewCount
};
I have a list like this:
List<Controls> list = new List<Controls>
How to handle adding new position to this list?
When I do:
myObject.myList.Add(new Control());
I would like to do something like this in my object:
myList.AddingEvent += HandleAddingEvent
And then in my HandleAddingEvent delegate handling adding position to this list. How should I handle adding new position event? How can I make this event available?
I believe What you're looking for is already part of the API in the ObservableCollection(T) class. Example:
ObservableCollection<int> myList = new ObservableCollection<int>();
myList.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(
delegate(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
MessageBox.Show("Added value");
}
}
);
myList.Add(1);
You could inherit from List and add your own handler, something like
using System;
using System.Collections.Generic;
namespace test
{
class Program
{
class MyList<T> : List<T>
{
public event EventHandler OnAdd;
public new void Add(T item) // "new" to avoid compiler-warnings, because we're hiding a method from base-class
{
if (null != OnAdd)
{
OnAdd(this, null);
}
base.Add(item);
}
}
static void Main(string[] args)
{
MyList<int> l = new MyList<int>();
l.OnAdd += new EventHandler(l_OnAdd);
l.Add(1);
}
static void l_OnAdd(object sender, EventArgs e)
{
Console.WriteLine("Element added...");
}
}
}
Warning
Be aware that you have to re-implement all methods which add objects to your list. AddRange() will not fire this event, in this implementation.
We did not overload the method. We hid the original one. If you Add() an object while this class is boxed in List<T>, the event will not be fired!
MyList<int> l = new MyList<int>();
l.OnAdd += new EventHandler(l_OnAdd);
l.Add(1); // Will work
List<int> baseList = l;
baseList.Add(2); // Will NOT work!!!
What you need is a class that has events for any type of modification that occurs in the collection. The best class for this is BindingList<T>. It has events for every type of mutation which you can then use to modify your event list.
http://msdn.microsoft.com/en-us/library/ms132679.aspx
You can't do this with List<T>. However, you can do it with ObservableCollection<T>. See ObservableCollection<T> Class.
To be clear: If you only need to observe the standard-functionalities you should use ObservableCollection(T) or other existing classes. Never rebuild something you already got.
..But.. If you need special events and have to go deeper, you should not derive from List! If you derive from List you can not overloead Add() in order to see every add.
Example:
public class MyList<T> : List<T>
{
public void Add(T item) // Will show us compiler-warning, because we hide the base-mothod which still is accessible!
{
throw new Exception();
}
}
public static void Main(string[] args)
{
MyList<int> myList = new MyList<int>(); // Create a List which throws exception when calling "Add()"
List<int> list = myList; // implicit Cast to Base-class, but still the same object
list.Add(1); // Will NOT throw the Exception!
myList.Add(1); // Will throw the Exception!
}
It's not allowed to override Add(), because you could mees up the functionalities of the base class (Liskov substitution principle).
But as always we need to make it work. But if you want to build your own list, you should to it by implementing the an interface: IList<T>.
Example which implements a before- and after-add event:
public class MyList<T> : IList<T>
{
private List<T> _list = new List<T>();
public event EventHandler BeforeAdd;
public event EventHandler AfterAdd;
public void Add(T item)
{
// Here we can do what ever we want, buffering multiple events etc..
BeforeAdd?.Invoke(this, null);
_list.Add(item);
AfterAdd?.Invoke(this, null);
}
#region Forwarding to List<T>
public T this[int index] { get => _list[index]; set => _list[index] = value; }
public int Count => _list.Count;
public bool IsReadOnly => false;
public void Clear() => _list.Clear();
public bool Contains(T item) => _list.Contains(item);
public void CopyTo(T[] array, int arrayIndex) => _list.CopyTo(array, arrayIndex);
public IEnumerator<T> GetEnumerator() => _list.GetEnumerator();
public int IndexOf(T item) => _list.IndexOf(item);
public void Insert(int index, T item) => _list.Insert(index, item);
public bool Remove(T item) => _list.Remove(item);
public void RemoveAt(int index) => _list.RemoveAt(index);
IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator();
#endregion
}
Now we've got all methods we want and didn't have to implement much. The main change in our code is, that our variables will be IList<T> instead of List<T>, ObservableCollection<T> or what ever.
And now the big wow: All of those implement IList<T>:
IList<int> list1 = new ObservableCollection<int>();
IList<int> list2 = new List<int>();
IList<int> list3 = new int[10];
IList<int> list4 = new MyList<int>();
Which brings us to the next point: Use Interfaces instead of classes. Your code should never depend on implementation-details!
One simple solution is to introduce an Add method for the list in your project and handle the event there. It doesn't answer the need for an event handler but can be useful for some small projects.
AddToList(item) // or
AddTo(list,item)
////////////////////////
void AddTo(list,item)
{
list.Add(item);
// event handling
}
instead of
list.Add(item);
You cannot do this with standard collections out of the box - they just don't support change notifications. You could build your own class by inheriting or aggregating a existing collection type or you could use BindingList<T> that implements IBindingList and supports change notifications via the ListChanged event.
To piggy-back off Ahmad's use of Extension Methods, you can create your own class where the list is private with a public get method and a public add method.
public class MyList
{
private List<SomeClass> PrivateSomeClassList;
public List<SomeClass> SomeClassList
{
get
{
return PrivateSomeClassList;
}
}
public void Add(SomeClass obj)
{
// do whatever you want
PrivateSomeClassList.Add(obj);
}
}
However, this class only provides access to List<> methods that you manually expose...hence may not be useful in cases where you need a lot of that functionality.
No need for adding an event just add the method.
public class mylist:List<string>
{
public void Add(string p)
{
// Do cool stuff here
base.Add(p);
}
}
//List overrider class
public class ListWithEvents<T> : List<T>
{
public delegate void AfterChangeHandler();
public AfterChangeHandler OnChangeEvent;
public Boolean HasAddedItems = false;
public Boolean HasRemovedItems = false;
public bool HasChanges
{
get => HasAddedItems || HasRemovedItems;
set
{
HasAddedItems = value;
HasRemovedItems = value;
}
}
public new void Add(T item)
{
base.Add(item);
HasAddedItems = true;
if(OnChangeEvent != null) OnChangeEvent();
OnChange();
}
public new void AddRange(IEnumerable<T> collection)
{
base.AddRange(collection);
HasAddedItems = true;
if (OnChangeEvent != null) OnChangeEvent();
OnChange();
}
public new void Insert(int index,T item)
{
base.Insert(index, item);
HasAddedItems = true;
if (OnChangeEvent != null) OnChangeEvent();
OnChange();
}
public new void InsertRange(int index, IEnumerable<T> collection)
{
base.InsertRange(index, collection);
HasAddedItems = true;
if (OnChangeEvent != null) OnChangeEvent();
OnChange();
}
public new void Remove(T item)
{
base.Remove(item);
HasRemovedItems = true;
if (OnChangeEvent != null) OnChangeEvent();
OnChange();
}
public new void RemoveAt(int index)
{
HasRemovedItems = true;
if (OnChangeEvent != null) OnChangeEvent();
OnChange();
}
public new void RemoveRange(int index,int count)
{
HasRemovedItems = true;
if (OnChangeEvent != null) OnChangeEvent();
OnChange();
}
public new void Clear()
{
base.Clear();
HasRemovedItems = true;
if (OnChangeEvent != null) OnChangeEvent();
OnChange();
}
public virtual void OnChange()
{
}
}