Milan Nosáľ
Milan Nosáľ

Reputation: 19737

How to detect a tap on header of currently selected PivotItem

I have a Pivot control. I want a special behavior -- everytime the user taps the header of currently chosen PivotItem, I want to react to that. However, this reaction can not happen when the tapped header does not belong to the currently selected pivot item.

My plan was as follows:

For each PivotItem create a custom header and associate its tap event with a handler:

<phone:PivotItem DataContext="{Binding}" ContentTemplate="{StaticResource MyTemplate}" Content="{Binding}" x:Name="itemA">
    <phone:PivotItem.Header>
        <TextBlock x:Name="headerA" Text="A" Tap = "HeaderA_Tapped"/>
    </phone:PivotItem.Header>
</phone:PivotItem>

And in the handler, test whether the tapped item is currently selected, if yes, react:

protected void HeaderA_Tapped(object sender, GestureEventArgs e)
{
    if (mainPivot.SelectedItem.Equals(itemA))
    {
        //selected item is the same pivotItem that reported tapping event
        react();
    }
}

It seemed pretty straightforward, but after giving it a try I found out that the tap event was reported only AFTER the selection changed event. In cases, where the user taps currently not selected pivotItem header, the pivot will change the selection accordingly (default behavior that I want to keep), and only then it reports the tap event. However, that is too late for my code, because in that moment the tapped header and currently selected item are already the same.

Is there any way how I can detect whether the tap initiated a selection change? Or is there a way to revert the order of events? I guess currently the WP event model sinks the event from the root of Visual Tree down to leafs -> therefore the Pivot gets to handle it sooner, and only then it gets to header TextBlock.

Upvotes: 2

Views: 1329

Answers (3)

Milan Nos&#225;ľ
Milan Nos&#225;ľ

Reputation: 19737

OK, so after some read of my Windows Phone 8 Development Internals book by Andrew Whitechapel and Sean McKenna (do not ask why I did not do it sooner) I got a working solution.

I am not going into full fledged detailed discussion of events, just to point out conclusions relevant to my issue. It seems that in the WP8 event model there are at least two types of events, lower level routed events and logical touch gesture events. The routed events are routed through visual tree from the most concrete element (in my case the header TextBlock control) to the root (therefore Pivot should have get it later). Logical events are not routed, they appear only on a single element (e.g., my TextBlock control), and therefore their handlers have to be registered on the particular element. I assume that the logical events are raised by the element based on the lower level routed event. Applied to my case, it seems that first the lower-level MouseLeftButtonDown (or button up) event was raised, routed to Pivot that used it to change selection, and only then my TextBlock control created the logical Tap event. This would result in behavior that I observed on my emulator. I am not sure about the way how the routed events are really routed and how the logical events are created, so if I made a mistake in my conclusions, please correct me. However, I was able to solve my problem.

Using aforementioned assumptions I decided to listen to lower-level routed events instead of logical tap gesture. Using this MouseLeftButtonUp event I was notified before the new PivotItem was selected, thus giving me chance to check whether the raised MouseLeftButtonUp was originated by currently selected PivotItem.

And so finally the solution:

My XAML Pivot definition (notice that now I am handling MouseLeftButtonUp events on the TextBlock controls, instead of logical Tap events):

<phone:Pivot Title="Pivot" Name="mainPivot">
    <phone:PivotItem DataContext="{Binding A}" ContentTemplate="{StaticResource MyTemplate}" Content="{Binding A}">
        <phone:PivotItem.Header>
             <TextBlock Text="A" MouseLeftButtonUp="HeaderHandlerA"/>
        </phone:PivotItem.Header>
    </phone:PivotItem>

    <phone:PivotItem DataContext="{Binding B}" ContentTemplate="{StaticResource MyTemplate}" Content="{Binding B}">
        <phone:PivotItem.Header>
             <TextBlock Text="B" MouseLeftButtonUp="HeaderHandlerB"/>
        </phone:PivotItem.Header>
    </phone:PivotItem>
</phone:Pivot>

Since I have a different handler for each PivotItem header, I can simply test selected index with a constant. The corresponding handlers in the code-behind:

private void HeaderHandlerA(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
    // HeaderHandlerA is allways called within the first PivotItem,
    // therefore I can just test whether selected index is 0 (index of the first PivotItem)
    if (mainPivot.SelectedIndex == 0)
    {
        OnSelectedItemTapped();
    }
    // else the "tapped" header was not the selected one and I do nothing
}

private void HeaderHandlerB(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
    if (mainPivot.SelectedIndex == 1)
    {
        OnSelectedItemTapped();
    }
}

Maybe not the most elegant solution, but it works...

Upvotes: 0

Bao Nguyen
Bao Nguyen

Reputation: 137

I think you should track Pivot SelectedIndex and update SelectedIndex in Selection_Changed event by using a Timer. Some think like this:

int selectedIndex;
func Selection_ChangedEvent()
{
    //use a timer to update selectedIndex
    //something like: Timer.do(selectedIndex = Pivot.SelectedIndex, 100)
    //fire after a specify time. adjust this for the best result. 
}

And in your tapped event

HeaderA_Tapped()
{
    if(selectedIndex == "index of item A in Pivot")
    {
        react();
    }
}

Upvotes: 1

Ajay
Ajay

Reputation: 6590

Create Pivot selection changed event

<phone:Pivot Title="MY APPLICATION" x:Name="MainPivot" SelectionChanged="Pivot_SelectionChanged">

Add the event handlers to cs file

private void Pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    switch (MainPivot.SelectedIndex)
    {
        case 0:
            // do something
            break;
        case 1:
            //do something
            break;
    }
}

For more details see this search https://www.google.co.in/?gfe_rd=cr&ei=Y1XdVZruLqfG8AfUuquIAQ&gws_rd=ssl#q=wp8+c%23+pivot+selectionchanged

https://social.msdn.microsoft.com/forums/windowsapps/en-US/1baf74fa-0ddd-4226-a02d-a7fc9f80374d/pivot-static-header-like-twitter-app

Upvotes: 0

Related Questions