2011-12-03 19 views
6

Trong WPF tôi đã có XAML sau:Slider ScrollViewer trong một giao diện cảm ứng không hoạt động đúng

<ScrollViewer Canvas.Left="2266" Canvas.Top="428" Height="378" Name="scrollViewer1" Width="728" PanningMode="VerticalOnly" PanningRatio="2"> 
    <Canvas Height="1732.593" Width="507.667"> 
     <Slider Height="40.668" x:Name="slider1" Width="507.667" Style="{DynamicResource SliderStyle1}" Canvas.Left="15" Canvas.Top="150" /> 
     </Slider> 
    </Canvas> 
</ScrollViewer> 

Đó là một ScrollViewer chứa một Slider. Tôi đang sử dụng sau đây trên một màn hình cảm ứng, và tôi đang sử dụng panning thậm chí để di chuyển ScrollViewer theo chiều dọc. Khi PanningMode = "VerticalOnly" được đặt, thanh trượt sẽ ngừng hoạt động!

Tôi giả định ScollViewer đang sử dụng sự kiện touch \ slide và xử lý nó trước khi thanh trượt thực hiện (nhưng tôi nghĩ rằng tôi sai về mặt trước này).

Có cách giải quyết nào cho vấn đề này không?

Trả lời

10

Tôi vừa giải quyết vấn đề này trong ứng dụng của mình.

Điều gì đang xảy ra là ScrollViewer chụp TouchDevice trong trình xử lý PreviewTouchMove của nó, "đánh cắp" TouchDevice từ các điều khiển khác và ngăn chúng nhận bất kỳ sự kiện PreviewTouchMove hoặc TouchMove nào.

Để giải quyết vấn đề này, bạn cần phải thực hiện một điều khiển Thumb tùy chỉnh để nắm bắt TouchDevice trong sự kiện PreviewTouchDown và lưu trữ một tham chiếu đến nó cho đến khi sự kiện PreviewTouchUp xảy ra. Sau đó, điều khiển có thể "ăn cắp" việc nắm bắt lại trong xử lý LostTouchCapture của nó, khi thích hợp. Dưới đây là một số mã ngắn gọn:

public class CustomThumb : Thumb 
{ 
    private TouchDevice currentDevice = null; 

    protected override void OnPreviewTouchDown(TouchEventArgs e) 
    { 
     // Release any previous capture 
     ReleaseCurrentDevice(); 
     // Capture the new touch 
     CaptureCurrentDevice(e); 
    } 

    protected override void OnPreviewTouchUp(TouchEventArgs e) 
    { 
     ReleaseCurrentDevice(); 
    } 

    protected override void OnLostTouchCapture(TouchEventArgs e) 
    { 
     // Only re-capture if the reference is not null 
     // This way we avoid re-capturing after calling ReleaseCurrentDevice() 
     if (currentDevice != null) 
     { 
      CaptureCurrentDevice(e); 
     } 
    } 

    private void ReleaseCurrentDevice() 
    { 
     if (currentDevice != null) 
     { 
      // Set the reference to null so that we don't re-capture in the OnLostTouchCapture() method 
      var temp = currentDevice; 
      currentDevice = null; 
      ReleaseTouchCapture(temp); 
     } 
    } 

    private void CaptureCurrentDevice(TouchEventArgs e) 
    { 
     bool gotTouch = CaptureTouch(e.TouchDevice); 
     if (gotTouch) 
     { 
      currentDevice = e.TouchDevice; 
     } 
    } 
} 

Sau đó, bạn sẽ cần phải định lại Mẫu trượt để sử dụng CustomThumb thay cho điều khiển Thumb mặc định.

+2

Tôi chưa thử nghiệm phương pháp này, nhưng có vẻ đủ hợp lệ. Tôi sẽ chọn nó làm câu trả lời. Cách tôi giải quyết tất cả các vấn đề của tôi là sử dụng Microsoft Surface 2.0 SDK http://www.microsoft.com/download/en/details.aspx?id=26716 và sử dụng ScrollViewer từ thư viện của họ (xử lý tất cả các vấn đề ở trên). – Bassem

+1

