Position of ItemClick event on a ListView Windows Phone 8.1
Asked Answered
A

3

14

I have a ListView which shows the products in a shopping cart. The datatemplate defines an increment and a decrement amount button for each product.

If the user wants to tap one of these buttons, there's a chance that they tap next to the button, so the ItemClick event will be triggered. I want to disable ItemClick in the area of the button. I had an idea to get the position where the ItemClick event occurred, and determine if it's in the disabled area which I defined.

Is it possible? Any other idea?

Antiworld answered 17/7, 2015 at 11:14 Comment(0)
M
7

There's a simple way to do this. Use an element as the "disabled area" around these increment/decrement buttons. In the ItemClick handler, say if (e.OriginalSource == **the element which is the disabled area**) return;.

This works, because the ItemClickedEventArgs is a RoutedEventArgs which always contains the element where it originated from. See https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.controls.itemclickeventargs

Musculature answered 27/7, 2015 at 9:23 Comment(2)
Thank you! It's indeed a really simple, elegant solution!Antiworld
e.OriginalSource is always ListView for me, how did you get the "disabledArea" ?Mowry
C
2

Why doing it the hard way?

You can change the DataTemplate in a way that each ListViewItem gets divided into two parts, "change amount part" and "item's info part" :

    <ListView ItemClick="OnItemClick">
        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ListViewItem">
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*"/>
                                    <ColumnDefinition Width="100"/>
                                </Grid.ColumnDefinitions>
                                <!-- This is the item's info part -->
                                <StackPanel Orientation="Horizontal" Grid.Column="0" >
                                    <TextBlock Text="{Binding Title}" />
                                    <TextBlock Text="{Binding Qnty}" />
                                </StackPanel>
                                <!-- This is the change amount part -->
                                <StackPanel Tag="Oops!" Orientation="Horizontal" Grid.Column="1" >
                                    <Button Content="▲" />
                                    <Button Content="▼" />
                                </StackPanel>
                            </Grid>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ListView.ItemContainerStyle>
    </ListView>

Now you can try one of the following ways to handle ItemClick properly:

First solution: You can find out what was the OriginalSource that raised the ItemClick event. if it was the "change amount part", then user probably tapped it by mistake and the event should be cancelled, if it was "item's info part" then the event should be raised:

    private void OnItemClick(object sender, ItemClickEventArgs e)
    {
        var tag = ((FrameworkElement)e.OriginalSource).Tag;

        if (tag != null && tag.ToString() == "Oops!")
        {
            return;
        }
        //else: do whatever needs to be done on item click
    }

Second solution: You can set the ListView to SelectionMode="None" and IsItemClickEnabled="False", and then I added Tapped handlers for each element manually (e.g. ItemTapped for item's info part and OnIncreaseTapped and OnDecreaseTapped for the buttons):

    <ListView ItemClick="OnItemClick" SelectionMode="None" IsItemClickEnabled="False">
         ...
                                <!-- This is the item's info part -->
                                <StackPanel Orientation="Horizontal" Tapped = "OnItemTapped" Grid.Column="0" >
                                    <TextBlock Text="{Binding Title}" />
                                    <TextBlock Text="{Binding Qnty}" />
                                </StackPanel>
                                <!-- This is the change amount part -->
                                <StackPanel Tag="Oops!" Orientation="Horizontal" Grid.Column="1" >
                                    <Button Content="▲" Tapped = "OnIncreaseTapped"/>
                                    <Button Content="▼" Tapped = "OnDecreaseTapped"/>
                                </StackPanel>
                            </Grid>

Third solution: Why even let user to tap the wrong area? I'd rather get rid of this area by using an ItemTemplate like this:

enter image description here

instead of this:

enter image description here

Christlike answered 27/7, 2015 at 9:56 Comment(0)
H
0

Suggestion 1
You might be able to listen to ManipulationStarted root of the DataTemplate and check the e.Position in the event handler if the input was near the buttons. If it's too close set a bool like IsCloseToStepperButtons to true and check for that bool in the ItemClick event handler.

Haven't tested this, but I think the events are fired in the desired order.

Suggestion 2
You could skip the whole ItemClick event and add an event listener to the other part of the DataTemplate. Put a margin between the two parts to prevent accidental clicks.

Hoashis answered 21/7, 2015 at 13:2 Comment(1)
Unfortunately it's not working. The ManipulationStarted event is not firing.Antiworld

© 2022 - 2024 — McMap. All rights reserved.