如果ListView不是“无”选择模式,则RightTapped不会在Metro ListViewItem上触发

时间:2012-05-07 23:53:56

标签: c# xaml windows-8 windows-runtime winrt-xaml

问题与此处描述的几乎相同:http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/542b827a-7c8e-4984-9158-9d8479b2d5b1但我对那里接受的答案感到不满意,并认为必须有更好的解决方案......

我正在尝试在列表视图上实现'clasic'上下文菜单(不是通过AppBar,而是通过PopupMenu)并且工作正常,但是只有将列表视图设置为“无”SelectionMode时才会生效。

上面的链接正确地解释了如果ListView设置为“无”选择模式以外的ListViewItem'吞下'右侧轻敲事件。如何覆盖此行为,以便列表视图项被选中,列表视图仍然会触发我可以响应的RightTapped事件?

3 个答案:

答案 0 :(得分:7)

我相信我通过继承ListView和ListViewItem类来解决问题。

public class MyListView : ListView
{
    protected override DependencyObject GetContainerForItemOverride()
    {
        return new MyListViewItem();
    }
}

public class MyListViewItem : ListViewItem
{
    protected override void OnRightTapped(Windows.UI.Xaml.Input.RightTappedRoutedEventArgs e)
    {
        base.OnRightTapped(e);
        e.Handled = false; // Stop 'swallowing' the event
    }
}

<CustomControls:MyListView
    x:Name="MyListView"
    ...
    SelectionMode="Single"
    RightTapped="MyListView_RightTapped">
</CustomControls:MyListView>

通过这种简单的方法,即使SelectionMode设置为“Single”,“Multiple”或“Extended”,也会调用MyListView_RightTapped处理程序。然而,接下来的问题是这个小小的胜利是否会导致应用程序UI的良好设计。我不会试图在这里回答这个问题......

答案 1 :(得分:1)

您可以在GridViewItem上使用PointerPressed / PointerReleased事件来获得与RightTapped或ManipulationCompleted相同的效果。

    <ListView
        Margin="120,80,0,0"
        SelectionMode="Multiple">
        <ListView.ItemContainerStyle>
            <Style
                TargetType="ListViewItem">
                <Setter
                    Property="Width"
                    Value="100" />
                <Setter
                    Property="Height"
                    Value="100" />
            </Style>
        </ListView.ItemContainerStyle>
        <ListViewItem
            RightTapped="ListViewItem_RightTapped_1"
            PointerPressed="ListViewItem_PointerPressed_1"
            PointerReleased="ListViewItem_PointerReleased_1"
            ManipulationStarted="ListViewItem_ManipulationStarted_1">
            <Rectangle
                Height="80"
                Width="80"
                Fill="Red" />
        </ListViewItem>
    </ListView>

    private void ListViewItem_RightTapped_1(object sender, RightTappedRoutedEventArgs e)
    {
        Debug.WriteLine("Tap");
    }

    private void ListViewItem_PointerPressed_1(object sender, PointerEventArgs e)
    {
        Debug.WriteLine("Press");
    }

    private void ListViewItem_ManipulationStarted_1(object sender, ManipulationStartedRoutedEventArgs e)
    {
        Debug.WriteLine("Manipulating");
    }

    private void ListViewItem_PointerReleased_1(object sender, PointerEventArgs e)
    {
        Debug.WriteLine("Release");
    }
}

输出:

按 发布 按 释放

*编辑

抱歉,我一定错过了这些事件,这些事件与触摸和鼠标的工作方式不同。我认为你得到的答案可能是你得到的最好的答案。否则 - 您需要实现自己的ListView版本。您可以尝试向他们施加压力,希望在未来的某个版本中获得更好的解决方案,但我不希望那里有太多。从我记忆中来看 - ContextMenus不是非常地铁,并且有比右键菜单更好的UX解决方案。您可以在AppBar中或在选择项目后打开的详细信息页面上显示命令。这可能比尝试破解从未设计为支持的东西的解决方法更好。

答案 2 :(得分:0)

我接受了@Jan Zeman的想法(顺便说一句,赞成;))并对其进行了一些改进。

原始方法存在一些问题:

  • 事件处理程序必须设置e.Handled = true,否则事件将冒出来,直到Page本身处理正确的点击事件 - 并因此打开应用栏。
  • 如果没有人在听这个事件,那么该事件将始终冒泡并到达Page
  • 当项目周围的空白处的列表项上发生右键时,将触发事件处理程序。

这种方法解决了上述问题:

public class MyListView : ListView
{
    public event RightTappedEventHandler ItemRightTapped;

    protected override DependencyObject GetContainerForItemOverride()
    {
        var item = new MyListViewItem();
        item.RightTapped += OnItemRightTapped;
        return item;
    }

    protected virtual void OnItemRightTapped(object sender, RightTappedRoutedEventArgs args)
    {
        if (ItemRightTapped != null)
            ItemRightTapped(sender, args);
        args.Handled = true;
    }
}

public class MyListViewItem : ListViewItem
{
    protected override void OnRightTapped(RightTappedRoutedEventArgs e)
    {
        base.OnRightTapped(e);

        // Stop 'swallowing' the event
        e.Handled = false;
    }
}

现在您可以订阅ItemRightTapped事件,当且仅当项目被右键点击时才会触发。

该项目将事件标记为未处理,该列表将允许您处理事件,然后将其标记为已处理 - 防止它冒泡并点击Page