Giải pháp này phù hợp với tôi. Nó rất tiện lợi vì tôi đã tái tạo lại Slider để sử dụng Thumb tùy chỉnh với hình dạng/kích thước phù hợp hơn để chạm vào. – tgr42

+0

Cách tiếp cận được cung cấp hoạt động như một sự quyến rũ! Tôi phải đối mặt với vấn đề trong khi loại bỏ (đối với tôi không được chấp nhận) Microsoft Surface 2.0 SDK. – SSchuette

2

tôi có vấn đề tương tự. workaround là một trong những (không ai trong số những người khác làm việc cho tôi): tôi tạo ra một ngón tay cái tùy chỉnh, và sau đó tôi sử dụng nó bên trong một phong cách thanh cuộn trong xaml như ngón tay cái của PART_Track.

public class DragableThumb : Thumb 
{ 
    double m_originalOffset; 
    double m_originalDistance; 
    int m_touchID; 

    /// <summary> 
    /// Get the parent scrollviewer, if any 
    /// </summary> 
    /// <returns>Scroll viewer or null</returns> 
    ScrollViewer GetScrollViewer() 
    { 
     if (TemplatedParent is ScrollBar && ((ScrollBar)TemplatedParent).TemplatedParent is ScrollViewer) 
     { 
      return ((ScrollViewer)((ScrollBar)TemplatedParent).TemplatedParent); 
     } 

     return null; 
    } 

    /// <summary> 
    /// Begin thumb drag 
    /// </summary> 
    /// <param name="e">Event arguments</param> 
    protected override void OnTouchDown(TouchEventArgs e) 
    { 
     ScrollViewer scrollViewer; 

     base.OnTouchDown(e); 

     m_touchID = e.TouchDevice.Id; 

     if ((scrollViewer = GetScrollViewer()) != null) 
     { 
      m_originalOffset = scrollViewer.HorizontalOffset; 
      m_originalDistance = e.GetTouchPoint(scrollViewer).Position.X; 
     } 
    } 

    /// <summary> 
    /// Handle thumb delta 
    /// </summary> 
    /// <param name="e">Event arguments</param> 
    protected override void OnTouchMove(TouchEventArgs e) 
    { 
     ScrollViewer scrollViewer; 
     double actualDistance; 

     base.OnTouchMove(e); 

     if ((scrollViewer = GetScrollViewer()) != null && m_touchID == e.TouchDevice.Id) 
     { 
      actualDistance = e.GetTouchPoint(scrollViewer).Position.X; 
      scrollViewer.ScrollToHorizontalOffset(m_originalOffset + (actualDistance - m_originalDistance) * scrollViewer.ExtentWidth/scrollViewer.ActualWidth); 
     } 
    } 
} 
+0

Cảm ơn, điều này giúp tôi đi đúng hướng cho vấn đề của mình. –

0

Làm việc sau đây cho tôi. Tôi tìm kiếm trong một thời gian dài cho một cái gì đó mà sẽ làm việc. Tôi đã điều chỉnh điều này để liên lạc từ How to make WPF Slider Thumb follow cursor from any point. Đây là bản sửa lỗi đơn giản hơn nhiều và cho phép bạn tránh tạo một điều khiển thanh trượt/ngón tay cái tùy chỉnh.

<Slider TouchMove="OnTouchMove" IsMoveToPointEnabled="True"/> 

IsMoveToPointEnable phải được đặt thành true để hoạt động.

private void Slider_OnTouchMove(object sender, TouchEventArgs e) 
{ 
    Slider slider = (Slider)sender;   
    TouchPoint point = e.GetTouchPoint (slider); 
    double d = 1.0/slider.ActualWidth * point.Position.X; 
    int p = int(slider.Maximum * d); 
    slider.Value = p; 
} 
0

Điều này là tốt đẹp và đơn giản và làm việc cho tôi - mặc dù nó đáng giá trong chức năng chung và mở rộng để xử lý giá trị tối thiểu của thanh trượt cũng có thể không bằng 0. Thật là một nỗi đau phải làm. Có rất nhiều điều về WPF mà là mát mẻ, nhưng rất nhiều điều đơn giản đòi hỏi các bước bổ sung nó thực sự có thể gây bất lợi cho năng suất.

Các vấn đề liên quan