xamarin / Xamarin.Forms

Xamarin.Forms is no longer supported. Migrate your apps to .NET MAUI.
https://aka.ms/xamarin-upgrade
Other
5.62k stars 1.87k forks source link

[Bug] RadioButton does not pass its BindingContext to its content #15176

Open sjordanGSS opened 2 years ago

sjordanGSS commented 2 years ago

Description

If a RadioButton is created with a ControlTemplate to allow it to display its .Content as a view, the BindingContext of the RadioButton doesn't get passed to .Content

Steps to Reproduce

  1. Create a blank project
  2. Create a view model for the main page with a property
  3. Add a RadioButton with a ControlTemplate that includes a ContentPresenter
  4. Set .Content on the RadioButton to a view e.g. a Label and create a binding to the viewmodel property

a Repro is available here: https://github.com/sjordanGSS/radio-button-content-binding-context-repro

Expected Behavior

The Label should display the value of the bound property

Actual Behavior

The Label does not display the value of the bound property

Basic Information

Environment

Show/Hide Visual Studio info ``` ```

Build Logs

Screenshots

Reproduction Link

Workaround

As demonstrated in the repro project, a RelativeSource binding can be used to traverse the view hierarchy until the desired viewmodel is found and then bound to.

Ruvi1996 commented 2 years ago

I have the same issue

sjordanGSS commented 2 years ago

Beginning to wonder whether or not this is actually a RadioButton bug, at first I thought I'd found a divergence in behaviour between the way that RadioButton and e.g. ContentPage handle ControlTemplates, but I've just reviewed a ControlTemplate that I wrote for ContentPage and noticed that it uses

BindingContext="{Binding Source={RelativeSource TemplatedParent}, Path=BindingContext}"

on the top level control within the template, which will obviously set the BindingContext of all controls within the template to the BindingContext of whatever they're templated onto. I've yet to test this on a RadioButton but I have a sinking feeling that it'll produce the expected behaviour

Sorry I'm getting myself in a right muddle: the ControlTemplate for the ContentPage sets its BindingContext to TemplatedParent.BindingContext so it can bind to properties from the viewmodel, the Content of the ContentPage doesn't have to do this. This does deviate from how things work with RadioButton where the Content's BindingContext doesn't get set, as is described by the OP.

RhomGit commented 2 years ago

Do you still have a repro/workaround for this? The repro link is dead. As you describe I also can't bind the content of RadioButtons inside a BindableLayout.

sjordanGSS commented 2 years ago

Do you still have a repro/workaround for this? The repro link is dead. As you describe I also can't bind the content of RadioButtons inside a BindableLayout.

Repro link seems to be working fine for me, the repo is still up and should be publicly available. What error do you get when clicking it?

As noted in the OP, you can use a RelativeSource binding in your .Content with Mode set to FindAncestorBindingContext to traverse the view hierarchy and find the proper binding target. So if you're binding to a viewmodel called RadioButtonViewModel with a property RadioButtonText, you should be able to use

<Label Text={Binding Source={RelativeBinding Mode=AncestorBindingContext, AncestorType={x:type viewmodels:RadioButtonViewModel}}, Path=RadioButtonText}" />

in your .Content.

RhomGit commented 2 years ago

I think your repro is set to private.

I had to change your above syntax according to: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/data-binding/relative-bindings#bind-to-an-ancestor however your workaround worked and I am now able to move forward. Thanks very much, this should be in the official XF documentation for radio buttons as I think its critical to anyone trying to use it like this. All the static samples for RadioButtons are pretty elementary and almost worthless without data binding.

sjordanGSS commented 2 years ago

I think your repro is set to private.

I had to change your above syntax according to: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/data-binding/relative-bindings#bind-to-an-ancestor however your workaround worked and I am now able to move forward. Thanks very much, this should be in the official XF documentation for radio buttons as I think its critical to anyone trying to use it like this. All the static samples for RadioButtons are pretty elementary and almost worthless without data binding.

It was set to private. I don't even know how I did that. It should be set to public now. Thanks!

Great to hear you've been able to solve your problem. I think this is a bug rather than an intended feature since, as I've noted, it is inconsistent with the way that other controls handle templates: ContentPage will pass the BindingContext to its .Content correctly when using a ControlTemplate.