2011-12-03 62 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有很多很酷的事情,但很多简单的事情都需要额外的步骤,它确实会对生产力造成不利影响。