UWP FlipView阻止用户交互

时间:2016-11-30 10:12:35

标签: xaml uwp winrt-xaml uwp-xaml flipview

是的,我已经用Google搜索了,这个解决方案并没有做到这一点:

Disable navigation on FlipView

因为我想继续使用动画更改项目,但只能以编程方式更改。

我调查了FlipView模板,发现所有交互/动画等都是使用ScrollingHost按名称构建的:

<ScrollViewer x:Name="ScrollingHost" AutomationProperties.AccessibilityView="Raw" BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}" HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" HorizontalSnapPointsType="MandatorySingle" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" IsTabStop="False" IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}" IsHorizontalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsHorizontalScrollChainingEnabled}" IsVerticalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsVerticalScrollChainingEnabled}" IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" Padding="{TemplateBinding Padding}" TabNavigation="{TemplateBinding TabNavigation}" VerticalSnapPointsType="MandatorySingle" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}" ZoomMode="Disabled">
    <ItemsPresenter/>
</ScrollViewer>

因此,我创建了一个自定义类MyFlipView并从FlipView派生,并覆盖了MouseWheel(这为我提供了桌面上所需的行为),并从模板中删除了导航按钮(这也限制了用户交互)。但唯一剩下的就是,用户仍然能够通过指针(平板电脑,手机,甚至是带触摸屏的PC)拖动项目。这是我的代码:

public class MyFlipView : FlipView
{
    ScrollViewer scroll;

    public MyFlipView()
    {

    }

    protected override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        scroll = GetTemplateChild("ScrollingHost") as ScrollViewer;
        scroll.HorizontalScrollMode = ScrollMode.Disabled;
        scroll.VerticalScrollMode = ScrollMode.Disabled;
        scroll.VerticalScrollBarVisibility = ScrollBarVisibility.Disabled;
        scroll.HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled;
        scroll.IsHorizontalRailEnabled = false;
        scroll.IsVerticalRailEnabled = false;
        scroll.IsVerticalScrollChainingEnabled = false;
        scroll.IsHorizontalScrollChainingEnabled = false;
        scroll.IsHoldingEnabled = false;
    }

    protected override void OnPointerWheelChanged(PointerRoutedEventArgs e)
    {
        e.Handled = true;
        //base.OnPointerWheelChanged(e);
    }
}

正如您所看到的,我尝试禁用ScrollingHost中的所有滚动,但仍然可以在触摸屏上切换项目。我怎样才能禁用它们?

3 个答案:

答案 0 :(得分:1)

将FlipView的IsHitTestVisible属性设置为false。 然后将KeyboardNavigation.DirectionalNavigation设置为无

这基本上是说“你不能碰我或者标签给我”

Thomas Schneiter的回答仍然允许通过Tabbing /其他有缺陷的导航方法来达到它。

答案 1 :(得分:0)

如果您不需要与FlipView进行任何交互,那么一个简单但又有点丑陋的解决方案就是在FlipView上放置一个(几乎)透明的矩形。

<Grid> 
    <FlipView ... />
    <Rectangle Fill="White" Opacity="0.01" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Grid>

答案 2 :(得分:0)

一年多以后,仍然没有很好的解决方案来禁用FlipView。这就是我最终做的事情,似乎没有创建新的FlipView控件。

编辑ControlTemplate并删除所有导航按钮。为DataTemplate容器添加透明背景。将一个PointerWheelChanged事件处理程序添加到DataTemplate容器并将其设置为e.Handled = true;。最后,将一个SelectionChanged事件处理程序添加到FlipView,并让它将所选项重置为原始项。

XAML

<FlipView x:Name="MyFlipView" ItemsSource="{x:Bind Items,Mode=OneWay}" SelectionChanged="FlipView_SelectionChanged">
    <FlipView.ItemTemplate>
        <DataTemplate>
            <Grid Background="Transparent" PointerWheelChanged="Item_PointerWheelChanged">
                <!--You Item XAML-->
            </Grid>
        </DataTemplate>
    </FlipView.ItemTemplate>
    <FlipView.Template>
        <ControlTemplate TargetType="FlipView">
            <Grid>
                <!--Default ScrollViewer settings omitted, but no changes needed-->
                <ScrollViewer>
                    <ItemsPresenter />
                </ScrollViewer>
            </Grid>
        </ControlTemplate>
    </FlipView.Template>
</FlipView>

背后的代码

private bool _isDisabled;
private object _selectedItem;

