Game.UI.Widgets.WidgetBindings
Assembly: Assembly-CSharp (Game)
Namespace: Game.UI.Widgets
Type: class
Base: CompositeBinding, IReader
Summary:
WidgetBindings manages a collection of child IWidget instances and exposes them to the Colossal.UI binding system as a single composite binding ("children" by default). It tracks changes in the widget tree, patches the JSON child list output when required, and provides a mechanism to add sets of widget-related bindings via binding factories. It also implements IReader
Fields
-
private string m_Group
The binding group name that identifies this bindings instance. Used when creating underlying bindings (e.g., RawValueBinding). -
private List<IWidget> m_LastChildren = new List<IWidget>()
A cached copy of the last known children list. Used to detect list-level changes and to write the child list to the writer. -
private List<int> m_CurrentPath = new List<int>()
Temporary stack that records the current index path while traversing the widget tree for patching. Used by UpdateSubTree to build JSON path segments. -
private RawValueBinding m_ChildrenBinding
The RawValueBinding representing the "children" value exposed to the binding system. This binding is updated (or patched) when the widget tree changes.
Properties
-
public IList<IWidget> children { get; set; } = new List<IWidget>()
The current list of top-level child widgets managed by this binding. External code (e.g., widget containers) should set or modify this list. Changes to this list are compared against m_LastChildren to detect and apply updates. -
public bool active => m_ChildrenBinding.active
Convenience property that forwards to the underlying RawValueBinding's active state. If not active, UpdateChildrenBinding and related processing are skipped. -
public event ValueChangedCallback EventValueChanged
Event fired when a child widget triggers a value change via OnValueChanged. Subscribers can react to widget-level value changes.
Constructors
public WidgetBindings(string group, string name = "children")
Create a new WidgetBindings instance. The group parameter is used to namespace created bindings, and the optional name parameter specifies the child-list binding name (defaults to "children"). The constructor creates and registers the RawValueBinding for the children list and wires it to WriteChildren.
Methods
-
public void AddDefaultBindings()
Convenience to add several common binding factories: InvokableBindings, SettableBindings, ExpandableBindings, ListBindings, and PagedBindings. This simplifies standard widget binding setup. -
public void AddBindings<U>() where U : IWidgetBindingFactory, new()
Generic helper that constructs a binding factory of type U and calls the non-generic AddBindings overload. -
public void AddBindings(IWidgetBindingFactory bindingFactory)
Add bindings produced by the provided factory. The factory's CreateBindings method is invoked with the group and this WidgetBindings instance; each returned IBinding is registered on this composite binding. -
private void OnValueChanged(IWidget widget)
Internal callback invoked by binding factories or child widgets when their value changes. Calls UpdateChildrenBinding (to ensure any resulting tree changes are applied) and raises the public EventValueChanged event for subscribers. -
public override bool Update()
Overridden Update from CompositeBinding. Ensures UpdateChildrenBinding is executed before calling the base Update. Returns the base Update result. -
private void UpdateChildrenBinding()
Ensures children list and subtree are reconciled with the binding system. If active, it: - Compares children to m_LastChildren, updates m_LastChildren and calls ContainerExtensions.SetDefaults when the outer list changed.
- Clears m_CurrentPath and traverses the tree via UpdateSubTree to calculate whether a full update is required or a patch can be applied.
- Asserts the m_CurrentPath is empty after traversal.
-
If changes are detected, either patches (via Widget.PatchWidget) or calls m_ChildrenBinding.Update() to push the full list.
-
private bool UpdateSubTree(IList<IWidget> widgets, bool patch)
Traverses the given widget list recursively. For each widget: - Calls widget.Update() to get WidgetChanges flags.
- Pushes the index onto m_CurrentPath and recurses into visibleChildren; if a child's subtree indicates changes, the parent's WidgetChanges.Children flag is set.
- If there are changes for this widget and patching was requested, Widget.PatchWidget is called with the current path and change mask. If patching is not requested, the method returns true to indicate that a non-patch (full) update is required.
-
Pops the index before continuing. Returns true if any node in the subtree caused a non-patch-required change.
-
private void WriteChildren(IJsonWriter writer)
Writes the cached m_LastChildren to the provided IJsonWriter. This is the callback used by the RawValueBinding to serialize the children list to the binding system. -
void IReader<IWidget>.Read(IJsonReader reader, out IWidget value)
Implementation of IReaderthat reads a path array from the reader and resolves it to an IWidget reference by walking the cached m_LastChildren and successive FindChild calls. If the array is empty, value is left null. Uses PathSegment to parse path elements.
Usage Example
// Create bindings for a container widget:
// group is a binding-group prefix (e.g., "myPanel"), name is optional
var bindings = new WidgetBindings("myGroup");
// Add common widget bindings
bindings.AddDefaultBindings();
// Hook value-changed events (e.g., to react to child widget interactions)
bindings.EventValueChanged += widget =>
{
// handle widget value change...
};
// Assign children (the container should keep the children list up to date)
containerBindings.children = new List<IWidget> { buttonWidget, labelWidget };
// During update loop, call Update so bindings and patches are applied:
bindings.Update();
Notes and implementation details:
- WidgetBindings relies on ContainerExtensions.SetDefaults to initialize newly detected children and on Widget.PatchWidget to perform efficient JSON patches for subtree changes when possible.
- The class tracks a per-update m_CurrentPath to build path segments for patch operations; an assertion ensures no path fragments are left after traversal.
- IReader