dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.16k stars 1.74k forks source link

[Bug] BindingContext default behavior, on nested controls #10296

Open Phenek opened 2 years ago

Phenek commented 2 years ago

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

SarthakGz commented 2 years ago

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

Phenek commented 2 years ago

@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>
ghost commented 2 years ago

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.

Phenek commented 1 year ago

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

What should be the default BindingContext?

*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,

AathifMahir commented 1 year ago

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