23

私はスレッドを通過しました:

2 つの VerticalScrollBar を互いにバインドする

目標を達成するのにほぼ役立ちましたが、まだ何かが欠けています。スクロールバーを左右または上下に移動すると、両方のスクロールビューアで期待されるスクロール動作が得られますが、スクロールビューアでこれらのスクロールバーの端にある矢印ボタンを使用またはクリックしてスクロールしようとすると、スクロールされないスクロールビューアのみがスクロールされます。予想される動作。

これを解決するには、他に何を追加/編集する必要がありますか?

4

5 に答える 5

42

これを行う 1 つの方法は、イベントを使用してScrollChanged別のイベントを更新することです。ScrollViewer

<ScrollViewer Name="sv1" Height="100" 
              HorizontalScrollBarVisibility="Auto"
              ScrollChanged="ScrollChanged">
    <Grid Height="1000" Width="1000" Background="Green" />
</ScrollViewer>

<ScrollViewer Name="sv2" Height="100" 
              HorizontalScrollBarVisibility="Auto"
              ScrollChanged="ScrollChanged">
    <Grid Height="1000" Width="1000" Background="Blue" />
</ScrollViewer>

private void ScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        if (sender == sv1)
        {
            sv2.ScrollToVerticalOffset(e.VerticalOffset);
            sv2.ScrollToHorizontalOffset(e.HorizontalOffset);
        }
        else
        {
            sv1.ScrollToVerticalOffset(e.VerticalOffset);
            sv1.ScrollToHorizontalOffset(e.HorizontalOffset);
        }
    }
于 2013-03-01T07:50:52.267 に答える
11

問題は WPF に関するものですが、UWP を開発している人がこれに出くわした場合に備えて、少し異なるアプローチを取る必要がありました。UWP では、( ScrollViewer.ChangeView
を使用して) 他のスクロール ビューアーのスクロール オフセットを設定すると、他のスクロール ビューアーでもViewChangedイベントがトリガーされ、基本的にループが発生し、非常に不安定になり、適切に動作しなくなります。

スクロールされているオブジェクトがイベントを処理した最後のオブジェクトと等しくない場合、イベントの処理に少しタイムアウトを使用することでこれを解決しました。

XAML:

<ScrollViewer x:Name="ScrollViewer1" ViewChanged="SynchronizedScrollerOnViewChanged"> ... </ScrollViewer>
<ScrollViewer x:Name="ScrollViewer2" ViewChanged="SynchronizedScrollerOnViewChanged"> ... </ScrollViewer>

コードビハインド:

public sealed partial class MainPage
{
    private const int ScrollLoopbackTimeout = 500;

    private object _lastScrollingElement;
    private int _lastScrollChange = Environment.TickCount;

    public SongMixerUserControl()
    {
        InitializeComponent();
    }

    private void SynchronizedScrollerOnViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
    {
        if (_lastScrollingElement != sender && Environment.TickCount - _lastScrollChange < ScrollLoopbackTimeout) return;

        _lastScrollingElement = sender;
        _lastScrollChange = Environment.TickCount;

        ScrollViewer sourceScrollViewer;
        ScrollViewer targetScrollViewer;
        if (sender == ScrollViewer1)
        {
            sourceScrollViewer = ScrollViewer1;
            targetScrollViewer = ScrollViewer2;
        }
        else
        {
            sourceScrollViewer = ScrollViewer2;
            targetScrollViewer = ScrollViewer1;
        }

        targetScrollViewer.ChangeView(null, sourceScrollViewer.VerticalOffset, null);
    }
}

タイムアウトは 500ms であることに注意してください。これは少し長いように見えるかもしれませんが、UWP アプリにはスクロール (マウスのスクロール ホイールを使用する場合) にアニメーション (実際にはイージング) があるため、数百ミリ秒以内に数回イベントがトリガーされます。 . このタイムアウトは完全に機能しているようです。

于 2016-09-10T10:45:27.440 に答える
0

UWP 用の C# での Rene Sackers のコード リストのフォローアップでは、UWP 用の VB.Net でこの同じ問題に対処し、タイムアウトを使用して、1 つの Scroll Viewer オブジェクトがイベントを発生させたために発生する驚異的な効果を回避する方法を次に示します。ユーザーの操作によるものではありません。アプリケーションに適した 500 ミリ秒のタイムアウト期間を設定しました。

注: svLvMain はスクロール ビューアーです (私にとってはメイン ウィンドウです)。いずれかのスクロールビューアをズームまたはスクロールすると、両方のスクロールビューアが同期されます。

Private Enum ScrollViewTrackingMasterSv
    Header = 1
    ListView = 2
    None = 0
End Enum

