MVVM and binding
Connect typed ViewModels to bindable properties without reflection or runtime code generation.
SkeleKit bindings work with ordinary INotifyPropertyChanged objects and ICommand. There is no required ViewModel base class. CommunityToolkit.Mvvm is convenient, but the binding system does not depend on it.
For command execution and gesture-backed actions, see commands and gestures.
The first binding is one-way: property changes update the label. Adding TwoWay to the second binding lets control changes run its writer, so both ViewModel changes and user interaction stay synchronized.
Converting values
Use ConvertTo when the control and source use different representations:
For a converted two-way binding, define both conversion directions before completing it with the source writer:
The writer receives the source type returned by ConvertFrom. In this example, age is an int, while the converters bridge that source value to and from the control's nullable string. ConvertTo by itself remains a valid one-way binding. Adding ConvertFrom makes the chain incomplete until TwoWay supplies the source writer.
This is useful for numeric text fields, but validation still belongs in the ViewModel or submission flow.
Update triggers
Two-way bindings update on every control change by default. Text controls can defer the write until focus leaves:
Other binding modes
Once reads whenever a context attaches and does not subscribe to later changes. Put conversion after the mode:
For a source-only binding, start with parameterless Bind() and state the source value type on ToSource. It never reads or observes the source:
When the control and source types differ, state the control type on ConvertFrom:
A bare Bind() is intentionally incomplete and cannot be assigned. Outside a typed ContentView or ItemView, use BindingFactory.Bind<MyViewModel>() to supply the source type.
Keep source writers to direct assignment. Put parsing, normalization, and fallback behavior in ConvertFrom, where the control value is transformed into the exact source type before the writer runs.
Nested paths
A normal nested binding evaluates the complete lambda but observes only the root ViewModel:
Use Path when changes raised by the intermediate object must update the control too:
The binding observes both MovieViewModel.Movie and Movie.Name. Replacing Movie moves the leaf subscription to the new instance. Additional Path calls can observe deeper object graphs.
A nested two-way writer receives the object from the final path rather than the root ViewModel:
When an intermediate property is nullable, handle that in the path lambda: .Path(movie => movie?.Name).
Binding paths must be plain property access. Calls, indexers, casts, and arbitrary expressions are rejected because SkeleKit derives subscriptions from the captured lambda text instead of using reflection or compiled expression trees.
Paths must come before conversion or binding mode selection. They are unavailable on parameterless source-only bindings because the source writer can access nested objects directly.
Lists
List-valued properties accept arrays, List<T>, ObservableCollection<T>, collection expressions, or a binding through BindableList<T>. An ObservableCollection<T> updates live controls such as Picker and CollectionView as items are added, removed, moved, or replaced.
The collection data and templates guide shows how item bindings behave with recycled cells.
Binding context
Bindings resolve against BindingContext. Panels pass their inherited context into their descendants. Set a local context when a reusable subtree needs another source; removing that local value makes it inherit from its parent again.