FluentAvalonia icon indicating copy to clipboard operation
FluentAvalonia copied to clipboard

List Item blue dot trail from selection indicator

Open emmauss opened this issue 2 years ago • 4 comments

Describe the bug When changing the selected item in a listbox, tiny blue dots remain at the position the selection indicator was.

Screenshots image

Desktop/Platform (please complete the following information):

  • OS: Windows 11
  • FluentAvalonia Version 1.3.1
  • Avalonia Version 0.10.13

Additional context

emmauss avatar Mar 17 '22 20:03 emmauss

It's either a Skia anti-aliasing thing or a deferred renderer dirty rect thing (or both). I'm waiting for the new renderer to see if the improvements in that fix it before I try to see if there's anything I can do.

I've already tried adding a margin to make it not sit against the edge of the LBI, but it didn't help: https://github.com/amwx/FluentAvalonia/blob/01dfeb05de3e8d0ddea482b5601727cf44d55493/FluentAvalonia/Styling/BasicControls/ListBoxStyles.axaml#L78-L87

amwx avatar Mar 17 '22 22:03 amwx

This one looks interesting. I don't think the problem is with the dirty rect at first look.

  1. It looks like there are actually 4 rendering artifacts (marked in red) that shouldn't be there at all. Since they shouldn't be there anyway that portion of the view is never invalidated to re-render so the artifacts remain.

    image

  2. Additionally, is the selection pill supposed to be rendered outside the width of the ListBoxItem? I don't have Windows 11 at the moment but all the selection pills I have seen are left aligned with the grey background of the ListBoxItem. This selection pill is horizontally centered on the left edge of the grey background itself so half of it sticks out past the edge.

Waiting for the new renderer is probably smart here.

robloo avatar Mar 26 '22 00:03 robloo

  1. Additionally, is the selection pill supposed to be rendered outside the width of the ListBoxItem?

No. It should be aligned with the left edge of pointer background. The template for ListViewItem is a bit of a special case - since the actual style uses the ListViewItemPresenter for whatever reason MS does this, but they didn't add that template to the xaml file. The "expanded" style they did include (which essentially unwraps the presenter) doesn't include the selection indicator, so I had to manually do that. To fix, the Margin on the selection indicator needs to be {2,0,0,0}, but I just tried that and the artifacts got even worse - so it needs to wait.

I believe this artifact issue is related to why we don't want anti-aliasing rounded rect clipping on Skia. It isn't just the selection indicator here doing it, I have it happening elsewhere too (outside this library) where it's even worse. Remove the corner radius, and it disappears. So you're right, it's not dirty rects - it's Skia (or SkiaSharp) being bad.

amwx avatar Mar 26 '22 02:03 amwx

I believe this artifact issue is related to why we don't want anti-aliasing rounded rect clipping on Skia.

Yes, you're very likely correct. Hopefully an update to SkiaSharp is released sometime soon. Everyone has been waiting on it for what seems like a year now. Maui is almost done so I hope development picks up again.

Also, just for reference, here is a WinUI 2 style for the selection pill indicator of a ListViewItem. This was based on the ComboBoxItem style since, as you said, Microsoft doesn't currently release what they have in WinUI 3 for this style. It uses the ContentPresenter and seems to work well enough for app needs. Certain things like Padding are app specific but you might find it useful for whatever reason.

