我在FlowDocumentReader中显示一个带有ViewingMode=“滚动”的ViewingMode=。如果我在鼠标上使用轮子,文档滚动的速度会非常慢。我想增加滚动步长。
有人有什么想法吗?
发布于 2009-06-10 03:01:11
我们可以在一个控件的MouseWheel事件中修改它,比如Sohnee,但是它只需要针对一个特定的情况就可以解决,而且您必须能够访问FlowDocumentReader,如果您使用类似于MVVM的东西,您将无法访问它。相反,我们可以创建一个附加属性,然后可以用ScrollViewer对任何元素进行设置。在定义附加属性时,我们还需要一个PropertyChanged回调,其中我们将执行对滚动速度的实际修改。我还将我的属性默认为1,我将使用的速度范围是.1x到3倍,尽管您可以轻松地执行类似于1-10的操作。
public static double GetScrollSpeed(DependencyObject obj)
{
return (double)obj.GetValue(ScrollSpeedProperty);
}
public static void SetScrollSpeed(DependencyObject obj, double value)
{
obj.SetValue(ScrollSpeedProperty, value);
}
public static readonly DependencyProperty ScrollSpeedProperty =
DependencyProperty.RegisterAttached(
"ScrollSpeed",
typeof(double),
typeof(ScrollHelper),
new FrameworkPropertyMetadata(
1.0,
FrameworkPropertyMetadataOptions.Inherits & FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
new PropertyChangedCallback(OnScrollSpeedChanged)));
private static void OnScrollSpeedChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
}既然我们有了附加的属性,就需要处理滚动,为此,在OnScrollSpeedChanged中,我们可以处理PreviewMouseWheel事件。我们希望连接到PreviewMouseWheel,因为它是一个隧道事件,在ScrollViewer能够处理标准MouseWheel事件之前就会发生。
目前,PreviewMouseWheel处理程序正在接收我们绑定它的FlowDocumentReader或其他东西,但是我们需要的是ScrollViewer。因为它可以是很多东西: ListBox、FlowDocumentReader、WPF、ScrollViewer等等,所以我们可以做一个简短的方法,使用VisualTreeHelper来完成这个任务。我们已经知道通过的项目将是某种形式的DependancyObject,所以如果存在,我们可以使用一些递归来查找ScrollViewer。
public static DependencyObject GetScrollViewer(DependencyObject o)
{
// Return the DependencyObject if it is a ScrollViewer
if (o is ScrollViewer)
{ return o; }
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++)
{
var child = VisualTreeHelper.GetChild(o, i);
var result = GetScrollViewer(child);
if (result == null)
{
continue;
}
else
{
return result;
}
}
return null;
}
private static void OnScrollSpeedChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var host = o as UIElement;
host.PreviewMouseWheel += new MouseWheelEventHandler(OnPreviewMouseWheelScrolled);
}现在我们可以得到ScrollViwer了,我们终于可以修改滚动速度了。我们需要从正在发送的ScrollSpeed属性中获取DependancyObject属性。此外,我们还可以使用助手方法来获取元素中包含的ScrollViewer。一旦我们有了这两件事,我们就可以获得和修改ScrollViewer的VerticalOffset。我发现,将MouseWheelEventArgs.Delta除以鼠标轮改变的数量,6得到了大约默认的滚动速度。所以,如果我们用我们的ScrollSpeed修饰符乘以它,我们就可以得到新的偏移值。然后,我们可以使用它公开的VerticalOffset方法来设置ScrollViewer的ScrollToVerticalOffset。
private static void OnPreviewMouseWheelScrolled(object sender, MouseWheelEventArgs e)
{
DependencyObject scrollHost = sender as DependencyObject;
double scrollSpeed = (double)(scrollHost).GetValue(Demo.ScrollSpeedProperty);
ScrollViewer scrollViewer = GetScrollViewer(scrollHost) as ScrollViewer;
if (scrollViewer != null)
{
double offset = scrollViewer.VerticalOffset - (e.Delta * scrollSpeed / 6);
if (offset < 0)
{
scrollViewer.ScrollToVerticalOffset(0);
}
else if (offset > scrollViewer.ExtentHeight)
{
scrollViewer.ScrollToVerticalOffset(scrollViewer.ExtentHeight);
}
else
{
scrollViewer.ScrollToVerticalOffset(offset);
}
e.Handled = true;
}
else
{
throw new NotSupportedException("ScrollSpeed Attached Property is not attached to an element containing a ScrollViewer.");
}
}现在我们已经设置了附加属性,我们可以创建一个简单的UI来演示它。我将创建一个ListBox和一个FlowDocumentReaders,这样我们就可以看到ScrollSpeed将如何在多个控件之间受到影响。
<UniformGrid Columns="2">
<DockPanel>
<Slider DockPanel.Dock="Top"
Minimum=".1"
Maximum="3"
SmallChange=".1"
Value="{Binding ElementName=uiListBox, Path=(ScrollHelper:Demo.ScrollSpeed)}" />
<ListBox x:Name="uiListBox">
<!-- Items -->
</ListBox>
</DockPanel>
<DockPanel>
<Slider DockPanel.Dock="Top"
Minimum=".1"
Maximum="3"
SmallChange=".1"
Value="{Binding ElementName=uiListBox, Path=(ScrollHelper:Demo.ScrollSpeed)}" />
<FlowDocumentReader x:Name="uiReader"
ViewingMode="Scroll">
<!-- Flow Document Content -->
</FlowDocumentReader>
</DockPanel>
</UniformGrid>现在,当我们运行时,我们可以使用Sliders来修改每个列的滚动速度,有趣的东西。
发布于 2018-04-24 14:46:00
哇。Rmoore的回答很精彩,但有点复杂。我把它简化了一点。对于那些不使用MVVM或可以将代码放在可以访问目标元素的类中的人来说,这两个方法对您来说就足够了:
将此方法放置到扩展中:
public static DependencyObject GetScrollViewer(this DependencyObject o)
{
// Return the DependencyObject if it is a ScrollViewer
if (o is ScrollViewer)
{ return o; }
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++)
{
var child = VisualTreeHelper.GetChild(o, i);
var result = GetScrollViewer(child);
if (result == null)
{
continue;
}
else
{
return result;
}
}
return null;
}然后将第二个方法放置到访问目标UI元素的类中,并将其订阅到"PreviewMouseWheel“事件。
private void HandleScrollSpeed(object sender, MouseWheelEventArgs e)
{
try
{
if (!(sender is DependencyObject))
return;
ScrollViewer scrollViewer = (((DependencyObject)sender)).GetScrollViewer() as ScrollViewer;
ListBox lbHost = sender as ListBox; //Or whatever your UI element is
if (scrollViewer != null && lbHost != null)
{
double scrollSpeed = 1;
//you may check here your own conditions
if (lbHost.Name == "SourceListBox" || lbHost.Name == "TargetListBox")
scrollSpeed = 2;
double offset = scrollViewer.VerticalOffset - (e.Delta * scrollSpeed / 6);
if (offset < 0)
scrollViewer.ScrollToVerticalOffset(0);
else if (offset > scrollViewer.ExtentHeight)
scrollViewer.ScrollToVerticalOffset(scrollViewer.ExtentHeight);
else
scrollViewer.ScrollToVerticalOffset(offset);
e.Handled = true;
}
else
throw new NotSupportedException("ScrollSpeed Attached Property is not attached to an element containing a ScrollViewer.");
}
catch (Exception ex)
{
//Do something...
}
}发布于 2009-06-09 10:53:23
不要使用滚动事件,而是捕获MouseWheel事件。
<FlowDocumentReader MouseWheel="...">https://stackoverflow.com/questions/876994
复制相似问题