dotnet/maui

XamlC resolves x:DataType incorrectly

mattleibow opened this issue ยท 14 comments

Description

This is partly a collection of issues and partly a more specific issue. Not sure if this is 100% a bug in all cases either.

XamlC uses the x:DataType="<type-name>" on <DataTemplate> to generate type-specific bindings, however, somce times the scope is incorrect or if the XAML is wrong but happens to match there is no exception and just fails silently.

In debug you can also get these errors using <_MauiForceXamlCForDebug>true</_MauiForceXamlCForDebug> but still no warnings or exceptions anywhere.

Steps to Reproduce

  1. Clone https://github.com/mattleibow/maui-bug-repros/tree/repro-xamlc-datatype
  2. Run
  3. Observe that not all the collection views have items in them

Link to public reproduction project repository

https://github.com/mattleibow/maui-bug-repros/blob/repro-xamlc-datatype/MauiApp1/MainPage.xaml

Version with bug

7.0 (current)

Last version that worked well

Unknown/Other

Affected platforms

iOS, Android, Windows, macOS, Other (Tizen, Linux, etc. not supported by Microsoft directly)

Affected platform versions

All versions

Did you find any workaround?

Make sure the x:DataType is specified correctly, and on every level of templates.

Relevant log output

No response

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.

This may have a simpler repro case: #13764

Can you give some love (priority) to this issue (I created a duplicated one yesterday the one @mattleibow mentioned) ?

From what I see Compiled bindings don't actually work as compiled bindings in MAUI and this issue is 3 months old

Thanks

Bump

Bump

Bump

Trying to keep the issue alive :)

homeyf commented

Verified this issue with Visual Studio Enterprise 17.7.0 Preview 3.0(net8). Can repro on Windows platform with sample Project.
https://github.com/mattleibow/maui-bug-repros/tree/repro-xamlc-datatype
image

@StephaneDelcroix Can I add this one to your short list?

nor0x commented

I can reproduce the issue with a Button in a CollectionView DataTemplate that binds to a Command on the page's BindingContext and passes the data binding element {Binding .} to it as a parameter

my comment and repro from #13754 (comment)

still a critical issue with version 8.0.0-preview.7.8842 which completely breaks CollectionView (haven't tested with other collection controls) on Windows. I have the usecase of a Button inside a CollectionView that has a Command binding to the ViewModel and passes the current Item (MyItem class) as a CommandParameter.

Executing this command fails of course because the Type of the CommandParameter is ViewModel instead of MyItem
Error Message:
Parameter "parameter" (object) cannot be of type MauiApp1.MainViewModel, as the command type requires an argument of type MauiApp1.MyItem. (Parameter 'parameter')

StackTrace:

   at CommunityToolkit.Mvvm.Input.RelayCommand`1.ThrowArgumentExceptionForInvalidCommandArgument(Object parameter)
   at CommunityToolkit.Mvvm.Input.RelayCommand`1.Execute(Object parameter)
   at Microsoft.Maui.Controls.ButtonElement.ElementClicked(VisualElement visualElement, IButtonElement ButtonElementManager)
   at Microsoft.Maui.Controls.Button.SendClicked()
   at Microsoft.Maui.Controls.Button.Microsoft.Maui.IButton.Clicked()
   at Microsoft.Maui.Handlers.ButtonHandler.OnClick(Object sender, RoutedEventArgs e)
   at WinRT._EventSource_global__Microsoft_UI_Xaml_RoutedEventHandler.EventState.<GetEventInvoke>b__1_0(Object sender, RoutedEventArgs e)
   at ABI.Microsoft.UI.Xaml.RoutedEventHandler.Do_Abi_Invoke(IntPtr thisPtr, IntPtr sender, IntPtr e)
--- End of stack trace from previous location ---
   at WinRT.ExceptionHelpers.<ThrowExceptionForHR>g__Throw|20_0(Int32 hr)
   at WinRT.ExceptionHelpers.ThrowExceptionForHR(Int32 hr)
   at ABI.Microsoft.UI.Xaml.Controls.IControlOverridesMethods.OnPointerReleased(IObjectReference _obj, PointerRoutedEventArgs e)
   at Microsoft.UI.Xaml.Controls.Control.OnPointerReleased(PointerRoutedEventArgs e)
   at Microsoft.UI.Xaml.Controls.Control.Microsoft.UI.Xaml.Controls.IControlOverrides.OnPointerReleased(PointerRoutedEventArgs e)
   at ABI.Microsoft.UI.Xaml.Controls.IControlOverrides.Do_Abi_OnPointerReleased_3(IntPtr thisPtr, IntPtr e)

And of course the output log is filled with Binding Diagnostic Errors:

Microsoft.Maui.Controls.Xaml.Diagnostics.BindingDiagnostics: Warning: 'ClickCommand' property not found on 'MauiApp1.MainViewModel', target property: 'Microsoft.Maui.Controls.Button.Command'
Microsoft.Maui.Controls.Xaml.Diagnostics.BindingDiagnostics: Warning: 'Name' property not found on 'MauiApp1.MainViewModel', target property: 'Microsoft.Maui.Controls.Label.Text'
Microsoft.Maui.Controls.Xaml.Diagnostics.BindingDiagnostics: Warning: 'Description' property not found on 'MauiApp1.MainViewModel', target property: 'Microsoft.Maui.Controls.Label.Text'

image

My Repro:

MauiApp1.zip

I wrote a test for 13764 and it looks like this no longer happens (main branch). The observer behavior is as follow

  • on Debug, x:DataType is ignored, and binding are resolved if possible using reflection
  • on Release, bindings with the wrong x:DataType silently fail

making the page crash on mismatching DataType is NOT an option, as the binding context could change multiple times when parenting the element until the 'right' context is set

what are the expectation ? sending a binding diagnostic warning on Debug ?

I suppose I lumped them all in together because I suppose I expected an exception. But maybe these are 3 separate issues and one is "just add a message".

Probably this one is more we need to add some logging or maybe a way to detect this. The generated code is using the type in the XAML, and thus it does not work. Maybe a detection can be added or logs:

<!--
    This results in an incorrect UI because the DataType on the
    DataTemplate is the wrong one.
    The generated TypedBinding is using the "incorrect" types:
         TypedBinding<SubItem, string>
-->
<Label Text="Incorrect binding, an incorrect DataType:" />
<CollectionView ItemsSource="{Binding Items}" HeightRequest="100">
    <CollectionView.ItemTemplate>
        <DataTemplate x:DataType="local:SubItem">
            <Label Text="{Binding Name}" />
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

This one feels more actionable somehow because of a missing DataType, the inner layer is using the outer type. In this case, the ItemsSource is always (maybe) going to change the binding context of the items. Should there be a way to say that we are using a DataType on an outer layer, so "reset" the type for the inner CV?

<!--
    This results in an incorrect UI because there is no DataType on the
    DataTemplate and XamlC falls back to the DataType on the one above.
    The generated TypedBinding is using the incorrect types:
         TypedBinding<CollectionItem, string>
-->
<Label Text="Incorrect nested binding, parent DataType:" />
<CollectionView ItemsSource="{Binding Items}" HeightRequest="100">
    <CollectionView.ItemTemplate>
        <DataTemplate x:DataType="local:CollectionItem">
            <CollectionView ItemsSource="{Binding SubItems}" HeightRequest="100">
                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <Label Text="{Binding Name}" />
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

This is probably a user error, but I have seen it happen a lot in samples. The DataType attribute is on the ItemTemplate property... shomehow... so should this be a XAMLC error as there is no way to do this in reality?

<!--
    This results in an incorrect UI because the DataType is not on the 
    DataTemplate so is ignored.
    The generated TypedBinding is using the incorrect types:
         TypedBinding<CollectionItem, string>
-->
<Label Text="Incorrect nested binding, parent DataType:" />
<CollectionView ItemsSource="{Binding Items}" HeightRequest="100">
    <CollectionView.ItemTemplate>
        <DataTemplate x:DataType="local:CollectionItem">
            <CollectionView ItemsSource="{Binding SubItems}" HeightRequest="100">
                <CollectionView.ItemTemplate x:DataType="local:SubItem">
                    <DataTemplate>
                        <Label Text="{Binding Name}" />
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

@mattleibow I created this PR that will warn if there's a Binding that inherits the x:DataType from outside of its DataTemplate scope: #22803 Would that resolve this issue?