Table of Contents

BindableDictionary

A basic way to make a Bindable dictionary is just to throw a regular C# Dictionary into a Bindable:

public Bindable<Dictionary<string, int>> IntDict = new(new());

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

IntDict.Value["cat"] = 5; // Does not trigger OnChange!

IntDict.NotifyChanged(); // Manually trigger OnChange

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

BindableDictionary

Create a BindableDictionary:

public BindableDictionary<string, int> IntDict = new();

This class inherits from Bindable<Dictionary<string, int>> and also implements IDictionary<string, int> which allows you to perform standard dictionary operations:

// Iterate over the dictionary:
foreach (var (key, value) in IntDict) { ... }

// Add an item - triggers OnElementAdd
IntDict.Add("cat", 5);

// Edit an item - triggers OnElementChange
IntDict["cat"] = 6;

// Remove an item - triggers OnElementRemove
IntDict.Remove("cat");

Events

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

  • OnElementAdd: Invoked when a new key is added.
  • OnElementChange: Invoked when an existing key is changed.
  • OnElementRemove: Invoked when a key is removed.
  • OnChange: Invoked when the underlying dictionary Value is changed, or when Clear is called.

DerivedDictionary

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

var dict1 = new BindableDictionary<string, int>();
dict1.Add("cat", 1);
dict1.Add("dog", 2);

var dict2 = new BindableDictionary<string, int>();
dict2.Add("foo", 3);
dict2.Add("bar", 4);

var selector = new Bindable<bool>();

var selectedDict = Derived.From(selector, dict1, dict2, (sel, d1, d2) => sel ? d1 : d2);

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

// This prints '("cat", 1), ("dog", 2)' because selectedDict == dict1

selector.Value = true;

// This prints '("foo", 3), ("bar", 4)' because selectedDict == dict2