ControlTemplate 中嵌套的 ScrollViewer ScrollChanged

Nested ScrollViewer ScrollChanged in ControlTemplate

我有一个 ScrollViewerControlTemplate 绑定(工作正常),里面有一个 Grid(覆盖默认 ScrollViewer 并设置 ScrollBars 在内容“上方”,最后我有一些 EventTriggers 将 ScrollBar 的不透明度设置为 1 或 0 Storyboard。它们也很好用。

我缺少的是在发生滚动时将 Opacity 设置为 1 的触发器之一。它可以通过鼠标、鼠标滚轮、手写笔或触摸来滚动,所以最好使用 ScrollViewerScrollChangedScrollBar 本身的 Scroll。但我无法让它发挥作用。哦,顺便说一句。我无法改变它的构建方式。所以我必须通过 ControlTemplate 中的纯 XAML 来实现它(我自己知道如何使用后面的代码来实现它,但这在这里是不可能的)。

样式看起来是这样的:

<Style TargetType="{x:Type controls:ViewerControl}">
    // ... some properties of no interest here
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type controls:ViewerControl}">
                <Border Grid.Row="0" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                    <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Name="PART_ScrollViewer">
                        <ScrollViewer.Template>
                            <ControlTemplate TargetType="{x:Type ScrollViewer}">
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="*" />
                                        <ColumnDefinition Width="Auto" />
                                    </Grid.ColumnDefinitions>
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="*"/>
                                        <RowDefinition Height="Auto"/>
                                    </Grid.RowDefinitions>
                                    <Grid.Triggers>
                                        <EventTrigger RoutedEvent="Grid.Loaded">
                                            <BeginStoryboard>
                                                <Storyboard>
                                                    <DoubleAnimation Duration="00:00:02" From="1" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_VerticalScrollBar"/>
                                                    <DoubleAnimation Duration="00:00:02" From="1" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_HorizontalScrollBar"/>
                                                </Storyboard>
                                            </BeginStoryboard>
                                        </EventTrigger>
                                        <EventTrigger RoutedEvent="Grid.MouseEnter">
                                            <BeginStoryboard>
                                                <Storyboard>
                                                    <DoubleAnimation Duration="0" From="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_VerticalScrollBar"/>
                                                    <DoubleAnimation Duration="0" From="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_HorizontalScrollBar"/>
                                                </Storyboard>
                                            </BeginStoryboard>
                                        </EventTrigger>
                                        <EventTrigger RoutedEvent="Grid.MouseLeave">
                                            <BeginStoryboard>
                                                <Storyboard>
                                                    <DoubleAnimation Duration="00:00:02" From="1" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_VerticalScrollBar"/>
                                                    <DoubleAnimation Duration="00:00:02" From="1" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_HorizontalScrollBar"/>
                                                </Storyboard>
                                            </BeginStoryboard>
                                        </EventTrigger>
                                    </Grid.Triggers>
                                    <ScrollContentPresenter Grid.ColumnSpan="2"
                                                            Grid.RowSpan="2"
                                                            ContentTemplate="{TemplateBinding ContentTemplate}"
                                                            Content="{TemplateBinding Content}"/>
                                    <ScrollBar Name="PART_VerticalScrollBar"
                                               HorizontalAlignment="Right"
                                               Opacity="0"
                                               Grid.Column="1"
                                               IsTabStop="False"
                                               Value="{TemplateBinding VerticalOffset}"
                                               Maximum="{TemplateBinding ScrollableHeight}"
                                               ViewportSize="{TemplateBinding ViewportHeight}"
                                               Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"/>
                                    <ScrollBar Name="PART_HorizontalScrollBar"
                                               VerticalAlignment="Bottom"
                                               Orientation="Horizontal"
                                               Opacity="0"
                                               Grid.Row="1"
                                               IsTabStop="False"
                                               Value="{TemplateBinding HorizontalOffset}"
                                               Maximum="{TemplateBinding ScrollableWidth}"
                                               ViewportSize="{TemplateBinding ViewportWidth}"
                                               Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"/>
                                </Grid>
                            </ControlTemplate>
                        </ScrollViewer.Template>
                        <StackPanel IsItemsHost="True" Name="PART_ItemsHost" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                    </ScrollViewer>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

我试过这样的东西:

<ScrollViewer.Triggers>
    <EventTrigger RoutedEvent="ScrollViewer.ScrollChanged">
        <BeginStoryboard>
            <Storyboard>
                <DoubleAnimation Duration="0" From="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_VerticalScrollBar"/>
                <DoubleAnimation Duration="0" From="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_HorizontalScrollBar"/>
            </Storyboard>
        </BeginStoryboard>
    </EventTrigger>
</ScrollViewer.Triggers>

但是如果我把它直接放在 ScrollViewer 里面它找不到 ScrollBars 而如果我把它放在 Grid 里面它会被完全忽略(Grid 本身无法控制 ScrollViewer 并且似乎不会把它冒出来。

我在有人使用 VisualStateManager 的地方找到了答案,但这似乎只适用于 Silverlight,不适用于 C#。它看起来像这样:

<VisualStateManager.VisualStateGroups>
    <VisualStateGroup x:Name="ScrollStates">
        <VisualStateGroup.Transitions>
            <VisualTransition GeneratedDuration="00:00:00.5"/>
        </VisualStateGroup.Transitions>
        <VisualState x:Name="Scrolling">
            <Storyboard>
                <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_VerticalScrollBar"/>
                <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_HorizontalScrollBar"/>
            </Storyboard>
        </VisualState>
        <VisualState x:Name="NotScrolling"/>
    </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

有人知道如何进行这项工作吗?

我的一个同事找到了答案:

<ControlTemplate.Triggers>
    <EventTrigger RoutedEvent="ScrollViewer.ScrollChanged">
        <BeginStoryboard>
            <Storyboard>
                <DoubleAnimation Duration="0" From="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_VerticalScrollBar"/>
                <DoubleAnimation Duration="0" From="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_HorizontalScrollBar"/>
                <DoubleAnimation BeginTime="00:00:02" Duration="00:00:01.5" From="1" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_VerticalScrollBar"/>
                <DoubleAnimation BeginTime="00:00:02" Duration="00:00:01.5" From="1" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_HorizontalScrollBar"/>
            </Storyboard>
        </BeginStoryboard>
    </EventTrigger>
</ControlTemplate.Triggers>

因此,如果您将 EventTrigger 放在 ControlTemplate.Triggers 中,它就像一个魅力...真的很酷。您只需要将这些 MouseEnterMouseLeave 放在 ScrollBar 中,否则如果光标进入 ScrollViewer 的内容,它们也会被触发,而不仅仅是进入ScrollBars.