I want to change the default text style (foreground color, font weight, etc) for pivot item header text when the header is selected.
E.g., if I have the following:
<Pivot>
<PivotItem Header="One"></PivotItem>
<PivotItem Header="Two"></PivotItem>
</Pivot>
I want the selected pivot item to be bolded when selected and/or change the foreground color (or maybe put the text in a border, etc). I don't want to change the default style for the unselected items.
Thanx,
The XAML framework offers many ways to customize the appearance of your apps. Styles let you set control properties and reuse those settings for a consistent appearance across multiple controls. You create a control template when you want to customize a control's visual structure and visual behavior.
You don't need to put the text of pivot header in a border, edit the Style for PivotHeaderItem would be a good choice, and you can add this style to the Resources of the Page.
Resources are typically definitions of some object that you expect to use more than once.
There is a default PivotHeaderItem styles and templates, you can copy it and add this to you page resources just like this:
<Page
x:Class="..."
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<Style TargetType="PivotHeaderItem">
...
</Style>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
...
</Grid>
</Page>
Now if you want to change the foreground of the text in header when the item is selected, you can edit the <VisualState x:Name="Selected"> like this:
<VisualState x:Name="Selected">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0" Value="Red" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Grid" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightTransparentBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
If you want to change the text of header to be bold, you can edit above VisualState like this:
<VisualState x:Name="Selected">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="FontWeight">
<DiscreteObjectKeyFrame KeyTime="0" Value="Bold" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Grid" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightTransparentBrush}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
You can leave other VisualStates as defalut, if you just want to change the style when the item is selected.
In XAML
<Pivot SelectionChanged="Pivot_SelectionChanged">
<PivotItem>
<PivotItem.Header>
<TextBlock Text="One"></TextBlock>
</PivotItem.Header>
</PivotItem>
<PivotItem>
<PivotItem.Header>
<TextBlock Text="Two"></TextBlock>
</PivotItem.Header>
</PivotItem>
</Pivot>
In C#
private void Pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Pivot pivot = sender as Pivot;
PivotItem pivotItemSelected = ((PivotItem) ((Pivot) sender).SelectedItem);
for (int i = 0; i < pivot.Items.Count; i++)
{
PivotItem pivotItem = pivot.Items[i] as PivotItem;
TextBlock tb = pivotItem.Header as TextBlock;
if (pivotItem == pivotItemSelected)
{
//Style
tb.Foreground = new SolidColorBrush(Colors.Blue);
}
else
{
tb.Foreground = new SolidColorBrush(Colors.Black);
}
}
}
I hope this can help you
Related
I am trying to create a different template for a list view item when it is selected, however I couldn't find anything about doing this.
What is the best way to select a template based on whether the listview item is selected or not?
What is the best way to select a template based on whether the listview item is selected or not?
Changing the default template and customize animation inside VisualState is the right way.
Copy and paste the default ListViewItem styles and templates in your project, see here
Change the brush in the Selected and PointerOverSelected visual states:
SystemControlHighlightListAccentLowBrush in the Selected visual state:
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderBackground" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListAccentLowBrush}" />
</ObjectAnimationUsingKeyFrames>
Change to:
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderBackground" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="Red" />
</ObjectAnimationUsingKeyFrames>
SystemControlHighlightListAccentMediumBrush in the PointerOverSelected visual state:
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderBackground" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightListAccentMediumBrush}" />
</ObjectAnimationUsingKeyFrames>
Change to:
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderBackground" Storyboard.TargetProperty="Fill">
<DiscreteObjectKeyFrame KeyTime="0" Value="Red" />
</ObjectAnimationUsingKeyFrames>
Screenshot:
Check my completed sample here
-----Update(09/27/2016)-----
How would I use this to change the DataTemplate of a ListBoxItem when it's selected
If you need to switch DataTemplate, you might change it from code behind.
1) Append a DataTeemplate in the page's resource:
<Page.Resources>
<DataTemplate x:Key="dataTemplate1">
<StackPanel Orientation="Horizontal">
<TextBlock Text="->" />
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
</Page.Resources>
2) Add handler for SelectionChanged event:
<ListView SelectionChanged="ListView_SelectionChanged">
<ListView.Items>
<ListViewItem Content="One"></ListViewItem>
<ListViewItem Content="Two"></ListViewItem>
<ListViewItem Content="Three"></ListViewItem>
</ListView.Items>
</ListView>
3) Change DataTemplate from code behind
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
//Assign DataTemplate for selected items
foreach (var item in e.AddedItems)
{
ListViewItem _lvi = item as ListViewItem;
_lvi.ContentTemplate = (DataTemplate)this.Resources["dataTemplate1"];
}
//Remove DataTemplate for unselected items
foreach (var item in e.RemovedItems)
{
ListViewItem _lvi = item as ListViewItem;
_lvi.ContentTemplate = null;
}
}
Have updated my demo: LINK
Below given code is used for toggling images. It works but when I click on button white rectangle is shown as a foreground of button. Is there any better way?
private void music_click(object sender, RoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine("music clickedddd");
switch (key)
{
case 1:
var brush = new ImageBrush();
BitmapImage image = new BitmapImage(new Uri(#"Images/music pause button.png", UriKind.Relative));
brush.ImageSource = image;
music.Background = brush;
key = 0;
System.Diagnostics.Debug.WriteLine("music clickedddd pause");
break;
case 0:
var brush2 = new ImageBrush();
BitmapImage image2 = new BitmapImage(new Uri(#"Images/Music on.png", UriKind.Relative));
brush2.ImageSource = image1;
music.Background = brush2;
key = 1;
System.Diagnostics.Debug.WriteLine("music clickedddd play");
break;
}
}
I recommend styling your ToggleButton to show two different VisualStates for the two cases "paused" and "running" (The ToggleButton control supports the two VisualStates "Checked" and "Unchecked").
How would I do this?
Well I tried the following code and it works:
<UserControl
x:Class="SilverlightApplication2.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Resources>
<ControlTemplate x:Key="MySpecialToggleButton" TargetType="ToggleButton">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CheckStates">
<VisualState x:Name="Checked">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="RunningIcon">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="PausedIcon">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Unchecked"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Image x:Name="PausedIcon" Source="/SilverlightApplication2;component/assets/paused.png" Visibility="Visible" Width="16" Height="16"/>
<Image x:Name="RunningIcon" Source="/SilverlightApplication2;component/assets/running.png" Visibility="Collapsed" Width="16" Height="16"/>
</Grid>
</ControlTemplate>
</UserControl.Resources>
<ToggleButton Height="20" Width="20" Template="{StaticResource MySpecialToggleButton}"/>
I assume you still want to handle the toggling to start playing music or stop it, well you can still handle the click in code behind but you won't have to change the button appearance anymore. And you do not have to track whether the button is toggled or not (your variable named "key"), you can always ask your button if it is checked or unchecked. And you do not need to aks it, just use the specialized ToggleButton events "Checked" and "Unchecked".
You should try using StoryBorads (http://msdn.microsoft.com/en-us/library/ms742868(v=vs.110).aspx) for this type of animation.
I want to write a custom control and want it to have different Padding if the page is Portrait or Snapped. I noticed that pages inherit from LayoutAwarePage which creates support for the following view states:
FullScreenLandscape
Filled
FullScreenPortrait
Snapped
Do I need to add similar code to my new control (It inherits from Control). If not, why does LayoutAwarePage have to do this? Also, Can I just stick the following VisualStateManager into the ControlTemplate of my control and get it to respect the page layout or is this too easy.
<VisualStateGroup x:Name="ApplicationViewStates">
<VisualState x:Name="FullScreenLandscape"/>
<VisualState x:Name="Filled"/>
<VisualState x:Name="FullScreenPortrait">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Padding">
<DiscreteObjectKeyFrame KeyTime="0" Value="1,2,3,4"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Snapped">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Padding">
<DiscreteObjectKeyFrame KeyTime="0" Value="5,6,7,8"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
EDIT : It looks like controls do not support these states by default and they have to be added. It also appears that ButtonBase does support these states because it uses them in its style.
If you look on the default "details" page within the windows 8 projects you'll find that it expects you to subscribe to the events on the page. You'll find the following within the flipview's ItemTemplate:
<FlipView.ItemTemplate>
<UserControl Loaded="StartLayoutUpdates" Unloaded="StopLayoutUpdates">
<ScrollViewer x:Name="scrollViewer" Style="{StaticResource HorizontalScrollViewerStyle}"
<!-- "Child Controls Here" -->
<VisualStateManager.VisualStateGroups>
<!-- "Visual states manuiplating the child controls above" -->
</VisualStateManager.VisualStateGroups>
</ScrollViewer>
</UserControl>
</FlipView.ItemTemplate>
What I do with my user controls is to have them inherit LayoutAwarePage. Next place the content in a grid and move the VisualStateGroup inside this grid. Hope this helps, it works for me.
I have created a HeaderTemplate for my accordions where I want to display a text block on one side of the header and a hyperlink on the right side. The display is working correctly, but the click event is not called when the user clicks, I'm guessing b/c the header itself is trapping the click for expand/contract.
<layoutToolkit:Accordion>
<layoutToolkit:AccordionItem IsSelected="True">
<layoutToolkit:AccordionItem.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Height="20">
<TextBlock Margin="0,0,700,0">Cancel Postcards</TextBlock>
<HyperlinkButton Content="Next Call" Foreground="Blue" Click="NextCancel_Click" />
</StackPanel>
</DataTemplate>
</layoutToolkit:AccordionItem.HeaderTemplate>
..... more code ....
Is there a way to get the hyperlink to respond to events without practically creating a new control?
Update: It looks like the header sets all child controls to disabled when expanded which is why the link doesnt work. It will work when you collapse that accordionitem. So, the question now is, how do i prevent the hyperlink from being disabled?
Hey Charlie, I just happened to answer this same question for Epic720. You have to change the Locked VisualState.
Interactive items in Silverlight Accordion Header
Here is the LockedStates VisualStateGroup of the AccordionItem which you should alter. I can post the whole style if you need, though it's quite verbose.
<VisualStateGroup x:Name="LockedStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Locked">
<Storyboard>
<!--
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="IsEnabled" Storyboard.TargetName="ExpanderButton">
<DiscreteObjectKeyFrame KeyTime="0" Value="False"/>
</ObjectAnimationUsingKeyFrames>
-->
</Storyboard>
</VisualState>
<VisualState x:Name="Unlocked">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="IsEnabled" Storyboard.TargetName="ExpanderButton">
<DiscreteObjectKeyFrame KeyTime="0" Value="True"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
I would like to have an item's width shrink on a click of a button.
Right now I have two objects basically, when you click the button on objectA, a storyboard starts that rotates it around the x-axis and collapses it. Then it shows objectB by setting it's visibility to visible and rotates it around into view.
All I want to add is setting the width smaller while the storyboard is happening to objectA and objectB and then setting it back to normal at the end of the storyboard.
I tried setting the Thickness but I got a compile-time error complaining that it was readonly.
<ObjectAnimationUsingKeyFrames
BeginTime="00:00:00"
Storyboard.TargetName="objectA"
Storyboard.TargetProperty="(UIElement.Margin)">
<DiscreteObjectKeyFrame KeyTime="00:00:00">
<DiscreteObjectKeyFrame.Value>
<Thickness Left="10" Right="10"/>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
I have a simple layout for now...
Here is my UI XAML:
<StackPanel>
<Border x:Name="objectA" BorderBrush="Blue" BorderThickness="1" Height="100" Width="100">
<StackPanel>
<TextBox Margin="10"></TextBox>
<Button Width="50" x:Name="btn1" Content="Flip" Click="btn1_Click"/>
</StackPanel>
<Border.Projection>
<PlaneProjection RotationX="0"></PlaneProjection>
</Border.Projection>
</Border>
<Border Visibility="Collapsed" x:Name="objectB" BorderBrush="Red" BorderThickness="1" Height="100" Width="100">
<StackPanel>
<TextBox Margin="10"></TextBox>
<Button Width="50" x:Name="btn2" Content="Flip" Click="btn2_Click"/>
</StackPanel>
<Border.Projection>
<PlaneProjection RotationX="90"></PlaneProjection>
</Border.Projection>
</Border>
Here is the storyboard...
<Storyboard x:Name="Storyboardtest">
<DoubleAnimation BeginTime="00:00:00"
Storyboard.TargetName="objectA"
Storyboard.TargetProperty="(UIElement.Projection).(RotationX)"
From="0" To="-90">
</DoubleAnimation>
<ObjectAnimationUsingKeyFrames
BeginTime="00:00:01"
Storyboard.TargetName="objectA"
Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00">
<DiscreteObjectKeyFrame.Value>
<Visibility>Collapsed</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames
BeginTime="00:00:01"
Storyboard.TargetName="objectB"
Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation BeginTime="00:00:01"
Storyboard.TargetName="objectB"
Storyboard.TargetProperty="(UIElement.Projection).(RotationX)"
From="90" To="0">
</DoubleAnimation>
</Storyboard>
If it is just the visual width you want to affect, add the following to your storyboard. It will give the appearance of the controls moving into the distance and back as it flips:
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)" Storyboard.TargetName="objectA">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="0.5"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)" Storyboard.TargetName="objectB">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="0.5"/>
<EasingDoubleKeyFrame KeyTime="0:0:2" Value="1"/>
</DoubleAnimationUsingKeyFrames>
you will also need to add the following as I used Expression blend to add the animation and it adds any required elements automatically:
<Border x:Name="objectA" BorderBrush="Blue" BorderThickness="1" Height="100" Width="100" RenderTransformOrigin="0.5,0.5">
<Border.RenderTransform>
<CompositeTransform/>
</Border.RenderTransform>
[Snip]
<Border Visibility="Collapsed" x:Name="objectB" BorderBrush="Red" BorderThickness="1" Height="100" Width="100" RenderTransformOrigin="0.5,0.5">
<Border.RenderTransform>
<CompositeTransform/>
</Border.RenderTransform>
The problem is that both the Width and Margin properties are not DependencyProperties so they can not be animated. On workaround method to accomplish this involves adding some custom DependencyProperties to your user control code-behind which can be hooked up to the storyboard and can in turn manipulate the actual properties of the objects.
For example you could add this DependencyProperty to your UserControl which basically allow the setting of the Width property of object A:
public static readonly DependencyProperty ObjectWidthProperty = DependencyProperty.Register(
"ObjectWidth",
typeof(double),
typeof(MainPage),
new PropertyMetadata(50.0, new PropertyChangedCallback(OnObjectWidthChanged)));
public double ObjectWidth
{
get { return (double)GetValue(ObjectWidthProperty); }
set { SetValue(ObjectWidthProperty, value); }
}
private static void OnObjectWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((MainPage)d).OnObjectWidthChanged(e);
}
private void OnObjectWidthChanged(DependencyPropertyChangedEventArgs e)
{
this.objectA.Width = this.ObjectWidth;
}
You could then add the following to your storyboard which would animate the width of objectA from 50 pixels down to 0:
<DoubleAnimation BeginTime="00:00:00"
Storyboard.TargetName="MyControl"
Storyboard.TargetProperty="ObjectWidth"
From="50" To="0"/>
The would also require you to add x:Name="MyControl" to your top-level UserControl. It's a little bit hacky, but it works to animate some of the underlying properties of elements that don't happen to be DependencyPropertys.