Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Setter Target Property #11537

Open
workgroupengineering opened this issue May 26, 2023 · 9 comments
Open

Add Setter Target Property #11537

workgroupengineering opened this issue May 26, 2023 · 9 comments
Milestone

Comments

@workgroupengineering
Copy link
Contributor

Is your feature request related to a problem? Please describe.
Change the ownership of another element when the selector is activated.

Describe the solution you'd like
Considering following Xaml

    <StackPanel>
        <CheckBox x:Name="Choiche1" Content="Quatsion ?"/>
        <TextBox x:Name="Input"/>
        <ComboBox x:Name="List"/>
     </StackPanel>

I'd like to write selector like this:

    <Style Selector="CheckBox#Choiche1[IsChecked=False]">
      <Setter Target="Input" Property="IsEnabale" Value="False"/>
      <Setter Target="List" Property="IsEnabale" Value="True"/>
    </Style>
    <Style Selector="CheckBox#Choiche1[IsChecked=True]">
      <Setter Property="Backgroud" Value="Green"/>
      <Setter Target="Input" Property="IsEnabale" Value="True"/>
      <Setter Target="List" Property="IsEnabale" Value="False"/>
    </Style>

Describe alternatives you've considered
I know, I can do a similar thing with binding. But the advantage of the proposed solution is to have everything centralized.

Additional context
WPF Setter.TargetName
UWP Setter.Target

@robloo
Copy link
Contributor

robloo commented May 27, 2023

This has come up a few times in the past. Surprising, I can't seem to find an existing issue for it so it must have been in comments some place.

This is a key simplification of UWP/WinUI XAML I definitely think Avalonia needs. I have also seen several places it will simplify things.

Also note that I would prefer the UWP/WinUI implementation which allows a path (Parent.Child) instead of simply an element name.

@maxkatz6
Copy link
Member

A long time ago I was also asking if we should add this as a feature.

Nowadays, it feels less useful, especially with 11.0.

A typical use case would be with the ControlTemplate, where it's currently nicely handled with nested styles.

But @workgroupengineering example is different - it's about styling controls depending on their siblings.
We do not currently handle this use case in an easy way.

If we continue following CSS here, they have two siblings selectors General sibling combinator and Adjacent sibling combinator. Both kinda solve this problem, but not completely. Because even with "general sibling combinator" you can only affect the following elements, but not previous elements. In my opinion, these are quite useless selectors.

"Has" selector, on the other hand, is very powerful and would solve this scenario easily as well. Something like StackPanel:has(CheckBox#Choiche1:unchecked).
It feels like we would end up implementing ":has" selector anyway at some point, as there was a demand for this as well.

Performance of this selector is a possible problem, though.

@amwx
Copy link
Contributor

amwx commented May 28, 2023

A long time ago I was also asking if we should add this as a feature.

Nowadays, it feels less useful, especially with 11.0.

I disagree. For the most part, yes, nested styles helped out here a lot but Selectors are still kinda verbose

<Style Selector="^:pointerover">
    <Style Selector="^ /template/ ContentPresenter#ContentPresenter">
        <Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundUncheckedPointerOver}" />
    </Style>
    <Style Selector="^ /template/ Border#Root">
        <Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundUncheckedPointerOver}" />
        <Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushUncheckedPointerOver}" />
    </Style>
    <Style Selector="^ /template/ Border#NormalRectangle">
        <Setter Property="Background" Value="{DynamicResource CheckBoxCheckBackgroundFillUncheckedPointerOver}"/>
        <Setter Property="BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeUncheckedPointerOver}" />
    </Style>
    <Style Selector="^ /template/ ui|FontIcon#CheckGlyph">
        <Setter Property="Foreground" Value="{DynamicResource CheckBoxCheckGlyphForegroundUncheckedPointerOver}"/>
    </Style>
</Style>

