dotnet / MobileBlazorBindings

Experimental Mobile Blazor Bindings - Build native and hybrid mobile apps with Blazor
MIT License
1.21k stars 172 forks source link

Alternative approach to attached properties using CaptureUnmatchedValues #438

Open Dreamescaper opened 2 years ago

Dreamescaper commented 2 years ago

Since Blazor does not support attached properties natively (see https://github.com/dotnet/aspnetcore/issues/20715, https://github.com/dotnet/aspnetcore/issues/5607, https://github.com/dotnet/aspnetcore/issues/22316), we have to emulate them somehow. Currently we use the approach with separate Blazor components - either parent (e.g. GridCell) or child (e.g. ShellProperties). However, sometimes it is quite cumbersome and doesn't feel natural.

I have an alternative suggestion.

Create some AttachedPropertyRegistry class, which would allow to register actions for certain attached properties, and register them in corresponding element's static constructor. E.g. for Grid it would look smth like that:

            AttachedPropertyRegistry.RegisterAttachedPropertyHandler("Grid.Row",
                (element, value) => GridLayout.SetRow(element, Convert.ToInt32(value, CultureInfo.InvariantCulture)));

Add property to Element, which would capture all unmatched values:

        [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object> AdditionalProperties { get; set; }

And in ElementHandler try to retrieve and execute action from AttachedPropertyRegistry for all unmatched values.

This approach would allow to use syntax, very close to what is used in XAML:

<Grid ColumnDefinitions="*,*,*" RowDefinitions="*,*,*">
    <Label Grid.Row="0" Grid.Column="0" Text="1" />
    <Label Grid.Row="1" Grid.Column="1" Text="2" />
    <Label Grid.Row="2" Grid.Column="2" Text="3" />
</Grid>

Of course, this approach is not perfect either. Because this property is a simple Dictionary, there would be no IntelliSense suggestions or compile time validations. Besides, we probably won't be able to handle complex properties this way, like

<ContentPage ...>    
    <Shell.BackButtonBehavior>
        <BackButtonBehavior Command="{Binding BackCommand}"
                            IconOverride="back.png" />   
    </Shell.BackButtonBehavior>
    ...
</ContentPage>

Any thoughts?