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
21.84k stars 1.67k forks source link

Children in CollectionView do not inherit BindingContext #9131

Open pekspro opened 1 year ago

pekspro commented 1 year ago

Description

I have two issues with BindingContext. First issue is that will not set the correct BindingContext on a ContentView:

<CollectionView.ItemTemplate>
    <DataTemplate>
        <vm:PersonView BindingContext="{Binding Leader}"/>
    </DataTemplate>
</CollectionView.ItemTemplate>

But this will;

<CollectionView.ItemTemplate>
    <DataTemplate>
        <Grid>
           <vm:PersonView BindingContext="{Binding Leader}"/>
        </Grid>
    </DataTemplate>
</CollectionView.ItemTemplate>

Second issue is that setting a BindingContext from a list is OK. Sample:

<VerticalStackLayout BindingContext="{Binding TheTeams[0]}">

This works fine when running an application. But if compiled binding are used, this will not compile.

Steps to Reproduce

  1. Create a new MAUI application.
  2. Add a ContentView named PersonView with this XAML content:
    <VerticalStackLayout>
    <Label Text="{Binding PersonName}" />
    </VerticalStackLayout>
  3. Replace the code in MainPage.xaml.cs:
    
    public record Person (string PersonName);

public record Team (string TeamName, Person Leader);

public record Teams (List TheTeams);

public partial class MainPage : ContentPage { public MainPage() { InitializeComponent();

    Person alice = new Person("Alice");
    Team coders = new Team("Coders", alice);
    Teams teams = new Teams(new List<Team> { coders });

    BindingContext = teams;
}

}

4. Replace MainPage.xaml with this:

``` XAML
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:vm="clr-namespace:MauiIssues"
             x:Class="MauiIssues.MainPage"
             >
    <!--Add this to ContentPage to see Issue 2. x:DataType="vm:Teams"-->

    <VerticalStackLayout>
        <Label Text="Issue 1: " />
        <CollectionView ItemsSource="{Binding TheTeams}">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <!--
                        Issue 1. This will show nothing. A workaround is to wrap everything in a Grid:

                        <Grid> <vm:PersonView BindingContext="{Binding Leader}"/> </Grid>
                    -->
                    <vm:PersonView BindingContext="{Binding Leader}"/>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>

        <!-- 
            Issue 2. These will not compile when x:DataType="vm:Teams" is added to ContentPage.
        -->
        <Label Text="Issue 2A:" />
        <VerticalStackLayout BindingContext="{Binding TheTeams[0]}">
            <HorizontalStackLayout BindingContext="{Binding Leader}">
                <Label Text="{Binding PersonName}" />
            </HorizontalStackLayout>
        </VerticalStackLayout>

        <Label Text="Issue 2B:" />
        <CollectionView ItemsSource="{Binding TheTeams}">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <VerticalStackLayout>
                        <HorizontalStackLayout BindingContext="{Binding Leader}">
                            <Label Text="{Binding PersonName}" />
                        </HorizontalStackLayout>
                    </VerticalStackLayout>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </VerticalStackLayout>
</ContentPage>
  1. Run the application. You will see nothing on issue 1. Wrap the view in Grid and it will work.
  2. Add x:DataType="vm:Teams" in the ContentPage tag.
  3. The project will no longer compile.

Full sample: https://github.com/pekspro/MauiIssues/tree/9131_BindingContext_cannot_be_changed

Version with bug

6.0.408 (current)

Last version that worked well

Unknown/Other

Affected platforms

Windows, I was not able test on other platforms

Affected platform versions

Windows 10.0.17763.0

Did you find any workaround?

Yes, described in the code.

Relevant log output

No response

PureWeen commented 1 year ago

Ideally we could just change this line

https://github.com/dotnet/maui/blob/733ba2f93b73e1acacc23d593c5380f188c6b1c9/src/Compatibility/Core/src/Android/CollectionView/TemplatedItemViewHolder.cs#L67

to use

VisualElement.SetInheritedBindingContext(View, itemBindingContext);

But then that causes the BC to flow from the parent which we don't want.

There's a similar case with this if you look at ContentPresenter where it overrides this

        internal override void SetChildInheritedBindingContext(Element child, object context)
        {
            // We never want to use the standard inheritance mechanism, we will get this set by our parent
        }

so that the BC doesn't flow from the parent. We don't really have a place to do this with CV but maybe this can be reworked so the BindableObject can get flagged to ignore the parent BC.

pekspro commented 1 year ago

I've updated sample application to .NET 7. The same issue remains, and it also an issue on Android.

XamlTest commented 1 year ago

Verified this on Visual Studio Enterprise 17.7.0 Preview 1.0. Repro on Windows 11 with below Project: 9131.zip

Issue1: Show nothing for Issue1 in application. image

Issue2: Run failed with Error XFC0045 "Binding: Property "Leader" not found on "MauiApp11.Teams"." after adding x:DataType="vm:Teams" to ContentPage. image