Slider \ ScrollViewer在触摸界面中无法正常工作

时间:2011-12-03 16:22:02

标签: wpf components slider scrollviewer multi-touch

在WPF中,我有以下XAML:

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

这是一个包含Slider的ScrollViewer。我在触摸屏上使用以下内容,我甚至使用平移来垂直滚动ScrollViewer。设置PanningMode =“VerticalOnly”时,滑块停止工作!

我假设ScollViewer正在使用touch \ slide事件并在滑块之前处理它(但我认为我在这方面做错了。)

有没有解决方法呢?

4 个答案:

答案 0 :(得分:11)

我刚刚在我们的应用中解决了这个问题。

发生的事情是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;
        }
    }
}

然后,您需要重新模板Slider以使用CustomThumb而不是默认的Thumb控件。

答案 1 :(得分:2)

我遇到了类似的问题。解决方法就是这个(其他人都没有为我工作):我创建了一个自定义拇指,然后我在xaml的滚动条样式中使用它作为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);
        }
    }
}

答案 2 :(得分: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;
 }

答案 3 :(得分:0)

这很好,很简单,对我有用 - 虽然它值得在一个泛型函数中包含并扩展以处理滑块最小值,因为它可能不是零。尽管如此,还有多痛苦。有很多关于WPF的东西很酷,但是很多简单的东西需要额外的步骤才真正对生产力产生不利影响。