在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事件并在滑块之前处理它(但我认为我在这方面做错了。)
有没有解决方法呢?
答案 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)
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的东西很酷,但是很多简单的东西需要额外的步骤才真正对生产力产生不利影响。