Reputation: 19737
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
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
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
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
Upvotes: 0