ControlTemplate 中嵌套的 ScrollViewer ScrollChanged
Nested ScrollViewer ScrollChanged in ControlTemplate
我有一个 ScrollViewer
与 ControlTemplate
绑定(工作正常),里面有一个 Grid
(覆盖默认 ScrollViewer
并设置 ScrollBar
s 在内容“上方”,最后我有一些 EventTrigger
s 将 ScrollBar
的不透明度设置为 1 或 0 Storyboard
。它们也很好用。
我缺少的是在发生滚动时将 Opacity
设置为 1 的触发器之一。它可以通过鼠标、鼠标滚轮、手写笔或触摸来滚动,所以最好使用 ScrollViewer
的 ScrollChanged
或 ScrollBar
本身的 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
里面它找不到 ScrollBar
s 而如果我把它放在 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
中,它就像一个魅力...真的很酷。您只需要将这些 MouseEnter
和 MouseLeave
放在 ScrollBar
中,否则如果光标进入 ScrollViewer
的内容,它们也会被触发,而不仅仅是进入ScrollBar
s.
我有一个 ScrollViewer
与 ControlTemplate
绑定(工作正常),里面有一个 Grid
(覆盖默认 ScrollViewer
并设置 ScrollBar
s 在内容“上方”,最后我有一些 EventTrigger
s 将 ScrollBar
的不透明度设置为 1 或 0 Storyboard
。它们也很好用。
我缺少的是在发生滚动时将 Opacity
设置为 1 的触发器之一。它可以通过鼠标、鼠标滚轮、手写笔或触摸来滚动,所以最好使用 ScrollViewer
的 ScrollChanged
或 ScrollBar
本身的 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
里面它找不到 ScrollBar
s 而如果我把它放在 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
中,它就像一个魅力...真的很酷。您只需要将这些 MouseEnter
和 MouseLeave
放在 ScrollBar
中,否则如果光标进入 ScrollViewer
的内容,它们也会被触发,而不仅仅是进入ScrollBar
s.