Table of Contents

BindableList

A basic way to make a Bindable list is just to throw a regular C# List into a Bindable:

public Bindable<List<int>> IntList = new(new());

This will work fine, but has some limations. For example, editing the list does not trigger change events, so you'll need to raise them yourself:

IntList.Value[3] = 5; // Does not trigger OnChange!

IntList.NotifyChanged(); // Manually trigger OnChange

Additionally, there's no way to detect whether a single element changed, or if the whole list changed. To get those features, use the BindableList class.

Instead, use BindableList:

public BindableList<int> IntList = new();

This class inherits from Bindable<List<int>> and also implements IList<T> which allows you to perform standard list operations:

// Iterate over the list:
foreach (var item in IntList) { ... }

// Add an item - triggers OnElementAdd
IntList.Add(5);

// Edit an item - triggers OnElementChange
IntList[0] = 6;

// Remove an item - triggers OnElementRemove
IntList.Remove(0);

// Sorts the list - triggers OnChange
IntList.Sort();

Events

In addition to OnChange and OnChangeWithValue, BindableList provides the following events:

  • OnElementAdd: Invoked when Add, AddRange, Insert, or InsertRange are called.
  • OnElementChange: Invoked when list[index] = value
  • OnElementMoved: Invoked when Move is called.
  • OnElementSwap: Invoked when Swap is called.
  • OnElementRemove: Invoked when Remove or RemoveRange is called.
  • OnChange: Invoked when the underlying list Value is changed, or when Clear, Sort, or Reverse are called.

DerivedList

You can standard Linq operations with BindableList, but they will generate a regular IEnumerable, not a Bindable.

To cover this gap, we added the methods DeriveSelect, DeriveConcat, DeriveCast, and DeriveDictionary. These will each return a Bindable which is bound to the original list. For example:

var list = new BindableList<int>();
var derivedList = list.DeriveSelect(n => n + 1);

list.Add(5);
list.Add(7);

// derivedList will now have [6, 8].

You can also use Derived.From to select from one list or the other, and all the change events will carry over to the appropriate list. When the list switches, OnChange will be invoked.

var list1 = new BindableList<int>() { 1, 2 };
var list2 = new BindableList<int>() { 3, 4 };
var selector = new Bindable<bool>();

var selectedList = Derived.From(selector, list1, list2, (sel, l1, l2) => sel ? l1 : l2);

this.Bind(selectedList, Debug.Log(string.Join(", ", selectedList)));

// This prints "1, 2" because selectedList == list1

selector.Value = true;

// This prints "3, 4" because selectedList == list2