0
votes

I think the present implementation of PivotItem is somewhat inconsistent not to say flawed. If the property Header is set before or after it has been rendered completely the size of the header is set appropriately, however, setting the Header back to null or string.empty does not cause the header to shrink again. Is there an elegant way of hiding and showing a PivotItem header when the Header is set via DataBinding or can a PivotItem be forced to revalidate it's boundaries?

As of now I'm trying "solve" my problem with some rather crude code which includes Events and the complete recreation of the Pivot programmatically and then attach all the PivotItems again. Maybe an OK solution for just page, but certainly somewhat iffy when this needs to be done 10+ times.

[This question has been asked before in a somewhat similiar context, but was never really solved.]

4

4 Answers

1
votes

Are you trying to remove the header for only one item while keeping the other headers? If so, I would not recommend this. It would be very confusing.

If trying to collapse all of them, you can bind the visibility of the PivotHeaderTemplate to a few things. One is the DataContext of your page

<controls:Pivot x:Name="MyPivot" >
    <controls:Pivot.HeaderTemplate>
        <DataTemplate>
            <Grid Visibility="{Binding DataContext.HeaderVisibility, ElementName=MyPivot}">
            <TextBlock Text="{Binding}" FontSize="{StaticResource PhoneFontSizeExtraExtraLarge}" />
            </Grid>
        </DataTemplate>
    </controls:Pivot.HeaderTemplate>

Then you could have a HeaderVisibility property in the viewmodel of your page.

If you want to set the text to null of the headers, you can use a value converter

xaml:

<controls:Pivot x:Name="MyPivot" >
    <controls:Pivot.HeaderTemplate>
        <DataTemplate>
            <Grid Visibility="{Binding Converter={StaticResource TextToVisibilityConverter}}">
            <TextBlock Text="{Binding}" FontSize="{StaticResource PhoneFontSizeExtraExtraLarge}"/>
            </Grid>
        </DataTemplate>
    </controls:Pivot.HeaderTemplate>

And the converter:

public class TextToVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null) return Visibility.Collapsed;

        return (string.InNullOrEmpty(value.ToString()) ? Visibility.Collapsed : Visibility.Visible;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
0
votes

Have you tried also binding the pivot's header height to a property that updates as your header text is set to empty/null (value 0?)

If that works, maybe another thing you could try is binding the Height property to the same value as your header text, along with a converter (pseudo: if text is null then return 0 for height) - that way you don't have an extra property to worry about.

0
votes

What I found is that changing the Visiblity or reducing the header height of a PivotItem simply doesn't work (yet?) on an already rendered item. It's simply broken, but it is possible to circumnavigate those shortcomings by moving the first child element of a PivotItem through changing its top margin to a negative value. Admittedly not elegant, but working. Here is some code:

<phone:PhoneApplicationPage.Resources>
    <local:SubtitleConverter x:Key="SubtitleConverter" />
    <local:MarginConverter x:Key="MarginConverter" />       
</phone:PhoneApplicationPage.Resources>

<controls:PivotItem Name="LayoutItem" Header="{Binding Path=MyProgramSettings.ShowHeader, Converter={StaticResource SubtitleConverter}}">
    <ListBox Margin="{Binding Path=MyProgramSettings.ShowHeader, Converter={StaticResource MarginConverter}}"> 
        <!-- element that is moved up and down depending on some property -->
    </ListBox>
</controls:PivotItem>

Code behind

public class SubtitleConverter : ConverterBase
    {
        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {   
            /* should always return a non empty string, making the PivotItem header height predictable */
            /* needed for MarginConverter */
            return MyProgramSettings.ShowHeader ? " " : MyResource.SomeText.ToLower();
        }
    }

    public class MarginConverter : ConverterBase
    {
        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is bool && (bool)value)
            {
                return new Thickness(12, 0, -28, 0);
            }
            return new Thickness(12, 0, -12, 0);
        }
    }
0
votes

Great idea! I don't use your solution exact, but I was inspired by your idea.

Here is what I did:

1.Create a StackPanel as a container, set the top margin with negative value, such as Margin="0,-35,0,0"

2.Add a few TextBlocks to fake the Pviot Headers, set data binding that you was intended to bind with the Headers.

3.Set TextBlocks Width = "Auto", add a few right Margin so it won't be too crowded

NOTE: When the first TextBlock represent the current PivotItem, the others represent the others -- which are in-activated.

4.For the TextBlocks for in-activated PivotItems, we set the Foreground="#FF727272" to make a distinguish with the activated one. And also add a Event Handler, e.g. Tap="GoToPivot2_Tap" with the simple code behind: PivotRoot.SelectedItem = Pivot2;

<controls:Pivot x:Name="PivotRoot">

    <controls:PivotItem x:Name="Pivot1">
        <StackPanel Margin="0,-35,0,0" Orientation="Horizontal">
            <TextBlock Text="{Binding Header1}" Width="Auto" Margin="0,0,25,0" FontSize="30"/>
            <TextBlock Text="{Binding Header2}" Tap="GoToPivot2_Tap" Width="Auto" Margin="0,0,25,0" Foreground="#FF727272" FontSize="30"/>
            <TextBlock Text="{Binding Header3}" Tap="GoToPivot3_Tap" Width="Auto" Margin="0,0,25,0" Foreground="#FF727272" FontSize="30"/>
        </StackPanel>
    </controls:PivotItem>

    <controls:PivotItem x:Name="Pivot2">
        <StackPanel Margin="0,-35,0,0" Orientation="Horizontal">
            <TextBlock Text="{Binding Header2}" Width="Auto" Margin="0,0,25,0" FontSize="30"/>
            <TextBlock Text="{Binding Header3}" Tap="GoToPivot3_Tap" Width="Auto" Margin="0,0,25,0" Foreground="#FF727272" FontSize="30"/>
            <TextBlock Text="{Binding Header1}" Tap="GoToPivot1_Tap" Width="Auto" Margin="0,0,25,0" Foreground="#FF727272" FontSize="30"/>
        </StackPanel>
    </controls:PivotItem>

    <controls:PivotItem x:Name="Pivot3">
        <StackPanel Margin="0,-35,0,0" Orientation="Horizontal">
            <TextBlock Text="{Binding Header3}" Width="Auto" Margin="0,0,25,0" FontSize="30"/>
            <TextBlock Text="{Binding Header1}" Tap="GoToPivot1_Tap" Width="Auto" Margin="0,0,25,0" Foreground="#FF727272" FontSize="30"/>
            <TextBlock Text="{Binding Header2}" Tap="GoToPivot2_Tap" Width="Auto" Margin="0,0,25,0" Foreground="#FF727272" FontSize="30"/>
        </StackPanel>
    </controls:PivotItem>
</controls:Pivot>

That's it.

Maybe event less elegant than yours, but also works.