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.98k stars 1.71k forks source link

Behavior bindable property with DynamicResource not supported? #23578

Open mattleibow opened 1 month ago

mattleibow commented 1 month ago

Discussed in https://github.com/dotnet/maui/discussions/13691

Originally posted by **Cybrosys** March 4, 2023 Hi, I raised this Q&A and also a bug in the MCT repo: https://github.com/CommunityToolkit/Maui/discussions/1054 It is a question related to doing a `DynamicResource ` binding against a bindable property on the `StatusBarBehaior`, if it is supported or a bug. If it is a bug I think it belongs here in the main MAUI repo. Here is a link to the bug in the MCT Repo: https://github.com/CommunityToolkit/Maui/issues/1056 So, is this a bug in the MAUI repo or a limitation? For me as a developer and consumer, since the XAML does not show any error I would expect and assume that I would be able to use a `DynamicResource` binding for the `StatusBarBehavior`'s `StatusBarColor` bindable property. I also expressed in one of my comments that if I wanted to start investigating this, where would I start? I do not know who would own the `DynamicResource` binding. When doing a normal `Bind` I would expect it to be owned by the UI element itself, targeting a defined `BindingContext`. However, `DynamicResource` bindings seem a bit more "magical" in that they work without a `BindingContext` being defined/assigned. There are several issues currently related to `DynamicResource` bindings not working in .NET 7 but in .NET 6. So I do not know if this problem is related to `Behavor`s specifically or a core issue with `DynamicResource`. **Update** I got information here https://github.com/CommunityToolkit/Maui/issues/1056 that it can't use `DynamicResource` because it does not inherit from [VisualElement](https://github.com/dotnet/maui/blob/main/src/Controls/src/Core/VisualElement.cs#L770) or implement [IResourcesProvider](https://github.com/dotnet/maui/blob/main/src/Controls/src/Core/IResourcesProvider.cs). I would argue that you should be able to use `DynamicResource` even when not inheriting from `VisualElement`. The reason being that you can put any type of value into a `ResourceDictionary`, so in essence it is just a normal binding where the source is the parent or app's `ResourceDictionary`.
github-actions[bot] commented 1 month ago

Hi I'm an AI powered bot that finds similar issues based off the issue title.

Please view the issues below to see if they solve your problem, and if the issue describes your problem please consider closing this one and thumbs upping the other issue to help us prioritize it. Thank you!

Closed similar issues:

Note: You can give me feedback by thumbs upping or thumbs downing this comment.

mattleibow commented 1 month ago

@mikeparker104 do you have a repro?

mattleibow commented 1 month ago

This may be a workaround:


public static class IconTintColor
{
    public static readonly BindableProperty TintColorProperty =
        BindableProperty.CreateAttached("TintColor", typeof(Color), typeof(IconTintColor), default,
            propertyChanged: OnTintColorChanged);

    private static void OnTintColorChanged(BindableObject bindable, object oldValue, object newValue)
    {
        if (bindable is not View view)
            return;

        if (view.Behaviors.OfType<IconTintColorBehavior>().FirstOrDefault() is { } existing)
        {
            existing.TintColor = (Color)newValue;
        }
        else
        {
            var behavior = new IconTintColorBehavior
            {
                TintColor = (Color)newValue
            };
            view.Behaviors.Add(behavior);
        }

    }

    public static Thickness GetTintColor(BindableObject view)
    {
        return (Thickness)view.GetValue(TintColorProperty);
    }

    public static void SetTintColor (BindableObject view, bool value)
    {
        view.SetValue(TintColorProperty, value);
    }
}

Used like:

<Image
    Source="dotnet_bot.png"
    HeightRequest="185"
    Aspect="AspectFit"
    SemanticProperties.Description="dot net bot in a race car number eight"
    local:IconTintColor.TintColor="{DynamicResource TargetColor}">
    <!-- <Image.Behaviors>
        <toolkit:IconTintColorBehavior TintColor="{DynamicResource TargetColor}" />
    </Image.Behaviors> -->
</Image>
mikeparker104 commented 1 month ago

@mikeparker104 do you have a repro?

@mattleibow adding repro: https://github.com/mikeparker104/repro_23578