RightTapped not fired on Metro ListViewItem if ListView in other than “None” selection mode

▼魔方 西西 提交于 2019-12-04 12:53:49

I believe I solved the problem by subclassing both ListView and ListViewItem classes.

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>

By this simple approach MyListView_RightTapped handler is called even if SelectionMode is set to 'Single', 'Multiple' or 'Extended'. Next question however is whether this small victory leads to a good design of the application UI. I will not try to answer that question here...

You can use PointerPressed/PointerReleased events on the GridViewItem to get the same effect you would otherwise get from RightTapped or 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");
    }
}

Output:

Press Release Press Release

*EDIT

Sorry, I must have missed it somehow that these events work differently with touch and mouse. I think the answers you got might be the best you will get. Otherwise - you would need to implement your own version of a ListView. You could try pressuring them with hope to get a better solution in one of the future releases, but I would not hope for much there. From what I remember - ContextMenus are not very metro and there are better UX solutions than right-click menus. You can display the commands in the AppBar or on a details page that opens after you select an item. That could work better than trying to hack a workaround for something that was never designed to be supported.

I took @Jan Zeman's idea ( upvoted, by the way ;) ) and improved it a bit.

A few problems with the original approach:

  • The event handler will have to set e.Handled = true, or else the event will bubble up, until the Page itself handles the right tap event - and consequently opens the app bar.
  • If no one's listening to this event, then the event will always bubble up and reach the Page.
  • The event handler will be fired when a right tap occurs on a list's item OR on the white space surrounding the items.

This approach solves the problems above:

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;
    }
}

Now you can subscribe to the ItemRightTapped event instead, which will be triggered if and only if an item is right tapped.

The item will mark the event as unhandled, the list will let you handle the event, and then mark it as handled - preventing it from bubbling up and hitting the Page.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!