Skip to content

Instantly share code, notes, and snippets.

@chiepomme
Last active August 29, 2015 14:17
Show Gist options
  • Save chiepomme/3057e64762f126becc62 to your computer and use it in GitHub Desktop.
Save chiepomme/3057e64762f126becc62 to your computer and use it in GitHub Desktop.
まねっこ ObservableCollection
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using UnityEngine.Events;
namespace Chiepomme
{
public enum ChangeAction
{
Add,
Update,
Remove,
Reset,
}
// imitating C# ObservableCollection<T>
// see https://msdn.microsoft.com/ja-jp/library/ms668604(v=vs.110).aspx
public class CollectionChange<T>
{
public readonly ChangeAction Action;
public readonly IEnumerable<T> NewItems;
public readonly int NewStartingIndex;
public readonly IEnumerable<T> OldItems;
public readonly int OldStartingIndex;
CollectionChange(ChangeAction action,
IEnumerable<T> newItems = null, int newStartingIndex = 0,
IEnumerable<T> oldItems = null, int oldStartingIndex = 0)
{
Action = action;
NewItems = newItems ?? new T[0];
NewStartingIndex = newStartingIndex;
OldItems = oldItems ?? new T[0];
OldStartingIndex = oldStartingIndex;
}
static public CollectionChange<T> CreateAdd(int startingIndex, T addedItem)
{
return new CollectionChange<T>(ChangeAction.Add,
newStartingIndex: startingIndex, newItems: new[] { addedItem });
}
static public CollectionChange<T> CreateAdd(int startingIndex, IEnumerable<T> addedItems)
{
return new CollectionChange<T>(ChangeAction.Add,
newStartingIndex: startingIndex, newItems: addedItems);
}
static public CollectionChange<T> CreateUpdate(int replacedIndex, T oldItem, T newItem)
{
return new CollectionChange<T>(ChangeAction.Update,
oldStartingIndex: replacedIndex, oldItems: new[] { oldItem },
newStartingIndex: replacedIndex, newItems: new[] { newItem });
}
static public CollectionChange<T> CreateRemove(int startingIndex, T removedItem)
{
return new CollectionChange<T>(ChangeAction.Remove,
oldStartingIndex: startingIndex, oldItems: new[] { removedItem });
}
static public CollectionChange<T> CreateRemove(int startingIndex, IEnumerable<T> removedItems)
{
return new CollectionChange<T>(ChangeAction.Remove,
oldStartingIndex: startingIndex, oldItems: removedItems);
}
static public CollectionChange<T> CreateReset(IEnumerable<T> oldItems, IEnumerable<T> newItems)
{
return new CollectionChange<T>(ChangeAction.Reset,
oldStartingIndex: 0, oldItems: oldItems,
newStartingIndex: 0, newItems: newItems);
}
}
public class ObservableList<T> : UnityEvent<CollectionChange<T>>, IList<T>
{
List<T> v;
public ReadOnlyCollection<T> Collection
{
get { return v.AsReadOnly(); }
}
public ObservableList()
{
v = new List<T>();
}
public ObservableList(IEnumerable<T> collection)
{
v = collection.ToList();
}
/// <summary> event: Reset </summary>
public void Replace(IEnumerable<T> collection)
{
var oldItems = v.AsEnumerable();
v = collection.ToList();
Notify(CollectionChange<T>.CreateReset(oldItems, v.ToArray()));
}
/// <summary> event: Add </summary>
public void Add(T item)
{
var index = v.Count;
v.Add(item);
Notify(CollectionChange<T>.CreateAdd(index, item));
}
/// <summary> event: Remove </summary>
public bool Remove(T item)
{
var index = v.IndexOf(item);
if (index == -1) return false;
RemoveAt(index);
return true;
}
public int IndexOf(T item)
{
return v.IndexOf(item);
}
/// <summary> event: Add </summary>
public void Insert(int index, T item)
{
v.Insert(index, item);
Notify(CollectionChange<T>.CreateAdd(index, item));
}
/// <summary> event: Remove </summary>
public void RemoveAt(int index)
{
var removedItem = v[index];
v.RemoveAt(index);
Notify(CollectionChange<T>.CreateRemove(index, removedItem));
}
/// <summary> event: Update </summary>
public T this[int index]
{
get
{
return v[index];
}
set
{
var oldItem = v[index];
v[index] = value;
Notify(CollectionChange<T>.CreateUpdate(index, oldItem, value));
}
}
/// <summary> event: Reset </summary>
public void Clear()
{
if (v.Count == 0) return;
var oldItems = v.ToArray();
v.Clear();
Notify(CollectionChange<T>.CreateReset(oldItems, new T[0]));
}
public bool Contains(T item)
{
return v.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
v.CopyTo(array, arrayIndex);
}
public int Count
{
get { return v.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public IEnumerator<T> GetEnumerator()
{
return v.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return v.GetEnumerator();
}
void Notify(CollectionChange<T> change)
{
Invoke(change);
}
/// <summary> event: Reset </summary>
public void BindListener(UnityAction<CollectionChange<T>> listener)
{
AddListener(listener);
listener(CollectionChange<T>.CreateReset(new T[0], v.ToArray()));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment