ScrollViewerのアンカーへスクロールする

2021-03-14

MainView.xaml

<Window x:Class="WpfApp27.View.MainView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
        xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
        xmlns:local="clr-namespace:WpfApp27.View"
        xmlns:vm="clr-namespace:WpfApp27.ViewModel"
        mc:Ignorable="d"
        Title="MainView" Height="250" Width="400">

    <Window.DataContext>
        <vm:MainViewModel/>
    </Window.DataContext>

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <StackPanel Grid.Column="0">
            <Button Content="Page1へ">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="ScrollToObject" MethodParameter="{Binding ElementName=page1}"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>
            <Button Content="Page2へ">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="ScrollToObject" MethodParameter="{Binding ElementName=page2}"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>
            <Button Content="Page3へ">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="ScrollToObject" MethodParameter="{Binding ElementName=page3}"/>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>
        </StackPanel>

        <ScrollViewer Grid.Column="1">
            <StackPanel>
                <StackPanel.Resources>
                    <Style TargetType="TextBlock">
                        <Setter Property="Margin" Value="0,0,0,300"/>
                    </Style>
                </StackPanel.Resources>
                
                <TextBlock x:Name="page1" Text="Page1"/>
                <TextBlock x:Name="page2" Text="Page2"/>
                <TextBlock x:Name="page3" Text="Page3"/>
            </StackPanel>
        </ScrollViewer>
    </Grid>
    
</Window>

MainView.xaml

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace WpfApp27.ViewModel
{
    public class MainViewModel : Livet.ViewModel
    {
        public void ScrollToObject(TextBlock ankerText)
        {
            double dblOffset = 0;
            FrameworkElement frameworkElement = ankerText;

            do
            {
                Vector vector = VisualTreeHelper.GetOffset(frameworkElement);
                dblOffset += vector.Y;

                frameworkElement = (FrameworkElement)frameworkElement.Parent;
            } while (frameworkElement is ScrollViewer == false);

            dblOffset += (frameworkElement as ScrollViewer).VerticalOffset;
            (frameworkElement as ScrollViewer).ScrollToVerticalOffset(dblOffset);
        }
    }
}