2011-12-03 101 views
6

在WPF我有以下XAML:滑塊 ScrollViewer中的觸摸界面不能正常工作

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

它包含滑塊的ScrollViewer。我在觸摸屏上使用了以下內容,我甚至使用平移來垂直滾動ScrollViewer。當設置PanningMode =「VerticalOnly」時,滑塊停止工作!

我假設ScollViewer正在使用touch \ slide事件並在滑塊之前處理它(但我認爲我在這方面是錯誤的)。

有沒有解決方法?

回答

10

我剛剛在我們的應用程序中解決了這個問題。

發生的事情是ScrollViewer在其PreviewTouchMove處理程序中捕獲TouchDevice,該處理程序從其他控件「竊取」TouchDevice並阻止它們接收任何PreviewTouchMove或TouchMove事件。

爲了解決這個問題,您需要實現一個自定義的Thumb控件,該控件捕獲PreviewTouchDown事件中的TouchDevice並存儲對它的引用,直到發生PreviewTouchUp事件。然後,控件可以在適當的時候將其「捕獲」回收到LostTouchCapture處理程序中。下面是一些簡單的代碼:

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

然後,你將需要重新模板的滑塊使用CustomThumb而不是默認的拇指控制。

+2

我還沒有測試過這種方法,但它看起來足夠有效。我會選擇它作爲答案。我解決所有問題的方式是使用Microsoft Surface 2.0 SDK http://www.microsoft.com/download/en/details.aspx?id=26716,並使用其庫中的ScrollViewer(它處理上述所有問題)。 – Bassem

+1

此解決方案適用於我。這非常方便,因爲我已經將滑塊重新模板化爲使用更適合觸摸的形狀/尺寸的自定義拇指。 – tgr42

+0

提供的方法就像一個魅力!我在刪除(對於我已棄用的​​)Microsoft Surface 2.0 SDK時遇到了問題。 – SSchuette

2

我苦惱了一個類似的問題。解決方法是這一個(其他人都沒有爲我工作):我創建了一個自定義的拇指,然後我用它作爲PART_Track的拇指在xaml中的滾動條樣式。

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

謝謝,這使我在正確的軌道上爲我的問題。 –

0

以下爲我工作。我搜索了很長一段時間才能發揮作用。我從How to make WPF Slider Thumb follow cursor from any point調整了這一點。這是一個更簡單的修復方法,可以避免創建自定義滑塊/滑塊控件。

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

必須將IsMoveToPointEnable設置爲true才能工作。

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

這是不錯的,簡單,對於我的工作 - 雖然它的價值在一個通用的函數進行包裝並延伸到處理滑塊最小值還因爲它可能不是零。但要做到這一點非常痛苦。關於WPF有很多很酷的事情,但很多簡單的事情都需要額外的步驟,它確實會對生產力造成不利影響。