【问题标题】:Slider \ ScrollViewer in a touch interface not working properly触摸界面中的 Slider \ ScrollViewer 无法正常工作
【发布时间】:2012-01-12 05:35:12
【问题描述】:

在 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 事件并在滑块之前处理它(但我认为我在这方面错了)。

有什么解决方法吗?

【问题讨论】:

    标签: wpf components slider scrollviewer multi-touch


    【解决方案1】:

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

    发生的情况是 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 控件。

    【讨论】:

    • 我还没有测试过这种方法,但它看起来足够有效。我会选择它作为答案。我解决所有问题的方法是使用 Microsoft Surface 2.0 SDK microsoft.com/download/en/details.aspx?id=26716 并使用他们库中的 ScrollViewer(它可以处理上述所有问题)。
    • 这个解决方案对我有用。这非常方便,因为我已经重新设计了 Slider 模板以使用形状/尺寸更适合触摸的自定义 Thumb。
    • 提供的方法就像一个魅力!我在删除(对我而言已弃用)Microsoft Surface 2.0 SDK 时遇到了问题。
    【解决方案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);
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      以下内容对我有用。我搜索了很长时间,以寻找可行的方法。我从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;
       }
      

      【讨论】:

        【解决方案4】:

        这很好,很简单,对我有用 - 尽管它值得包含在一个通用函数中并扩展以处理滑块最小值,因为它可能不为零。不得不这样做是多么痛苦。 WPF 有很多很酷的东西,但是很多简单的东西需要额外的步骤,这确实会损害生产力。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-07-28
          • 1970-01-01
          • 1970-01-01
          • 2016-12-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多