Apparently, general bindings in Setters are not supported yet in WinUI 3, although it is a much-requested feature. A workaround is to create a helper class with a DependencyProperty in it that calls a change handler whenever the property is changed/set. The change handler can then create the required binding in code. Kudos to clemens who suggested something like this ages ago for UWP. Here is an example helper class:
internal class BindingHelper
{
#region CompactPaneLengthBindingPath
public static readonly DependencyProperty CompactPaneLengthBindingPathProperty = DependencyProperty.RegisterAttached(
"CompactPaneLengthBindingPath", typeof(string), typeof(BindingHelper), new PropertyMetadata(null, BindingPathChanged));
public static string GetCompactPaneLengthBindingPath(DependencyObject obj)
{
return (string)obj.GetValue(CompactPaneLengthBindingPathProperty);
}
public static void SetCompactPaneLengthBindingPath(DependencyObject obj, string value)
{
obj.SetValue(CompactPaneLengthBindingPathProperty, value);
}
#endregion
#region HeightBindingPath
// another DP is defined here (all of them are strings)
#region ForegroundBindingPath
// and a third one, etc.
// ===================== Change Handler: Creates the actual binding
private static void BindingPathChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is string source) // source property (could add DataContext by setting Value="source@datacontext" for example)
{
DependencyProperty target; // which property is the target of the binding?
if (e.Property == CompactPaneLengthBindingPathProperty) target = NavigationView.CompactPaneLengthProperty;
else if (e.Property == HeightBindingPathProperty) target = FrameworkElement.HeightProperty;
else if (e.Property == ForegroundBindingPathProperty) target = Control.ForegroundProperty;
else throw new System.Exception($"BindingHelper: Unknown target ({nameof(e.Property)}"); // don't know this property
obj.ClearValue(target); // clear previous bindings (and value)
BindingOperations.SetBinding(obj, target, // set new binding (and value)
new Binding { Path = new PropertyPath(source), Mode = BindingMode.OneWay });
}
}
Note that all of the DependencyProperties are of type string and that the target type can be any ancestor type of the control you are working with. For example, the HeightBindingPathProperty
binding can be used with any FrameworkElement.
Use the helper in a Style just as you would any Setter, like this:
<Style x:Key="MyNavigationView" TargetType="controls:NavigationView" >
<Setter Property="local:BindingHelper.CompactPaneLengthBindingPath" Value="CurrentCompactPaneLength" />
</Style>
I hope this helps.