Private ScrollViewTrackingMaster As ScrollViewTrackingMasterSv
Private DispatchTimerForSvTracking As DispatcherTimer    

Private Sub DispatchTimerForSvTrackingSub(sender As Object, e As Object)
    ScrollViewTrackingMaster = ScrollViewTrackingMasterSv.None
    DispatchTimerForSvTracking.Stop()
End Sub

Private Sub svLvTracking(sender As Object, e As ScrollViewerViewChangedEventArgs, ByRef inMastScrollViewer As ScrollViewer)
    Dim tempHorOffset As Double
    Dim tempVerOffset As Double
    Dim tempZoomFactor As Single

    Dim tempSvMaster As New ScrollViewer
    Dim tempSvSlave As New ScrollViewer

    Select Case inMastScrollViewer.Name
        Case svLvMainHeader.Name

            Select Case ScrollViewTrackingMaster
                Case ScrollViewTrackingMasterSv.Header
                    tempSvMaster = svLvMainHeader
                    tempSvSlave = svLvMain

                    tempHorOffset = tempSvMaster.HorizontalOffset
                    tempVerOffset = tempSvMaster.VerticalOffset
                    tempZoomFactor = tempSvMaster.ZoomFactor

                    tempSvSlave.ChangeView(tempHorOffset, tempVerOffset, tempZoomFactor)

                    If DispatchTimerForSvTracking.IsEnabled Then
                        DispatchTimerForSvTracking.Stop()
                        DispatchTimerForSvTracking.Start()
                    End If

                Case ScrollViewTrackingMasterSv.ListView

                Case ScrollViewTrackingMasterSv.None
                    tempSvMaster = svLvMainHeader
                    tempSvSlave = svLvMain

                    ScrollViewTrackingMaster = ScrollViewTrackingMasterSv.Header
                    DispatchTimerForSvTracking = New DispatcherTimer()
                    AddHandler DispatchTimerForSvTracking.Tick, AddressOf DispatchTimerForSvTrackingSub
                    DispatchTimerForSvTracking.Interval = New TimeSpan(0, 0, 0, 0, 500)
                    DispatchTimerForSvTracking.Start()

                    tempHorOffset = tempSvMaster.HorizontalOffset
                    tempVerOffset = tempSvMaster.VerticalOffset
                    tempZoomFactor = tempSvMaster.ZoomFactor

                    tempSvSlave.ChangeView(tempHorOffset, tempVerOffset, tempZoomFactor)
            End Select


        Case svLvMain.Name

            Select Case ScrollViewTrackingMaster
                Case ScrollViewTrackingMasterSv.Header

                Case ScrollViewTrackingMasterSv.ListView

                    tempSvMaster = svLvMain
                    tempSvSlave = svLvMainHeader

                    tempHorOffset = tempSvMaster.HorizontalOffset
                    tempVerOffset = tempSvMaster.VerticalOffset
                    tempZoomFactor = tempSvMaster.ZoomFactor

                    tempSvSlave.ChangeView(tempHorOffset, tempVerOffset, tempZoomFactor)

                    If DispatchTimerForSvTracking.IsEnabled Then
                        DispatchTimerForSvTracking.Stop()
                        DispatchTimerForSvTracking.Start()
                    End If

                Case ScrollViewTrackingMasterSv.None
                    tempSvMaster = svLvMain
                    tempSvSlave = svLvMainHeader

                    ScrollViewTrackingMaster = ScrollViewTrackingMasterSv.ListView
                    DispatchTimerForSvTracking = New DispatcherTimer()
                    AddHandler DispatchTimerForSvTracking.Tick, AddressOf DispatchTimerForSvTrackingSub
                    DispatchTimerForSvTracking.Interval = New TimeSpan(0, 0, 0, 0, 500)
                    DispatchTimerForSvTracking.Start()

                    tempHorOffset = tempSvMaster.HorizontalOffset
                    tempVerOffset = tempSvMaster.VerticalOffset
                    tempZoomFactor = tempSvMaster.ZoomFactor

                    tempSvSlave.ChangeView(tempHorOffset, tempVerOffset, tempZoomFactor)
            End Select

        Case Else
            Exit Sub

    End Select


End Sub


Private Sub svLvMainHeader_ViewChanged(sender As Object, e As ScrollViewerViewChangedEventArgs) Handles svLvMainHeader.ViewChanged

    Call svLvTracking(sender, e, svLvMainHeader)

End Sub

Private Sub svLvMain_ViewChanged(sender As Object, e As ScrollViewerViewChangedEventArgs) Handles svLvMain.ViewChanged

    Call svLvTracking(sender, e, svLvMain)

End Sub
于 2016-12-14T09:57:30.607 に答える