Toque:

enter image description here

Ratón:

enter image description here

¿Cómo le digo a ScrollViewer que empiece a usar la barra de desplazamiento táctil del código?

Este es un ejemplo:

<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>

Y:

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);
    }
}

Si ejecuta esto (al menos en una PC táctil), las barras de desplazamiento serán inicialmente táctiles. Y si luego mueve el cursor sobre él con el mouse, cambiará a mouse. y si luego lo toca (después de que las barras de desplazamiento se hayan ocultado) volverá a tocar.

Quiero decirle programáticamente que cambie de uno a otro. ¿Cómo se puede hacer eso? Si la única forma es editando la plantilla, ¿cómo se puede hacer eso sin codificación rígida la plantilla? Solo arreglando el detalle que necesita arreglarse. Para que quede claro: quiero poder llamar a un método que cambiará de uno a otro: void ChangeTo(bool mouse) { ... }. (Sin embargo, de lo contrario, forzar al ScrollViewer a estar siempre en un modo, sería una solución alternativa).

4
ispiro 23 dic. 2016 a las 00:49

3 respuestas

La mejor respuesta

Dentro de la plantilla predeterminada hay 3 VisualStates definidos: NoIndicator, TouchIndicator y MouseIndicator

El estilo del pulgar de desplazamiento se ve diferente según el estado que esté configurado actualmente. Para cambiar el estado de los controles, puede llamar

VisualStateManager.GoToState(scrollViewer1, "TouchIndicator");

Pero deberá encargarse manualmente de todos los eventos y acciones cuando este estado pueda cambiar.

Pero si desea tener siempre TouchIndicator visible, la mejor solución en mi opinión sería implementar CustomVisualStateManager, por ejemplo:

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;
    }
}

Luego, debe copiar la plantilla de MSDN, configurarla en su ScrollViewer y colocar MyVisualStateManager dentro de ella:

<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>

Conjunto de estilo:

<ScrollViewer Name="scrollViewer1"  Style="{StaticResource ScrollStyle}" HorizontalScrollBarVisibility="Visible">

Ahora, siempre que sea necesario cambiar su estado de ScrollViewer, ignora el estado exacto que desea, configurando TouchIndicator en su lugar.

2
RTDev 29 dic. 2016 a las 13:52

Estaba buscando restaurar el comportamiento simple de la barra de desplazamiento que uno podría esperar de una aplicación WPF (eliminando el indicador táctil por completo). El ejemplo dado por @Jay Zuo no funcionó, así que creé el mío. Las plantillas se pueden ver en el siguiente repositorio:

https://github.com/jsymon/UWP-Classic-ScrollBar-Template

enter image description here

1
maxp 19 jun. 2019 a las 09:02

Windows tiene dos visualizaciones de desplazamiento, que se basan en el modo de entrada del usuario: indicadores de desplazamiento cuando se usa el teclado táctil o el gamepad; y barras de desplazamiento interactivas para otros dispositivos de entrada, como mouse, teclado y lápiz.

enter image description here

Y en Directrices para la panorámica, es declaró que

Hay dos modos de visualización panorámica basados en el dispositivo de entrada detectado:

  • Indicadores de panorámica para el tacto.
  • Barras de desplazamiento para otros dispositivos de entrada, como mouse, panel táctil, teclado y lápiz.

Nota Los indicadores de desplazamiento solo son visibles cuando el contacto táctil está dentro de la región de desplazamiento. Del mismo modo, la barra de desplazamiento solo es visible cuando el cursor del mouse, el lápiz / lápiz o el foco del teclado están dentro de la región desplazable.

Indicadores de desplazamiento Los indicadores de desplazamiento son similares al cuadro de desplazamiento en una barra de desplazamiento. Indican la proporción del contenido visualizado al área total panoramizable y la posición relativa del contenido visualizado en el área panoramizable.

Nota A diferencia de las barras de desplazamiento estándar, los indicadores de desplazamiento son puramente informativos. No están expuestos a dispositivos de entrada y no pueden manipularse de ninguna manera.

Entonces, el modo de visualización se basa en el modo de entrada del usuario, no podemos cambiarlo programáticamente de uno a otro. Lo que podemos hacer es editar plantilla de ScrollViewer para que ScrollViewer lo haga solo use una interfaz de usuario de visualización.

En el estilo predeterminado, podemos encontrar que ScrollViewer tiene tres VisualState s: NoIndicator , TouchIndicator y MouseIndicator , que se utilizan para controlar el modo de visualización. Podemos cambiar el estado visual de TouchIndicator o MouseIndicator para que ScrollViewer esté siempre en un modo de visualización.

Por ejemplo, podemos reemplazar el Storyboard en "TouchIndicator" VisualState con el Storyboard en "MouseIndicator" VisualState para que el ScrollViewer esté siempre en modo de barra de desplazamiento me gusta:

<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>

Y viceversa.

<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>

Una vez que tengamos estas dos plantillas, podemos usar ScrollViewer.Template propiedad para cambiar el modo de visualización de uno a otro como sigue (" MouseIndicatorTemplate "y" TouchIndicatorTemplate "se colocan en Page.Resources):

void ChangeTo(bool mouse)
{
    if (mouse)
    {
        scrollViewer1.Template = (ControlTemplate)Resources["MouseIndicatorTemplate"];
    }
    else
    {
        scrollViewer1.Template = (ControlTemplate)Resources["TouchIndicatorTemplate"];
    }
}
2
Jay Zuo 28 dic. 2016 a las 09:05