我已经通过了螺纹:
结合2个VerticalScrollBars彼此
它几乎帮助实现这一目标,但仍然有一些人失踪。 这是那动人的左右滚动条或上下给人预计在我的两个scrollviewers的滚动,但行为时,我们尝试使用滚动/点击箭头按钮在scrollviewers这些滚动条只有一个ScrollViewer中滚动的两端是不是预期的行为。
那么我们还有什么需要添加/编辑来解决这个问题?
我已经通过了螺纹:
结合2个VerticalScrollBars彼此
它几乎帮助实现这一目标,但仍然有一些人失踪。 这是那动人的左右滚动条或上下给人预计在我的两个scrollviewers的滚动,但行为时,我们尝试使用滚动/点击箭头按钮在scrollviewers这些滚动条只有一个ScrollViewer中滚动的两端是不是预期的行为。
那么我们还有什么需要添加/编辑来解决这个问题?
这样做的一种方法是使用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);
}
}
现在的问题是WPF,但在任何情况下,在开发这个UWP跌倒,我不得不采取稍微不同的方法。
在UWP,当你设置滚动(使用其他滚动浏览器的偏移ScrollViewer.ChangeView ),这也触发ViewChanged另滚动浏览器的事件,基本上创建一个循环,使它非常stuttery,而无法正常工作。
我通过对处理事件,如果被滚动的对象不等于处理该事件的最后一个对象有点超时解决了这个。
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应用程序有一个动画(或者,缓和,真)在其滚动(使用鼠标滚轮时),它会导致几百毫秒之内,触发了几次事件。 此超时似乎完美地工作。
如果它是有用的,这里有一个行为(UWP,但它足以让这个想法); 使用行为有助于分离视图和代码在一个MVVM设计。
using Microsoft.Xaml.Interactivity;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
public class SynchronizeHorizontalOffsetBehavior : Behavior<ScrollViewer>
{
public static ScrollViewer GetSource(DependencyObject obj)
{
return (ScrollViewer)obj.GetValue(SourceProperty);
}
public static void SetSource(DependencyObject obj, ScrollViewer value)
{
obj.SetValue(SourceProperty, value);
}
// Using a DependencyProperty as the backing store for Source. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SourceProperty =
DependencyProperty.RegisterAttached("Source", typeof(object), typeof(SynchronizeHorizontalOffsetBehavior), new PropertyMetadata(null, SourceChangedCallBack));
private static void SourceChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
SynchronizeHorizontalOffsetBehavior synchronizeHorizontalOffsetBehavior = d as SynchronizeHorizontalOffsetBehavior;
if (synchronizeHorizontalOffsetBehavior != null)
{
var oldSourceScrollViewer = e.OldValue as ScrollViewer;
var newSourceScrollViewer = e.NewValue as ScrollViewer;
if (oldSourceScrollViewer != null)
{
oldSourceScrollViewer.ViewChanged -= synchronizeHorizontalOffsetBehavior.SourceScrollViewer_ViewChanged;
}
if (newSourceScrollViewer != null)
{
newSourceScrollViewer.ViewChanged += synchronizeHorizontalOffsetBehavior.SourceScrollViewer_ViewChanged;
synchronizeHorizontalOffsetBehavior.UpdateTargetViewAccordingToSource(newSourceScrollViewer);
}
}
}
private void SourceScrollViewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
ScrollViewer sourceScrollViewer = sender as ScrollViewer;
this.UpdateTargetViewAccordingToSource(sourceScrollViewer);
}
private void UpdateTargetViewAccordingToSource(ScrollViewer sourceScrollViewer)
{
if (sourceScrollViewer != null)
{
if (this.AssociatedObject != null)
{
this.AssociatedObject.ChangeView(sourceScrollViewer.HorizontalOffset, null, null);
}
}
}
protected override void OnAttached()
{
base.OnAttached();
var source = GetSource(this.AssociatedObject);
this.UpdateTargetViewAccordingToSource(source);
}
}
以下是如何使用它:
<ScrollViewer
HorizontalScrollMode="Enabled"
HorizontalScrollBarVisibility="Hidden"
>
<interactivity:Interaction.Behaviors>
<behaviors:SynchronizeHorizontalOffsetBehavior Source="{Binding ElementName=ScrollViewer}" />
</interactivity:Interaction.Behaviors>
</ScrollViewer>
<ScrollViewer x:Name="ScrollViewer" />
在刘若英Sackers码跟进在C#中UWP上市,这是我如何在VB.Net解决同样的问题了UWP有超时,避免因为一个滚动浏览器对象触发事件的惊人效果,因为它的观点是通过改变的代码,而不是由用户交互。 我把一个500毫秒的超时时间这对我的应用效果很好。
注:svLvMain是一个ScrollViewer中(对我来说是主窗口)svLVMainHeader是一个ScrollViewer中(对我来说是就是那张在主窗口上方,我想主窗口,反之亦然跟踪沿着什么样的头)。 缩放或滚动的ScrollViewer或者将保留两个scrollviewers同步。
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