maui icon indicating copy to clipboard operation
maui copied to clipboard

[Bug] BindingContext default behavior, on nested controls

Open Phenek opened this issue 2 years ago • 4 comments

Description

Hello,

I am trying to bind a Text Property of a control that is inside another, and it does not work.

Let me explain, I was creating kind of an Input layout, like so

public partial class InputLayout : Grid
{
    public static readonly BindableProperty LabelProperty =
        BindableProperty.Create(nameof(Label), typeof(Label), typeof(InputLayout), null, propertyChanged: LabelChanged);

    public static readonly BindableProperty InputViewProperty =
       BindableProperty.Create(nameof(InputView), typeof(InputView), typeof(InputLayout), null, propertyChanged: InputViewChanged);
       
     ...
       
    public Label Label
    {
        get => (Label)GetValue(LabelProperty);
        set => SetValue(LabelProperty, value);
    }

    public InputView InputView
    {
        get => (InputView)GetValue(InputViewProperty);
        set => SetValue(InputViewProperty, value);
    }
    
    ...
    
    private static void InputViewChanged(BindableObject bindable, object oldValue, object newValue)
    {
        if (bindable is not InputLayout intputLayout
            || newValue is not InputView inputView
            || inputView is not IFontElement fontElement) return;

        Grid.SetColumn(inputView, 2);
        Grid.SetColumnSpan(inputView, 1);
        Grid.SetRow(inputView, 1);
        Grid.SetRowSpan(inputView, 1);
        intputLayout.Children.Add(inputView);
    }
}

We should be able to use it like this, But the binding on the Entry does not work anymore...

<controls:InputLayout x:Name="_email" StyleClass="NormalInputLayout">

   <controls:InputLayout.Label>
      <Label Text="Email"/>
   </controls:InputLayout.Label>

   <controls:InputLayout.InputView>
      <Entry
           Keyboard="Email"
           IsTextPredictionEnabled="false"
           Text="{Binding Email, Mode=TwoWay}"/>
   </controls:InputLayout.InputView>
   
</controls:InputLayout>

I also tried to create a intermediate Bindable Text Property in my InputLayout, then bind it progamaticaly, but it also doesn not work.

InputView.SetBinding(InputView.TextProperty, new Binding(nameof(Text)) { Source = this, Mode = BindingMode.TwoWay });

Hope you get it :)

Steps to Reproduce

  1. Take the code below to create a nested control in another one.
  2. Add an Entry as the nested control.
  3. Try to bind the TextProperty to a stringProperty from the BindingContext.
  4. You will never Bind them in anyway (OneWay, TwoWay does not work)..

Link to public reproduction project repository

Does my sample code is enough? Let me know, Regards

Version with bug

6.0.486 (current)

Last version that worked well

Unknown/Other

Affected platforms

iOS, Android, Windows, macOS

Affected platform versions

iOS 16, Mac, Android 12

Did you find any workaround?

You will need to provide a relative Source to make it works.

Text="{Binding Source={RelativeSource AncestorType={x:Type vm:SignInViewModel}}, Path=Email, Mode=TwoWay}"/>

Relevant log output

No response

Phenek avatar Sep 23 '22 22:09 Phenek

I am not sure if this should work or not but you can always use relative bindings in that case

SarthakGz avatar Sep 24 '22 04:09 SarthakGz

@SarthakGz for this workaround, It works!

Text="{Binding Source={RelativeSource AncestorType={x:Type vm:SignInViewModel}}, Path=Email, Mode=TwoWay}"/>

Maybe this one needs attention, Is it the correct default behavior?

PS: I know that I can Bind a color to a Shadow witout Relative Binding, so why do I have to do this with my nested input?

<Border ...>
   <Border.Shadow>
      <Shadow  Brush="{Binding ShadowBrush, Mode=OneWay}"
         Offset="0,2" 
         Radius="20" 
         Opacity="0.5" />
   </Border.Shadow>
   ...
   <Border>

Phenek avatar Sep 24 '22 07:09 Phenek

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

ghost avatar Sep 28 '22 18:09 ghost

Hello, Could we have a guideline about the future intended behavior of BindingContext?

  • using Source={RelativeSource AncestorType={x:Type ...}} is making useless the x:Datatype autocompletion Does it make Compiled Bindings? (Compiled bindings are resolved more quickly than classic bindings)

  • Or I can set the Binding context manually on each elements on the page and so on to their children, when Parent set and when BindingContextChanged... _view.BindingContext = BindingContext;

What should be the default BindingContext?

  • Null ?
  • Self ? (generaly the view it self) *
  • The closest parent BindingContext not Null ? *

*This two are really interesting, and depends if you works on MVVM or not. Maybe x:Datatype could choose for us?

I just wanted to know which way should I take, to make less refactoring at the end. Regards,

Phenek avatar Nov 26 '22 10:11 Phenek

This is kind a Sucks, The Intel sense does show the properties for nested controls and binds without any issue but doesn't work when app launches, On Most Cases We need to use RelativeSource or Reference Markup Extensions to Get Most of it work on Nested Controls with Compiled Bindings with Single Data Context

AathifMahir avatar May 03 '23 12:05 AathifMahir