This example from CheckBox could be condensed down to (following UWP's Target)

<Style Selector="^:pointerover">
    <Setter Target="ContentPresenter.Foreground" Value="{DynamicResource CheckBoxForegroundUncheckedPointerOver}" />
    <Setter Target="Root.Background" Value="{DynamicResource CheckBoxBackgroundUncheckedPointerOver}" />
    <Setter Target="Root.BorderBrush" Value="{DynamicResource CheckBoxBorderBrushUncheckedPointerOver}" />
    <Setter Target="NormalRectangle.Background" Value="{DynamicResource CheckBoxCheckBackgroundFillUncheckedPointerOver}"/>
    <Setter Target="NormalRectangle.BorderBrush" Value="{DynamicResource CheckBoxCheckBackgroundStrokeUncheckedPointerOver}" />
    <Setter Target="CheckGlyph.Foreground" Value="{DynamicResource CheckBoxCheckGlyphForegroundUncheckedPointerOver}"/>
</Style>

@maxkatz6
Copy link
Member

Another possible use case - animations. Inspired by #11905.

<Animation Duration="00:00:01">
    <KeyFrame>
        <Setter Target='SizingGrid.Height' Value='1200' />
        <Setter Target='SizingGrid.Width' Value='800' />
        <Setter Target="MainCanvas.Opacity" To="0.4"/>
        <Setter Target="MainLogo.Opacity" To="0.8"/>
        <Setter Target="MainCanvas.Margin" To="0,0,14,14"/>
        <Setter Target="TitleBox.Margin" To="0,2,48,0"/>
    </KeyFrame>
</Animation>

@maxkatz6
Copy link
Member

Or, alternatively, if we step from UWP/WPF syntax, but probably make it less confusing (for a new users at least, definitely not WPF/UWP users):

<Animation Duration="00:00:01">
    <KeyFrame>
        <Setter Target='SizingGrid' Property='Height' Value='1200' />
        <Setter Target='SizingGrid' Property='Width' Value='800' />
        <Setter Target="MainCanvas' Property='Opacity" To="0.4"/>
        <Setter Target="MainLogo' Property='Opacity" To="0.8"/>
        <Setter Target="MainCanvas' Property='Margin" To="0,0,14,14"/>
        <Setter Target="TitleBox' Property='Margin" To="0,2,48,0"/>
    </KeyFrame>
</Animation>

Where if Target is null, animation assumes style target as an animation target.

@maxkatz6
Copy link
Member

Where Animation.RunAsync(Animatable control, CancellationToken cancellationToken) needs to be adjusted to Animation.RunAsync(Animatable defaultTarget, CancellationToken cancellationToken) (or better).

cc @jmacato @kekekeks

@jmacato
Copy link
Member

jmacato commented Jun 27, 2023

Yes I like this solution since it will also simplify setters in styles

@maxkatz6 maxkatz6 added this to the 11.x milestone Jun 29, 2023
@maxkatz6
Copy link
Member

maxkatz6 commented Nov 7, 2023

Note, WPF has TargetName property, which might work better for our needs.
See:

<Animation Duration="00:00:01">
    <KeyFrame>
        <Setter TargetName='SizingGrid' Property='Height' Value='1200' />
        <Setter TargetName='SizingGrid' Property='Width' Value='800' />
        <Setter TargetName="MainCanvas' Property='Opacity" To="0.4"/>
        <Setter TargetName="MainLogo' Property='Opacity" To="0.8"/>
        <Setter TargetName="MainCanvas' Property='Margin" To="0,0,14,14"/>
        <Setter TargetName="TitleBox' Property='Margin" To="0,2,48,0"/>
    </KeyFrame>
</Animation>

@robloo
Copy link
Contributor

robloo commented Nov 7, 2023

@maxkatz6 Yes, I believe Target vs TargetName was discussed above and noted in the original issue. Did I miss something at the link below?

#11537 (comment)

Target is more powerful and preferred from my viewpoint.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants