我有一个ScrollBar的样式。默认情况下,滚动条中的轨迹具有"隐藏可见性"。如果出现以下情况之一,则更改为可见:-鼠标在滚动条上-或者,用户当前正在使用滚轮滚动一旦可见性条件不再满足,如何保持轨迹可见1秒,然后返回"隐藏"?
谢谢!
<ControlTemplate x:Key="VerticalScrollBarTemplate" TargetType="{x:Type ScrollBar}">
<Grid Width="15">
<Border Opacity="0.7"/>
<Track x:Name="PART_Track"
Width="12"
MinHeight="20"
Height="Auto"
Margin="2"
IsDirectionReversed="true" >
<Track.DecreaseRepeatButton>
<RepeatButton Style="{StaticResource ScrollBackgroundStyle}" Command="ScrollBar.LineUpCommand" />
</Track.DecreaseRepeatButton>
<Track.IncreaseRepeatButton>
<RepeatButton Style="{StaticResource ScrollBackgroundStyle}" Command="ScrollBar.LineDownCommand" />
</Track.IncreaseRepeatButton>
<Track.Thumb>
<Thumb Name="Thumb" Visibility="Hidden" Style="{StaticResource ScrollBarThumbStyle}" />
</Track.Thumb>
</Track>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="Thumb" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
我尝试使用:
<Storyboard x:Key="FadeInStoryboard">
<DoubleAnimation Storyboard.TargetName="Thumb"
Storyboard.TargetProperty="Opacity"
From="0" To="1" Duration="0:0:0.5"/>
</Storyboard>
<Storyboard x:Key="FadeOutStoryboard" BeginTime="0:0:1">
<DoubleAnimation Storyboard.TargetName="Thumb"
Storyboard.TargetProperty="Opacity"
From="1" To="0" Duration="0:0:0.5" />
</Storyboard>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="Thumb" Property="Visibility" Value="Visible"/>
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource FadeInStoryboard}" />
</Trigger.EnterActions>
<Trigger.ExitActions><
<BeginStoryboard Storyboard="{StaticResource FadeOutStoryboard}" />
</Trigger.ExitActions>
</Trigger>
但如果没有保留,轨迹将在1秒内可见,然后返回"隐藏",除非我在ScrollBar中设置轨迹默认为"可见性可见"。谢谢
问题是您的Setter
,您将Visibility
设置为Visible
。一旦IsMouseOver
属性的值更改为false,触发器将自动将Visibility
设置回Hidden
。要解决此问题,您必须设置Visibility
属性的动画,并从触发器中删除Setter
。
故事板示例:
<Storyboard x:Key="FadeInStoryboard">
<ObjectAnimationUsingKeyFrames Duration="0:0:0"
Storyboard.TargetName="Thumb"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0%" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Duration="0:0:0.5" From="0"
Storyboard.TargetName="Thumb"
Storyboard.TargetProperty="Opacity" To="1" />
</Storyboard>
<Storyboard x:Key="FadeOutStoryboard" >
<DoubleAnimation Duration="0:0:0.5" From="1" BeginTime="0:0:1"
Storyboard.TargetName="Thumb" Storyboard.TargetProperty="Opacity"
To="0" />
<ObjectAnimationUsingKeyFrames Duration="0:0:1"
Storyboard.TargetName="Thumb"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="100%" Value="{x:Static Visibility.Hidden}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
编辑:这是在使用鼠标滚轮滚动时触发相同行为的一种可能方式。我只是很快创建了这个,所以在使用它之前请检查它,并期望它是健壮的。您必须创建一个新类并从ScrollViewer
:派生它
public class ScrollViewerEx : ScrollViewer {
public static readonly DependencyProperty IsScrollingWithMouseWheelProperty = DependencyProperty.Register(
"IsScrollingWithMouseWheel", typeof (bool), typeof (ScrollViewerEx), new FrameworkPropertyMetadata(false));
public bool IsScrollingWithMouseWheel {
get { return (bool) GetValue(IsScrollingWithMouseWheelProperty); }
set { SetValue(IsScrollingWithMouseWheelProperty, value); }
}
private readonly DispatcherTimer mouseWheelActivityTimer;
public ScrollViewerEx() {
mouseWheelActivityTimer = new DispatcherTimer();
mouseWheelActivityTimer.Interval = TimeSpan.FromSeconds(1);
mouseWheelActivityTimer.Tick += MouseWheelActivityTimerOnTick;
}
private void MouseWheelActivityTimerOnTick(object sender, EventArgs eventArgs) {
mouseWheelActivityTimer.Stop();
IsScrollingWithMouseWheel = false;
}
protected override void OnMouseWheel(MouseWheelEventArgs e) {
mouseWheelActivityTimer.Stop();
IsScrollingWithMouseWheel = true;
mouseWheelActivityTimer.Start();
base.OnMouseWheel(e);
}
}
将以下DataTrigger
添加到ScrollBar
的ControlTemplate
:注意:这会显式停止BeginStoryboard
s,您还需要将StopStoryboard
s添加到ControlTemplate
中现有的Trigger
中,否则最后一个Trigger
将阻塞第一个Trigger
。
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=data:ScrollViewerEx}, Path=IsScrollingWithMouseWheel}"
Value="True">
<DataTrigger.EnterActions>
<StopStoryboard BeginStoryboardName="fadeOut"/>
<BeginStoryboard Storyboard="{StaticResource FadeInStoryboard}" Name="fadeIn"/>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="fadeIn"/>
<BeginStoryboard Storyboard="{StaticResource FadeOutStoryboard}" Name="fadeOut"/>
</DataTrigger.ExitActions>
</DataTrigger>
编辑2:这是另一种方法,使用附加的属性和EventTrigger
。
您必须调整ScrollViewer
的ControlTemplate
以添加以下EventTrigger
:
<EventTrigger RoutedEvent="PreviewMouseWheel">
<BeginStoryboard>
<Storyboard FillBehavior="Stop">
<BooleanAnimationUsingKeyFrames Duration="0:0:1" Storyboard.TargetProperty="(data:ScrollViewerProperties.IsScrollingWithMouseWheel)">
<DiscreteBooleanKeyFrame KeyTime="0%" Value="True"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
并创建一个类来定义中的附加属性,类似于以下内容:
public static class ScrollViewerProperties {
public static readonly DependencyProperty IsScrollingWithMouseWheelProperty = DependencyProperty.RegisterAttached(
"IsScrollingWithMouseWheel", typeof (bool), typeof (ScrollViewerProperties), new PropertyMetadata(default(bool)));
public static void SetIsScrollingWithMouseWheel(DependencyObject element, bool value) {
element.SetValue(IsScrollingWithMouseWheelProperty, value);
}
public static bool GetIsScrollingWithMouseWheel(DependencyObject element) {
return (bool) element.GetValue(IsScrollingWithMouseWheelProperty);
}
}
并更新ScrollBar
模板中的DataTrigger
以使用附加的属性,如下所示:
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ScrollViewer}},Path=(data:ScrollViewerProperties.IsScrollingWithMouseWheel)}" Value="True">
<DataTrigger.EnterActions>
<StopStoryboard BeginStoryboardName="fadeOut"/>
<BeginStoryboard Storyboard="{StaticResource FadeInStoryboard}" Name="fadeIn"/>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="fadeIn"/>
<BeginStoryboard Storyboard="{StaticResource FadeOutStoryboard}" Name="fadeOut"/>
</DataTrigger.ExitActions>
</DataTrigger>
只是为了完成一个精彩的@Roel van Westerop评论。我自己尝试过编辑2。除了一件小事,它的效果很好。与其只使用DataTrigger,不如使用这样的MultiDataTrigger:
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource=
{RelativeSource FindAncestor, AncestorType={x:Type ScrollViewer}},
Path=(data:ScrollViewerProperties.IsScrollingWithMouseWheel)}" Value="True"/>
<Condition Binding="{Binding RelativeSource={RelativeSource Mode=Self},
Path=IsMouseOver}" Value="False"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<StopStoryboard BeginStoryboardName="fadeOut"/>
<BeginStoryboard Storyboard="
{StaticResource FadeInStoryboard}" Name="fadeIn"/>
</MultiDataTrigger.EnterActions>
<MultiDataTrigger.ExitActions>
<StopStoryboard BeginStoryboardName="fadeIn"/>
<BeginStoryboard Storyboard="{StaticResource FadeInStoryboard}" Name="fadeOut"/>
</MultiDataTrigger.ExitActions>
</MultiDataTrigger>
此MultiDataTrigger修复了当您将鼠标悬停在滚动条上并使用MouseWheel滚动内容时的错误(如果没有此multitrigger,即使鼠标悬停在其上,滚动条也会淡出)