触:
鼠标:
如何告诉ScrollViewer
开始使用代码中的触摸式滚动条?
以下是一个例子:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ScrollViewer Name="scrollViewer1" HorizontalScrollBarVisibility="Visible" >
<Image Stretch="UniformToFill">
<Image.Source>
<BitmapImage x:Name="bitmapImage1" UriSource="https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-icon.png"></BitmapImage>
</Image.Source>
</Image>
</ScrollViewer>
</Grid>
和
public sealed partial class MainPage : Page
{
DispatcherTimer dispatcherTimer1 = new DispatcherTimer { Interval = TimeSpan.FromSeconds(5) };
bool SE;
public MainPage()
{
this.InitializeComponent();
dispatcherTimer1.Tick += DispatcherTimer1_Tick;
dispatcherTimer1.Start();
}
private void DispatcherTimer1_Tick(object sender, object e)
{
if (SE = !SE) bitmapImage1.UriSource = new Uri("https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/se/se-icon.png");
else bitmapImage1.UriSource = new Uri("https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-icon.png");
scrollViewer1.ChangeView(SE ? 1 : 0, SE ? 1 : 0, null);
}
}
如果你运行它(至少在启用触摸的PC上),滚动条最初会被触摸。然后,如果您使用鼠标将光标移到它上面,它将变为鼠标。如果你然后触摸它(在隐藏滚动条之后)它将返回触摸。
我想以编程方式告诉它从一个变为另一个。怎么办?如果唯一的方法是编辑模板 - 如何在没有硬编码的情况下完成 the template?只需修复需要修复的细节。要明确:我希望能够调用一个方法,从一个方法改为另一个方法:void ChangeTo(bool mouse) { ... }
。 (尽管如此,如果不这样做,只是强迫ScrollViewer始终处于一种模式,那将是一种解决方法。)
答案 0 :(得分:2)
Windows有两个滚动可视化,基于用户的输入模式:滚动指示器,当使用触摸或游戏手柄时;和其他输入设备(包括鼠标,键盘和笔)的交互式滚动条。
根据检测到的输入设备,有两种平移显示模式:
- 平移触控指示。
- 滚动条以显示其他输入设备,包括鼠标,触控板,键盘和手写笔。
注意仅当触控接触位于可信任区域内时,才会显示平移指示。同样,仅当鼠标光标,笔/手写笔光标或键盘焦点位于可滚动区域内时,滚动条才可见。
平移指标平移指标与滚动条中的滚动框类似。它们表示显示内容占总可用区域的比例以及显示内容在可占用区域中的相对位置。
注意与标准滚动条不同,平移指示器纯粹是提供信息。它们不会暴露在输入设备中,也无法以任何方式进行操作。
因此显示模式基于用户的输入模式,我们无法以编程方式将其从一个更改为另一个。我们可以做的是编辑ScrollViewer's template,以便ScrollViewer只使用一个可视化UI。
在默认样式中,我们可以发现ScrollViewer
有三个VisualState s: NoIndicator , TouchIndicator 和 MouseIndicator ,用于控制显示模式。我们可以更改 TouchIndicator 或 MouseIndicator 可视状态,使ScrollViewer
始终处于一种显示模式。
例如,我们可以将“TouchIndicator”Storyboard
下的VisualState
替换为“MouseIndicator”Storyboard
下的VisualState
,以使ScrollViewer
始终在滚动条模式如:
<ControlTemplate x:Key="MouseIndicatorTemplate" TargetType="ScrollViewer">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ScrollingIndicatorStates">
<VisualStateGroup.Transitions>
<VisualTransition From="MouseIndicator" To="NoIndicator">
<Storyboard>
<FadeOutThemeAnimation BeginTime="0:0:3" TargetName="ScrollBarSeparator" />
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="0:0:3">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>None</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="0:0:3">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>None</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition From="TouchIndicator" To="NoIndicator">
<Storyboard>
<FadeOutThemeAnimation TargetName="ScrollBarSeparator" />
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="0:0:0.5">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>None</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="0:0:0.5">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>None</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="NoIndicator">
<Storyboard>
<FadeOutThemeAnimation TargetName="ScrollBarSeparator" />
</Storyboard>
</VisualState>
<VisualState x:Name="TouchIndicator">
<Storyboard>
<FadeInThemeAnimation TargetName="ScrollBarSeparator" />
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode" Duration="0">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>MouseIndicator</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode" Duration="0">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>MouseIndicator</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="MouseIndicator">
<Storyboard>
<FadeInThemeAnimation TargetName="ScrollBarSeparator" />
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode" Duration="0">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>MouseIndicator</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode" Duration="0">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>MouseIndicator</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ScrollContentPresenter x:Name="ScrollContentPresenter"
Grid.RowSpan="2"
Grid.ColumnSpan="2"
Margin="{TemplateBinding Padding}"
ContentTemplate="{TemplateBinding ContentTemplate}" />
<Grid Grid.RowSpan="2" Grid.ColumnSpan="2" />
<ScrollBar x:Name="VerticalScrollBar"
Grid.Column="1"
HorizontalAlignment="Right"
IsTabStop="False"
Maximum="{TemplateBinding ScrollableHeight}"
Orientation="Vertical"
ViewportSize="{TemplateBinding ViewportHeight}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
Value="{TemplateBinding VerticalOffset}" />
<ScrollBar x:Name="HorizontalScrollBar"
Grid.Row="1"
IsTabStop="False"
Maximum="{TemplateBinding ScrollableWidth}"
Orientation="Horizontal"
ViewportSize="{TemplateBinding ViewportWidth}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
Value="{TemplateBinding HorizontalOffset}" />
<Border x:Name="ScrollBarSeparator"
Grid.Row="1"
Grid.Column="1"
Background="{ThemeResource ScrollViewerScrollBarSeparatorBackground}" />
</Grid>
</Border>
</ControlTemplate>
反之亦然。
<ControlTemplate x:Key="TouchIndicatorTemplate" TargetType="ScrollViewer">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ScrollingIndicatorStates">
<VisualStateGroup.Transitions>
<VisualTransition From="MouseIndicator" To="NoIndicator">
<Storyboard>
<FadeOutThemeAnimation BeginTime="0:0:3" TargetName="ScrollBarSeparator" />
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="0:0:3">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>None</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="0:0:3">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>None</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition From="TouchIndicator" To="NoIndicator">
<Storyboard>
<FadeOutThemeAnimation TargetName="ScrollBarSeparator" />
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="0:0:0.5">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>None</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode">
<DiscreteObjectKeyFrame KeyTime="0:0:0.5">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>None</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="NoIndicator">
<Storyboard>
<FadeOutThemeAnimation TargetName="ScrollBarSeparator" />
</Storyboard>
</VisualState>
<VisualState x:Name="TouchIndicator">
<Storyboard>
<FadeOutThemeAnimation TargetName="ScrollBarSeparator" />
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode" Duration="0">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>TouchIndicator</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode" Duration="0">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>TouchIndicator</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="MouseIndicator">
<Storyboard>
<FadeOutThemeAnimation TargetName="ScrollBarSeparator" />
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="IndicatorMode" Duration="0">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>TouchIndicator</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="HorizontalScrollBar" Storyboard.TargetProperty="IndicatorMode" Duration="0">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<ScrollingIndicatorMode>TouchIndicator</ScrollingIndicatorMode>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ScrollContentPresenter x:Name="ScrollContentPresenter"
Grid.RowSpan="2"
Grid.ColumnSpan="2"
Margin="{TemplateBinding Padding}"
ContentTemplate="{TemplateBinding ContentTemplate}" />
<Grid Grid.RowSpan="2" Grid.ColumnSpan="2" />
<ScrollBar x:Name="VerticalScrollBar"
Grid.Column="1"
HorizontalAlignment="Right"
IsTabStop="False"
Maximum="{TemplateBinding ScrollableHeight}"
Orientation="Vertical"
ViewportSize="{TemplateBinding ViewportHeight}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
Value="{TemplateBinding VerticalOffset}" />
<ScrollBar x:Name="HorizontalScrollBar"
Grid.Row="1"
IsTabStop="False"
Maximum="{TemplateBinding ScrollableWidth}"
Orientation="Horizontal"
ViewportSize="{TemplateBinding ViewportWidth}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
Value="{TemplateBinding HorizontalOffset}" />
<Border x:Name="ScrollBarSeparator"
Grid.Row="1"
Grid.Column="1"
Background="{ThemeResource ScrollViewerScrollBarSeparatorBackground}" />
</Grid>
</Border>
</ControlTemplate>
一旦我们有了这两个模板,我们可以使用ScrollViewer.Template属性将显示模式从一个更改为另一个,如下所示(“MouseIndicatorTemplate”和“TouchIndicatorTemplate”放在Page.Resources
中):< / p>
void ChangeTo(bool mouse)
{
if (mouse)
{
scrollViewer1.Template = (ControlTemplate)Resources["MouseIndicatorTemplate"];
}
else
{
scrollViewer1.Template = (ControlTemplate)Resources["TouchIndicatorTemplate"];
}
}
答案 1 :(得分:2)
在默认模板中,定义了3个VisualStates: NoIndicator, TouchIndicator和 MouseIndicator
根据当前设置的状态,scroller thumb的样式看起来不同。 要更改控件状态,您可以调用
VisualStateManager.GoToState(scrollViewer1, "TouchIndicator");
但是当这种状态发生变化时,您需要手动处理所有事件和操作。
但是如果你想让TouchIndicator始终可见,那么我认为更好的解决方案就是实现CustomVisualStateManager,例如:
public class MyVisualStateManager : VisualStateManager
{
protected override bool GoToStateCore(Control control, FrameworkElement templateRoot,
System.String stateName, VisualStateGroup group, VisualState state, System.Boolean useTransitions)
{
switch (stateName)
{
case "NoIndicator":
case "TouchIndicator":
case "MouseIndicator":
base.GoToStateCore(control, templateRoot, "TouchIndicator", group, state, useTransitions);
break;
}
return true;
}
}
然后,您需要从MSDN复制模板,将其设置为ScrollViewer并将MyVisualStateManager放入其中:
<Style TargetType="ScrollViewer" x:Key="ScrollStyle">
<Setter Property="HorizontalScrollMode" Value="Auto" />
<Setter Property="VerticalScrollMode" Value="Auto" />
<Setter Property="IsHorizontalRailEnabled" Value="True" />
<Setter Property="IsVerticalRailEnabled" Value="True" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="ZoomMode" Value="Disabled" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="VerticalContentAlignment" Value="Top" />
<Setter Property="VerticalScrollBarVisibility" Value="Visible" />
<Setter Property="Padding" Value="0" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ScrollViewer">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<VisualStateManager.CustomVisualStateManager>
<local:MyVisualStateManager/>
</VisualStateManager.CustomVisualStateManager>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ScrollingIndicatorStates">
<VisualStateGroup.Transitions>
<VisualTransition From="MouseIndicator" To="NoIndicator">
<Storyboard>
(... blabla ...)
</Style>
样式集:
<ScrollViewer Name="scrollViewer1" Style="{StaticResource ScrollStyle}" HorizontalScrollBarVisibility="Visible">
现在,无论何时需要更改ScrollViewer状态,您都会忽略它想要的确切状态,而是设置TouchIndicator。
答案 2 :(得分:0)
我一直在寻找恢复WPF应用程序可能期望的简单滚动条行为的方式(完全删除触摸指示器)。 @Jay Zuo给出的示例无效,因此我创建了自己的示例。可以在以下存储库中查看模板: