我遇到过同样的问题。你至少有两个选择
- 使用 MS Surface 工具包
- 修复 ScrollViewer
我选择了第二个。只需创建一个自定义控件,继承自 ScrollViewer,在 Generic.xaml 中只需要放一个<ContentPresenter />
,仅此而已。真正的工作是在代码背后,但也不那么复杂。我必须检查用户是否触摸了按钮或只是想滚动。诀窍是检查触摸点上的内容并打开/关闭平移模式。
这是代码:
namespace Demo.Controls
{
public class ScrollViewerWithTouch : ScrollViewer
{
private PanningMode panningMode;
private bool panningModeSet;
static ScrollViewerWithTouch()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ScrollViewerWithTouch), new FrameworkPropertyMetadata(typeof(ScrollViewerWithTouch)));
}
protected override void OnManipulationCompleted(ManipulationCompletedEventArgs e)
{
base.OnManipulationCompleted(e);
// set it back
this.PanningMode = this.panningMode;
}
protected override void OnManipulationStarted(ManipulationStartedEventArgs e)
{
// figure out what has the user touched
var result = VisualTreeHelper.HitTest(this, e.ManipulationOrigin);
if (result != null && result.VisualHit != null)
{
var hasButtonParent = this.HasButtonParent(result.VisualHit);
// if user touched a button then turn off panning mode, let style bubble down, in other case let it scroll
this.PanningMode = hasButtonParent ? PanningMode.None : this.panningMode;
}
base.OnManipulationStarted(e);
}
protected override void OnTouchDown(TouchEventArgs e)
{
// store panning mode or set it back to it's original state. OnManipulationCompleted does not do it every time, so we need to set it once more.
if (this.panningModeSet == false)
{
this.panningMode = this.PanningMode;
this.panningModeSet = true;
}
else
{
this.PanningMode = this.panningMode;
}
base.OnTouchDown(e);
}
private bool HasButtonParent(DependencyObject obj)
{
var parent = VisualTreeHelper.GetParent(obj);
if ((parent != null) && (parent is ButtonBase) == false)
{
return HasButtonParent(parent);
}
return parent != null;
}
}
}