Last week I published an article about the x:DefaultBindMode
feature in UWP XAML. Uno Platform, the cross-platform UWP/WinUI bridge for Android, iOS, and WebAssembly, was at that time missing the feature. What happened next, was astounding. In just over a day, the feature was not only implemented but also merged (along with several additional improvements like BindBack
!) and available in the latest prerelease package on NuGet. Just wow.
Example on WASM
Taking one of the code samples from my previous article:
It now just works as expected on WebAssembly running Uno Platform – TextBlock
uses OneWay
binding, while TextBox
explicitly overrides this with TwoWay
. The same on all other Uno Platform targets.
How did they do this?
I thought it would be interesting to look into how the Uno Platform team achieved this magically quick implementation of the feature. The whole feature was implemented in the XamlFileGenerator class, which generates C# code from XAML. The x:DefaultBindMode
feature works as a "scope," meaning the declared mode applies to an element and all its children unless overridden somewhere further down the tree. As the XAML file is parsed in a depth-first manner, the most appropriate data structure to maintain the currently "active" bind mode is a LIFO (Last-In-First-Out) data structure like a stack. And that is what Uno Platform uses to maintain the feature's state:
Notice the stack is initialized with OneTime
– this matches the UWP's default x:Bind
mode. So unless x:DefaultBindMode
is used in the XAML file, OneTime
is the fallback. How do we push a new "default mode" in the stack? That's where the TrySetDefaultBindMode
method comes in:
First, the code retrieves the DefaultBindMode
attribute from the element's XAML definition. If this is not defined, the method short-circuits and returns null
. If the bind mode was defined, it is validated against the list of known values (IsValid
) method. For a valid DefaultBindMode
value, we need to push it onto the stack to start a new scope. The method then returns a DisposableAction
instance, which implements IDisposable
and makes sure to execute the passed in lambda when it is disposed of. And in this case, it pops the top value off the stack to end the current scope. This greatly aids the readability of the code, as it really signifies the fact that the method creates a new scope when used with the using
block:
Note that in case TrySetDefaultBindMode
evaluates to a null
(for the case when DefaultBindMode
is not set), using
statement just ignores it (and does not attempt to call Dispose()
on null
at the end). Finally, retrieving the currently set mode is a simple Peek
of the top of the stack:
The GetDefaultBindMode()
method is used, when the x:Bind
evaluation function is constructed:
Succinctly said, when the x:Bind
explicitly states a Mode
, it takes precedence. Otherwise the currently active DefaultBindMode
is applied. That's all there's to it! As we can see, the feature was implemented very elegantly, and thanks to Uno Platform, we really have #WinUIEverywhere!