unoplatform / uno

Build Mobile, Desktop and WebAssembly apps with C# and XAML. Today. Open source and professionally supported.
https://platform.uno
Apache License 2.0
8.51k stars 690 forks source link

Style setter does not support `Binding` #4826

Closed MartinZikmund closed 4 weeks ago

MartinZikmund commented 3 years ago

Current behavior

When Binding is used in Style Setter, Uno targets don't compile.

Expected behavior

Should compile.

TabView button style uses this approach, so it would be a useful addition.

How to reproduce it (as minimally and precisely as possible)

<Page.Resources>
   <SolidColorBrush x:Key="TestBrush">Red</SolidColorBrush>
   <Style TargetType="TextBlock">
      <Setter Property="Foreground" Value="{Binding Source={ThemeResource TestBrush}}" />
   </Style>
</Page.Resources>
<Grid>
   <TextBlock Text="Test" />
</Grid>

Run the app on Windows and notice the text is red.

Try to compile under Uno and notice build fails with error CS1024: Preprocessor directive expected

The error is also in the generated g.cs file, similar to the following:

new global::Windows.UI.Xaml.Setter(global::Windows.UI.Xaml.Controls.TextBlock.ForegroundProperty, 
__ResourceOwner_278, __ResourceOwner_279 => (Windows.UI.Xaml.SolidColorBrush)
                        #Error // Binding could not be found.
)

Workaround

Avoid use of Binding in style setter

Environment

Nuget Package:

Nuget Package Version(s):

Affected platform(s):

IDE:

Relevant plugins:

Anything else we need to know?

MartinZikmund commented 3 years ago

When fixed, revert Uno specific TODOs in both TabView.xaml files

davidjohnoliver commented 3 years ago

Strange that TabView is using this - I was under the impression it wasn't supported on UWP? https://stackoverflow.com/questions/33573929/uwp-binding-in-style-setter-not-working

Stack Overflow
UWP Binding in Style Setter not working
I have problem with creating xaml control. I'm writing new project in VS 2015 in universal app. I want create grid. In this grid I want to have a button. In model I specifi the column (Level) and R...
MartinZikmund commented 3 years ago

@davidjohnoliver They are using it this way:

<contract7Present:Setter Property="CornerRadius" Value="{Binding Source={ThemeResource OverlayCornerRadius}, Converter={StaticResource TopCornerRadiusFilterConverter}}"/>

So maybe this use-case is supported - to utilize {Binding} for the purposes of a value converter applied on a resource

davidjohnoliver commented 3 years ago

Ahhhh...... yeah, maybe it works in the particular case that a Source is specified (and it's a resource)

jeromelaban commented 3 years ago

We'll probably have to make a special case for those. it's probably excluded explicitly in the generator for setters.

davidjohnoliver commented 2 years ago

This probably could be supported using SetterExtensions.ApplyThemeResourceUpdateValues(), similar to as is done when the value is directly set to a ThemeResource:

https://github.com/unoplatform/uno/blob/55101581bdd4b2faccab84d7a52fc1b548fc8cb5/src/SourceGenerators/Uno.UI.SourceGenerators/XamlGenerator/XamlFileGenerator.cs#L1592-L1595

MartinZikmund commented 10 months ago

Ensure the fix also supports the following scenario:

SetterConvertedBug.zip

Given VS 2019, create new UNO solution, leave only 3 projects: Shared, UWP and Wasm Add some value converter:

    public class SomeConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            return (parameter ?? "").ToString();
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }

Use it in MainPage.xaml:

<Page
    x:Class="SetterConvertedBug.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:SetterConvertedBug"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Page.Resources>
        <local:SomeConverter x:Key="SomeConverter"/>
    </Page.Resources>

    <Grid>
        <TextBlock>
            <TextBlock.Resources>
                <Style TargetType="TextBlock">
                    <Setter Property="Text">
                        <Setter.Value>
                            <Binding Path="Whatever" Converter="{StaticResource SomeConverter}"/>
                        </Setter.Value>
                    </Setter>
                </Style>
            </TextBlock.Resources>
        </TextBlock>
    </Grid>
</Page>

Build. UWP build is OK, Wasm build fails with error at Uno.UI.SourceGenerators.XamlGenerator.XamlFileGenerator.BuildBindingOption(XamlMemberDefinition m, INamedTypeSymbol propertyType) в C:\a\1\s\src\SourceGenerators\Uno.UI.SourceGenerators\XamlGenerator\XamlFileGenerator.cs:line 5023

The same happens for inline binding declaration like
<Setter Property="Text" Value="{Binding Path=Whatever, Converter={StaticResource SomeConverter}}"/> with and without converter parameter.

Youssef1313 commented 1 month ago

Possible fixed with https://github.com/unoplatform/uno/pull/16010 ? Not sure

agneszitte commented 1 month ago

Possible fixed with #16010 ? Not sure

@MartinZikmund, maybe @morning4coffe-dev can help validate if it is already fixed or not

morning4coffe-dev commented 4 weeks ago

@MartinZikmund, @agneszitte, Tested on Skia, wasm, and Android with Uno 5.3.0-dev.1282 - all platforms now have the same behavior as WinUI for both scenarios. For the first one, I can see a red ‘Test’ text, and for the second one, although I see a blank page, it is the same behavior for me as on WinUI and it no longer results in any error.