Click to Expand Code
<!--
        A customized ListViewItem style that solves the issue of Text Foreground color in child controls.
        Fluent v2 changes the selected item background contrast so much the text Foreground color must be inverted.
        That causes a problem for child controls that set their own text Foreground (like DatePicker).
        This wasn't an issue in Fluent v1 where the background contrast was never so high.
        The fix for this is to use a style heavily derived from ComboBoxItem with the pill indicator and a gray background.
        This style was created with only a few modifications from the DefaultComboBoxItemStyle to make it work for ListViewItem.
    
        See: https://github.com/microsoft/microsoft-ui-xaml/issues/6469
        Source: https://github.com/microsoft/microsoft-ui-xaml/blob/01eea310f89b72109a36de6537e3357fb2421556/dev/ComboBox/ComboBox_themeresources.xaml#L778
    -->
    <Style
        TargetType="ListViewItem"
        x:Key="PillListViewItemStyle">
        <Setter
            Property="Foreground"
            Value="{ThemeResource ComboBoxItemForeground}" />
        <Setter
            Property="Background"
            Value="{ThemeResource ComboBoxItemBackground}" />
        <Setter
            Property="Padding"
            Value="12,3,12,3" />
        <Setter
            Property="HorizontalContentAlignment"
            Value="Stretch" />
        <Setter
            Property="VerticalContentAlignment"
            Value="Stretch" />
        <Setter
            Property="UseSystemFocusVisuals"
            Value="True" />
        <Setter
            Property="FocusVisualMargin"
            Value="-3" />
        <Setter
            Property="CornerRadius"
            Value="{StaticResource ComboBoxItemCornerRadius}" />
        <Setter
            Property="Template">
            <Setter.Value>
                <ControlTemplate
                    TargetType="ListViewItem">
                    <Grid
                        x:Name="LayoutRoot"
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        CornerRadius="{TemplateBinding CornerRadius}"
                        Control.IsTemplateFocusTarget="True">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup
                                x:Name="CommonStates">
                                <VisualState
                                    x:Name="Normal" />
                                <VisualState
                                    x:Name="PointerOver">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames
                                            Storyboard.TargetName="LayoutRoot"
                                            Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame
                                                KeyTime="0"
                                                Value="{ThemeResource ComboBoxItemBackgroundPointerOver}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames
                                            Storyboard.TargetName="LayoutRoot"
                                            Storyboard.TargetProperty="BorderBrush">
                                            <DiscreteObjectKeyFrame
                                                KeyTime="0"
                                                Value="{ThemeResource ComboBoxItemBorderBrushPointerOver}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames
                                            Storyboard.TargetName="ContentPresenter"
                                            Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame
                                                KeyTime="0"
                                                Value="{ThemeResource ComboBoxItemForegroundPointerOver}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState
                                    x:Name="Disabled">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames
                                            Storyboard.TargetName="LayoutRoot"
                                            Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame
                                                KeyTime="0"
                                                Value="{ThemeResource ComboBoxItemBackgroundDisabled}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames
                                            Storyboard.TargetName="LayoutRoot"
                                            Storyboard.TargetProperty="BorderBrush">
                                            <DiscreteObjectKeyFrame
                                                KeyTime="0"
                                                Value="{ThemeResource ComboBoxItemBorderBrushDisabled}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames
                                            Storyboard.TargetName="ContentPresenter"
                                            Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame
                                                KeyTime="0"
                                                Value="{ThemeResource ComboBoxItemForegroundDisabled}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState
                                    x:Name="Pressed">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames
                                            Storyboard.TargetName="LayoutRoot"
                                            Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame
                                                KeyTime="0"
                                                Value="{ThemeResource ComboBoxItemBackgroundPressed}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames
                                            Storyboard.TargetName="LayoutRoot"
                                            Storyboard.TargetProperty="BorderBrush">
                                            <DiscreteObjectKeyFrame
                                                KeyTime="0"
                                                Value="{ThemeResource ComboBoxItemBorderBrushPressed}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames
                                            Storyboard.TargetName="ContentPresenter"
                                            Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame
                                                KeyTime="0"
                                                Value="{ThemeResource ComboBoxItemForegroundPressed}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState
                                    x:Name="Selected">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames
                                            Storyboard.TargetName="Pill"
                                            Storyboard.TargetProperty="Opacity">
                                            <DiscreteObjectKeyFrame
                                                KeyTime="0"
                                                Value="1" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames
                                            Storyboard.TargetName="LayoutRoot"
                                            Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame
                                                KeyTime="0"
                                                Value="{ThemeResource ComboBoxItemBackgroundSelected}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames
                                            Storyboard.TargetName="LayoutRoot"
                                            Storyboard.TargetProperty="BorderBrush">
                                            <DiscreteObjectKeyFrame
                                                KeyTime="0"
                                                Value="{ThemeResource ComboBoxItemBorderBrushSelected}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames
                                            Storyboard.TargetName="ContentPresenter"
                                            Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame
                                                KeyTime="0"
                                                Value="{ThemeResource ComboBoxItemForegroundSelected}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState
                                    x:Name="PointerOverSelected">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames
                                            Storyboard.TargetName="Pill"
                                            Storyboard.TargetProperty="Opacity">
                                            <DiscreteObjectKeyFrame
                                                KeyTime="0"
                                                Value="1" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames
                                            Storyboard.TargetName="LayoutRoot"
                                            Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame
                                                KeyTime="0"
                                                Value="{ThemeResource ComboBoxItemBackgroundSelectedPointerOver}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames
                                            Storyboard.TargetName="LayoutRoot"
                                            Storyboard.TargetProperty="BorderBrush">
                                            <DiscreteObjectKeyFrame
                                                KeyTime="0"
                                                Value="{ThemeResource ComboBoxItemBorderBrushSelectedPointerOver}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames
                                            Storyboard.TargetName="ContentPresenter"
                                            Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame
                                                KeyTime="0"
                                                Value="{ThemeResource ComboBoxItemForegroundSelectedPointerOver}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState
                                    x:Name="PressedSelected">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames
                                            Storyboard.TargetName="Pill"
                                            Storyboard.TargetProperty="Opacity">
                                            <DiscreteObjectKeyFrame
                                                KeyTime="0"
                                                Value="1" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <DoubleAnimationUsingKeyFrames
                                            Storyboard.TargetName="PillTransform"
                                            Storyboard.TargetProperty="ScaleY">
                                            <SplineDoubleKeyFrame
                                                KeyTime="{StaticResource ComboBoxItemScaleAnimationDuration}"
                                                Value="{StaticResource ComboBoxItemPillMinScale}"
                                                KeySpline="0,0,0,1" />
                                        </DoubleAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames
                                            Storyboard.TargetName="LayoutRoot"
                                            Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame
                                                KeyTime="0"
                                                Value="{ThemeResource ComboBoxItemBackgroundSelectedPressed}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames
                                            Storyboard.TargetName="LayoutRoot"
                                            Storyboard.TargetProperty="BorderBrush">
                                            <DiscreteObjectKeyFrame
                                                KeyTime="0"
                                                Value="{ThemeResource ComboBoxItemBorderBrushSelectedPressed}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames
                                            Storyboard.TargetName="ContentPresenter"
                                            Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame
                                                KeyTime="0"
                                                Value="{ThemeResource ComboBoxItemForegroundSelectedPressed}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>

                        <Rectangle
                            x:Name="Pill"
                            Style="{StaticResource ListViewItemPill}"
                            Opacity="0"
                            RenderTransformOrigin="0.5,0.5">
                            <Rectangle.RenderTransform>
                                <CompositeTransform
                                    x:Name="PillTransform"
                                    ScaleY="1" />
                            </Rectangle.RenderTransform>
                        </Rectangle>

                        <ContentPresenter
                            x:Name="ContentPresenter"
                            Content="{TemplateBinding Content}"
                            ContentTransitions="{TemplateBinding ContentTransitions}"
                            ContentTemplate="{TemplateBinding ContentTemplate}"
                            Foreground="{TemplateBinding Foreground}"
                            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                            VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                            Margin="{TemplateBinding Padding}" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!-- BasedOn Source: https://github.com/microsoft/microsoft-ui-xaml/blob/01eea310f89b72109a36de6537e3357fb2421556/dev/ComboBox/ComboBox_themeresources.xaml#L372 -->
    <Style
        x:Key="ListViewItemPill"
        TargetType="Rectangle">
        <Setter
            Property="HorizontalAlignment"
            Value="Left" />
        <Setter
            Property="VerticalAlignment"
            Value="Center" />
        <Setter
            Property="Height"
            Value="32" />
        <Setter
            Property="Width"
            Value="3" />
        <Setter
            Property="Fill"
            Value="{ThemeResource ComboBoxItemPillFillBrush}" />
        <Setter
            Property="RadiusX"
            Value="1.5" />
        <Setter
            Property="RadiusY"
            Value="1.5" />
    </Style>

robloo avatar Mar 26 '22 03:03 robloo