◆ タブ切り替え時に TabItem の中の要素にフォーカスされる
◆ ScrollViewer の中の要素にフォーカスされると ScrollViewer がスクロールされる
◆ 対策は ダミーのフォーカス可能要素を TabItem の最初においておくのがよさそう
◆ Tab でフォーカス切替時に邪魔ならスキップする処理を入れておく 

TabControl でタブを作ってその中に ScrollViewer があると 勝手に下の方までスクロールされていました

原因はタブを切り替えるとそのタブの中の最初の要素にフォーカスが当たるから
ScrollViewer の中にはボタンがあって ボタンにフォーカスが当たることでボタンが見える位置までスクロールされていました

切り替え前の最初に画面を表示したときのタブではスクロールされていません
タブを切り替えると切り替え先のタブ内の ScrollViewer がスクロールされます

ただでさえ 最初から中途半端なところにスクロールあると気持ち悪いのに タブを切り替えるたびにボタンが見える位置までスクロールされて前回の位置が保持されないのは使いづらいです


この Window を開いてタブを切り替えるだけで再現できます
<Window x:Class="w02.Window1"
        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:local="clr-namespace:w02"
        mc:Ignorable="d"
        Title="Window1"
        Height="320" Width="480">
    <Grid>
        <TabControl>
            <TabItem Header="1" Padding="20 10">
                <Grid></Grid>
            </TabItem>
            <TabItem Header="2" Padding="20 10">
                <ScrollViewer>
                    <StackPanel>
                        <Label Margin="0 20">a</Label>
                        <Label Margin="0 20">a</Label>
                        <Label Margin="0 20">a</Label>
                        <Label Margin="0 20">a</Label>
                        <Label Margin="0 20">a</Label>
                        <Label Margin="0 20">a</Label>
                        <Label Margin="0 20">a</Label>
                        <Button>b</Button>
                        <Label Margin="0 20">c</Label>
                        <Label Margin="0 20">c</Label>
                        <Label Margin="0 20">c</Label>
                        <Label Margin="0 20">c</Label>
                        <Label Margin="0 20">c</Label>
                        <Label Margin="0 20">c</Label>
                        <Label Margin="0 20">c</Label>
                        <Button>d</Button>
                    </StackPanel>
                </ScrollViewer>
            </TabItem>
        </TabControl>
    </Grid>
</Window>

対策

対策をするにもタブ切り替えイベントで  ScrollViewer のスクロールポジションを一番上にするというのもちょっと大変です
そのタブに ScrollViewer があるかないかもわからないですし どこにあるか構造も統一されていないです

複数あった場合にはフォーカスされたものだけを対象にしないといけないですし すでに開いたことのあるタブなら一番上じゃなくて前回のスクロール場所に戻すべきですからスクロールをキャンセルとできないなら 前の値を保持して手動で再設定することになります

さすがにこれはやりたくないので別のアプローチを考えます


フォーカスによってスクロールされたのを戻す

ではなく

フォーカスされないようにする

です


これなら ScrollViewer や TabControl を拡張しないで済みそうです

方法ですが そもそもなぜスクロールするかは ボタンなどのフォーカス出来る要素がスクロールしたところにあるからです
スクロールの必要のない上の部分 というか TabItem の中の ScrollViewer の外側かつ ScollViewer より前にフォーカス出来る要素があればそっちをフォーカスしてくれるはずです

TabItem をこれから
<TabItem Header="2" Padding="20 10">
    <ScrollViewer>
        <StackPanel>
            <Label Margin="0 20">a</Label>
            <Label Margin="0 20">a</Label>
            <Label Margin="0 20">a</Label>
            <Label Margin="0 20">a</Label>
            <Label Margin="0 20">a</Label>
            <Label Margin="0 20">a</Label>
            <Label Margin="0 20">a</Label>
            <Button>b</Button>
            <Label Margin="0 20">c</Label>
            <Label Margin="0 20">c</Label>
            <Label Margin="0 20">c</Label>
            <Label Margin="0 20">c</Label>
            <Label Margin="0 20">c</Label>
            <Label Margin="0 20">c</Label>
            <Label Margin="0 20">c</Label>
            <Button>d</Button>
        </StackPanel>
    </ScrollViewer>
</TabItem>

こうします
<TabItem Header="2" Padding="20 10">
    <Grid>
        <Control Width="0" Height="0"></Control>
        <ScrollViewer>
            <StackPanel>
                <Label Margin="0 20">a</Label>
                <Label Margin="0 20">a</Label>
                <Label Margin="0 20">a</Label>
                <Label Margin="0 20">a</Label>
                <Label Margin="0 20">a</Label>
                <Label Margin="0 20">a</Label>
                <Label Margin="0 20">a</Label>
                <Button>b</Button>
                <Label Margin="0 20">c</Label>
                <Label Margin="0 20">c</Label>
                <Label Margin="0 20">c</Label>
                <Label Margin="0 20">c</Label>
                <Label Margin="0 20">c</Label>
                <Label Margin="0 20">c</Label>
                <Label Margin="0 20">c</Label>
                <Button>d</Button>
            </StackPanel>
        </ScrollViewer>
    </Grid>
</TabItem>

フォーカス可能な Control をおいてます
Width と Height には 0 を指定して見えないようにしておきます
ScrollViewer のほうが前面ですが フォーカス時の点線は見えるので 0 にしておいたほうがいいです

フォーカス

一応完成ですが Control がないものと比べると Tab キーを押してフォーカスを切り替える場合に余計なものが入ります
画面上は何もないのに Control の分 一度フォーカスを見失うときがあります

気にならないようなものですが 気にする人もいると思うので Control がフォーカスを受けるとスキップするようにします
画面上では見えないので 通常の使い方ではクリックでフォーカスされることはないです
キーボードでフォーカス切り替えたときだけ発生する問題です

XAML では Control に GotFocus イベントリスナを設定します
<TabItem Header="2" Padding="20 10">
    <Grid>
        <Control Width="0" Height="0" GotFocus="skipFocus"></Control>
        <ScrollViewer>
            <StackPanel>
                <Label Margin="0 20">a</Label>
                <Label Margin="0 20">a</Label>
                <Label Margin="0 20">a</Label>
                <Label Margin="0 20">a</Label>
                <Label Margin="0 20">a</Label>
                <Label Margin="0 20">a</Label>
                <Label Margin="0 20">a</Label>
                <Button>b</Button>
                <Label Margin="0 20">c</Label>
                <Label Margin="0 20">c</Label>
                <Label Margin="0 20">c</Label>
                <Label Margin="0 20">c</Label>
                <Label Margin="0 20">c</Label>
                <Label Margin="0 20">c</Label>
                <Label Margin="0 20">c</Label>
                <Button>d</Button>
            </StackPanel>
        </ScrollViewer>
    </Grid>
</TabItem>

スキップする処理はこうなります
private void skipFocus(object sender, RoutedEventArgs e)
{
    var direction = FocusNavigationDirection.Next;

    if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
    {
        direction = FocusNavigationDirection.Previous;
    }

    var treq = new TraversalRequest(direction);

    if (((UIElement)sender).MoveFocus(treq)) e.Handled = true;
}

Shift キーが押されてるとバックなので前方向 それ以外は後方向の要素をフォーカスさせます
これでおっけい


それにしても TabControl に切替時に内側の最初の要素をフォーカスするかどうかのオプションがほしいですね
デフォルトはタブの中身じゃなくてタブ切り替えのボタン自体をフォーカスしておいてくれればいいのに