7

RichEditBox(editor) とGrid(MarginNotes)を備えた Windows ストア アプリを持っています。

2 つの要素の垂直スクロール位置を常に一致させる必要があります。これの目的は、ユーザーがドキュメントの余白にメモを追加できるようにすることです。

カーソル位置に基づいてメモの配置を既に把握しています。メモが追加されると、カーソルまでのすべてのテキストが選択されます。その選択はRichEditBox、 内の2 番目の invisible に追加されStackPanelます。次にActualHeight、グリッド内のノートの位置を示すこのコントロールの を取得します。

私の問題は、RichEditBox上下にスクロールすると、Gridそれに応じてスクロールしないことです。

最初のテクニック

両方を の中に入れて、ScrollViewerスクロールを無効にしてみましたRichEditBox

<ScrollViewer x:Name="EditorScroller" 
    VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150" />
            <ColumnDefinition Width="{Binding *" />
            <ColumnDefinition Width="150" />
        </Grid.ColumnDefinitions>
        <Grid x:Name="MarginNotes" Grid.Column="0" HorizontalAlignment="Right"                  
            Height="{Binding ActualHeight, ElementName=editor}">
        </Grid>
        <StackPanel Grid.Column="1">
            <RichEditBox x:Name="margin_helper" Opacity="0" Height="Auto"></RichEditBox>
        </StackPanel>
        <RichEditBox x:Name="editor" Grid.Column="1" Height="Auto"
            ScrollViewer.VerticalScrollBarVisibility="Hidden" />
    </Grid>
</ScrollViewer>

コントロールの一番下までスクロールしてRichEditBoxEnter キーを数回押すと、カーソルが見えなくなります。はScrollViewerカーソルで自動的にスクロールしません。

カーソルの位置を確認し、それをエディターの高さと比較し、それにVerticalOffset応じてスクロールを調整する C# コードを追加してみました。これはうまくいきましたが、信じられないほど遅かったです。最初はKeyUp、文を入力するとアプリが停止するイベントでそれを持っていました。その後、5 秒のタイマーを設定しましたが、それでもアプリのパフォーマンスが低下し、カーソルが見えなくなってからRichEditBoxスクロールするまでに 5 秒の遅延が発生する可能性がありました。

第二のテクニック

MarginNotesまた、独自のを入れて、自分のイベントに基づいてScrollViewerプログラムで設定しようとしました。VerticalOffsetRichEditBoxViewChanged

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="150" />
        <ColumnDefinition Width="{Binding *" />
        <ColumnDefinition Width="150" />
    </Grid.ColumnDefinitions>
    <ScrollViewer x:Name="MarginScroller" Grid.Column="0" 
         VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
        <Grid x:Name="MarginNotes" HorizontalAlignment="Right"                  
            Height="{Binding ActualHeight, ElementName=editor}">
        </Grid>
    </ScrollViewer>
    <StackPanel Grid.Column="1">
        <RichEditBox x:Name="margin_helper" Opacity="0" Height="Auto"></RichEditBox>
    </StackPanel>
    <RichEditBox x:Name="editor" Grid.Column="1" Height="Auto" 
        Loaded="editor_loaded" SizeChanged="editor_SizeChanged" />
</Grid>

関連するイベント ハンドラ

void editor_Loaded(object sender, RoutedEventArgs e)
{
    // setting this in the OnNavigatedTo causes a crash, has to be set here. 
    // this uses WinRTXAMLToolkit as suggested by Nate Diamond to find the 
    // ScrollViewer and add the event handler
    editor.GetFirstDescendantOfType<ScrollViewer>().ViewChanged += editor_ViewChanged;
}

private void editor_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
    // when the RichEditBox scrolls, scroll the MarginScroller the same amount
    double editor_vertical_offset = ((ScrollViewer)sender).VerticalOffset;
    MarginScroller.ChangeView(0, editor_vertical_offset, 1);       
}

private void editor_SizeChanged(object sender, SizeChangedEventArgs e)
{
    // when the RichEditBox size changes, change the size of MarginNotes to match
    string text = "";
    editor.Document.GetText(TextGetOptions.None, out text);
    margin_helper.Document.SetText(TextSetOptions.None, text);
    MarginNotes.Height = margin_helper.ActualHeight;
}

ViewChangedこれは機能しましたが、スクロールが停止した後、イベントが発生するまでスクロールが適用されないため、かなりラグがありました。イベントを使ってみたのViewChangingですが、なぜか全く発火しません。さらに、Grid高速スクロール後に位置がずれることもありました。

4

1 に答える 1