public ObservableCollection<object> Items { get; } = new ObservableCollection<object>();

//methods for setting Items, _isDisabled, and _selectedItem omitted

private void Item_PointerWheelChanged(object sender, PointerRoutedEventArgs e)
{
    //this prevents the wheel from changing the items
    e.Handled = _isDisabled;
}

private void FlipView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    //Can't find a way to disable keyboard from changing items so we'll monitor the change and flip it back
    if (_isDisabled)
    {
        this.SetupSelectedItem();
    }
}

private void SetupSelectedItem()
{
    //do a check here to prevent SelectionChanged events from firing.
    if (this.MyFlipView.SelectedItem != _selectedItem)
    {
        this.MyFlipView.SelectedItem = _selectedItem;
    }
}

<强>更新

好的,TouchScreen仍然存在一些问题,所以我又采取了一些措施。我们需要处理两个级别,FlipViewItem和FlipView。不幸的是我们必须对这些进行子类化,因为我们没有任何覆盖可以中断默认行为。我也想使用绑定来打开或关闭翻转。这仅支持水平方向,但可以轻松调整以支持垂直方向。

需要自定义FlipViewItem来控制鼠标和键盘。

public sealed class GalleryFlipViewItem : FlipViewItem
{
    public bool IsFlipEnabled { get; set; }

    protected override void OnKeyDown(KeyRoutedEventArgs e)
    {
        e.Handled = !this.IsFlipEnabled;

        base.OnKeyDown(e);
    }

    protected override void OnPointerWheelChanged(PointerRoutedEventArgs e)
    {
        e.Handled = !this.IsFlipEnabled;

        base.OnPointerWheelChanged(e);
    }
}

需要自定义FlipView来控制触摸并将设置细化到自定义FlipViewItem。

public sealed class GalleryFlipView : FlipView
{
    public static readonly DependencyProperty IsFlipEnabledProperty =
        DependencyProperty.Register("IsFlipEnabled", typeof(bool), typeof(GalleryFlipView), new PropertyMetadata(true, IsFlipEnabledChanged));

    private static void IsFlipEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is GalleryFlipView control)
        {
            if (control.GetTemplateChild("ScrollingHost") is ScrollViewer scrollViewer)
            {
                scrollViewer.HorizontalScrollMode = control.IsFlipEnabled ? ScrollMode.Auto : ScrollMode.Disabled;
            }

            if (control.ContainerFromItem(control.SelectedItem) is GalleryFlipViewItem flipViewItem)
            {
                flipViewItem.IsFlipEnabled = control.IsFlipEnabled;
            }
        }
    }

    public bool IsFlipEnabled
    {
        get { return (bool)GetValue(IsFlipEnabledProperty); }
        set { SetValue(IsFlipEnabledProperty, value); }
    }

    protected override DependencyObject GetContainerForItemOverride()
    {
        return new GalleryFlipViewItem
        {
            IsFlipEnabled = this.IsFlipEnabled
        };
    }
}

现在我们需要为每个控件添加样式。我刚刚复制了FlipViewItem和FlipView的默认样式。我通过移除向上/向下按钮并添加了绑定来控制左/右按钮的可见性,对FlipView进行了一些小调整。为此,将原始按钮包裹在网格中,然后使用转换器将bool转换为可见性枚举。

<Grid HorizontalAlignment="Left" VerticalAlignment="Center" Visibility="{Binding IsFlipEnabled,RelativeSource={RelativeSource TemplatedParent},Converter={StaticResource BooleanToVisibleConverter}}">
    <Button x:Name="PreviousButtonHorizontal" Height="36" IsTabStop="False" Template="{StaticResource HorizontalPreviousTemplate}" UseSystemFocusVisuals="False" Width="20" />
</Grid>
<Grid HorizontalAlignment="Right" VerticalAlignment="Center" Visibility="{Binding IsFlipEnabled,RelativeSource={RelativeSource TemplatedParent},Converter={StaticResource BooleanToVisibleConverter}}">
    <Button x:Name="NextButtonHorizontal" Height="36" IsTabStop="False" Template="{StaticResource HorizontalNextTemplate}" UseSystemFocusVisuals="False" Width="20" />
</Grid>

由于IsFlipEnabled是DependencyProperty,您可以使用绑定,xaml或代码来控制它。

<controls:GalleryFlipView IsFlipEnabled="False">

最后,这似乎是正确的解决方案。令人沮丧的是,我们必须做很多工作来简单地打开和关闭此功能。