2009-05-18 4 views
6

ViewingMode = "Scroll"인 FlowDocumentReader에 FlowDocument를 표시하고 있습니다. 마우스에서 휠을 사용하면 문서가 매우 느리게 스크롤됩니다. 스크롤 단계를 늘리고 싶습니다.ViewingMode가 Scroll으로 설정된 경우 FlowDocumentReader의 스크롤 증가량을 조정 하시겠습니까?

  1. 나는 제어판에서 내 마우스의 스크롤 설정을 변경하려고 시도했지만 아무런 효과가 없습니다. 나는 WPF가 FlowDocumentScrollViewer의 설정을 무시한다고 생각한다.

  2. FlowDocument 및 FlowDocumentReader에 Scroll 이벤트를 추가했지만 마우스 휠을 사용할 때 실행되지 않습니다.

  3. 나는 FlowDocumentReader에로드 이벤트를 추가 한, 스크롤 뷰어의 템플릿에서 스크롤바 ("PART_VerticalScrollBar")를 발견하고 SmallChange & LargeChange 속성을 조정의에서 ScrollViewer의 후손을 얻었다. 그것도 아무런 효과가 없었습니다.

누구나 아이디어가 있습니까?

+0

내 대답에 대해 수행해야 할 tweeking이 표준 속도에 대한 '/ 6'인 경우 다른 질문에 답하면서 더 나은 방법을 실감했습니다. 대신 SystemInformation.MouseWheelScrollLines/3 (현재 컴퓨터 설정/기본값)을 곱하면 정적 속도 대신 사용자 마우스 설정에 따라 작동해야합니다. – rmoore

답변

19

Sohnee이 sugested처럼 우리는 컨트롤의 마우스 휠 이벤트에서 이것을 수정할 수 있지만 그것은 단지 하나의 특정 경우에 해결 될 것입니다, 당신은 FlowDocumentReader에 액세스 할 수 있어야 할 것입니다있는 당신의 usinging 경우 MVVM과 비슷합니다. 대신 ScrollViewer를 사용하여 요소에 설정할 수있는 연결된 속성을 만들 수 있습니다. 첨부 된 속성을 정의 할 때 우리는 스크롤 속도에 대한 실제 수정을 수행 할 PropertyChanged 콜백을 원할 것입니다. 또한 속성을 기본값 1로 지정했습니다. 사용할 속도 범위는 .1x에서 3x이지만, 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 이벤트를 처리 할 수 ​​있습니다,이 작업을 수행하기 위해, 스크롤을 처리해야합니다. ScrollViewer가 표준 MouseWheel 이벤트를 처리하기 전에 발생하는 터널링 이벤트이므로 PreviewMouseWheel에 연결하려고합니다.

현재 PreviewMouseWheel 핸들러는 FlowDocumentReader 또는 우리가 바인딩 한 다른 항목을 사용하고 있지만 필요한 것은 ScrollViewer입니다. ListBox, FlowDocumentReader, WPF Toolkit Grid, 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를 얻을 수 있으므로 스크롤 속도를 최종적으로 수정할 수 있습니다. 우리는 보내지는 DependancyObject에서 ScrollSpeed ​​속성을 가져와야합니다. 또한 도우미 메서드를 사용하여 요소 내에 포함 된 ScrollViewer를 가져올 수 있습니다. 이 두 가지가 생기면 ScrollViewer의 VerticalOffset을 가져 와서 수정할 수 있습니다. 마우스 휠이 변경된 MouseWheelEventArgs.Delta를 6으로 나누면 대략 기본 스크롤 속도가된다는 것을 알았습니다. 따라서 ScrollSpeed ​​수정자를 곱하면 새 오프셋 값을 얻을 수 있습니다. 그런 다음 ScrollViewer의 VerticalOffset을 노출하는 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를 만들어서 보여줍니다. ScrollSpeed가 여러 컨트롤에서 어떻게 영향을 받는지 확인할 수 있도록 ListBox 및 FlowDocumentReaders를 만듭니다.

<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> 

이제 실행시 슬라이더를 사용하여 각 열의 재미있는 스크롤 속도를 수정할 수 있습니다.

+1

굉장! MVVM과 비슷한 것을 사용하고있어 귀하의 접근 방식이 완벽하게 작동합니다. 나는 그것을 구현하기를 고대하고있다. 고맙습니다. – Christo

+1

그것은 훌륭하게 작동합니다! 컴파일하고 작동 시키려면 약간만 조정해야했습니다. – Christo

0

scroll 이벤트를 사용하는 대신 MouseWheel 이벤트를 캡처하십시오.

<FlowDocumentReader MouseWheel="..."> 
+0

나는 이것을 시도 할 것이다, 아마 나는 일할 무언가를 얻을 수있다. 나는 많은 코드를 작성하지 않고도 달성하기가 매우 어려울 것이라는 생각에 거의 사임했다. – Christo

관련 문제