WinRT - border hover change opacity - xaml

I would like to add a hover effect to the border that I've created as below.
<Border x:Name="borderHeader" Background="#000000" Height="100" VerticalAlignment="top" Opacity="0.5" HorizontalAlignment="Left" Width="1366">
And my visual state code as below.
<VisualStateManager.VisualStateGroups>
<VisualState x:Name="PointerOver">
<Storyboard>
<DoubleAnimation Duration="0" To="1.0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="borderHeader"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
How ever it's not working.
Please advise which part I have did wrongly.
Thanks

Visual states can be applied to those controls which are inside ControlTemplate. Border is stand alone control. So you need to rely on PointerEntered & PointerExited events.
XAML
<Border x:Name="borderHeader" Background="Yellow" Height="100" VerticalAlignment="top" Opacity="0.5" HorizontalAlignment="Left" Width="1366"
PointerEntered="borderHeader_PointerEntered_1" PointerExited="borderHeader_PointerExited_1"/>
C#
private void borderHeader_PointerEntered_1(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
borderHeader.Opacity = 1;
}
private void borderHeader_PointerExited_1(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
{
borderHeader.Opacity = 0.5;
}

Related

Access ContentPresenter children for Visualstate animation

I'm using the following GridView and have an ItemTemplate with 3 Elements inside.
Now what i would like to do, is to animate the MyTextBlock opacity on PointerOver from the GridViewItem.
<GridView x:Name="MyList" ItemContainerStyle="{StaticResource GridViewItemContainerStyle}" ItemsSource="{Binding MyList}">
<GridView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="200" />
<RowDefinition Height="3" />
<RowDefinition Height="80" />
</Grid.RowDefinitions>
<Image Grid.Row="0" Source="{Binding Url}" />
<ProgressBar Grid.Row="1" IsIndeterminate="True" />
<TextBlock Name="MyTextBlock" Opacity="0" Text="Test" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
The ItemContainerStyle is like this. Problem is, i can't access MyTextBlock with Storyboard.TargetName="MyTextBlock" from here since it's inside the ContentPresenter.
How can i do a visualstate animation of an element inside the ContentPresenter?
<Style TargetType="GridViewItem" x:Key="GridViewItemContainerStyle">
...
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="GridViewItem">
<Grid x:Name="ContentBorder" Control.IsTemplateFocusTarget="True" RenderTransformOrigin="0.5,0.5">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard>
<PointerUpThemeAnimation Storyboard.TargetName="ContentPresenter" />
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOver">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="BorderRectangle" Storyboard.TargetProperty="Opacity" Duration="0" To="1" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Rectangle x:Name="BorderRectangle" Fill="{ThemeResource SystemControlHighlightListAccentLowBrush}" Opacity="0" />
<ContentPresenter x:Name="ContentPresenter" ContentTransitions="{TemplateBinding ContentTransitions}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="{TemplateBinding Padding}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Edit:
I tried using the following TargetProperty, but it's just setting the opacity of the whole ContentPresenter
and not just TextBlock inside of it.
<DoubleAnimation Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="(TextBlock.Opacity)" Duration="0" To="1" />
Problem is, i can't access MyTextBlock with Storyboard.TargetName="MyTextBlock" from here since it's inside the ContentPresenter. How can i do a visualstate animation of an element inside the ContentPresenter?
You can add two visualstates inside DataTemplate(PointerEntered and PointerExited):
<GridView x:Name="MyList" Grid.Row="1" ItemContainerStyle="{StaticResource GridViewItemContainerStyle}" >
<GridView.ItemTemplate>
<DataTemplate>
<Grid PointerExited="Grid_PointerExited" PointerEntered="Grid_PointerEntered">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="PointerEntered">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="MyTextBlock" Storyboard.TargetProperty="Opacity" Duration="0" To="1" />
</Storyboard>
</VisualState>
<VisualState x:Name="PointerExited">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="MyTextBlock" Storyboard.TargetProperty="Opacity" Duration="0" To="0" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.RowDefinitions>
<RowDefinition Height="200" />
<RowDefinition Height="3" />
<RowDefinition Height="80" />
</Grid.RowDefinitions>
<Image Grid.Row="0" Source="{Binding Url}" />
<ProgressBar Grid.Row="1" IsIndeterminate="True" />
<TextBlock Grid.Row="2" Name="MyTextBlock" Opacity="0" Text="Test" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
And using the following codes in Grid.PointerEntered and Grid.PointerExited events to get the storyboard start:
private void Grid_PointerExited(object sender, PointerRoutedEventArgs e)
{
Grid grid = sender as Grid;
var visualStateGroups = VisualStateManager.GetVisualStateGroups(grid);
var visualStateGroup = visualStateGroups[0];
visualStateGroup.States[1].Storyboard.Begin();
}
private void Grid_PointerEntered(object sender, PointerRoutedEventArgs e)
{
Grid grid = sender as Grid;
var visualStateGroups = VisualStateManager.GetVisualStateGroups(grid);
var visualStateGroup = visualStateGroups[0];
visualStateGroup.States[0].Storyboard.Begin();
}
DataTemplate can come from anywhere (App Resource, Window Resource, Local Resource, Code), so it uses its own NameScope.
You are unable to use MyTextBlock because of Namescope issues. So, best would be to define VisualStates as part of DataTemplate itself.

XAML Storyboard for Background ImageBrush

I have the following XAML Grid:
<Grid Style="{StaticResource LayoutRootStyle}" x:Name="mainGrid">
<Grid.Resources>
<Storyboard x:Name="FadeOut">
<DoubleAnimation Duration="3" To="0.0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="gridBackgroundImageBrush" d:IsOptimized="True"/>
</Storyboard>
<Storyboard x:Name="FadeIn">
<DoubleAnimation Duration="3" To="0.35" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="gridBackgroundImageBrush" d:IsOptimized="True"/>
</Storyboard>
</Grid.Resources>
<Grid.Background>
<ImageBrush x:Name="gridBackgroundImageBrush" ImageSource="{Binding BackgroundImage}" Opacity="0.35">
</ImageBrush>
</Grid.Background>
I want to programmatically start the "FadeOut" animation and change the Image from ImageBrush, then start the "FadeIn" animation, like this:
private void t_Tick(object sender, object e)
{
try
{
FadeOut.Begin();
this.DefaultViewModel["BackgroundImage"] = BackgroundImage;
FadeIn.Begin();
}
catch { }
}
However the image is changing without any animation. I guess the problem is about how I'm accessing the "Opacity" property of the ImageBrush. I tried the following syntax for the
TargetProperty attribute:
(Control.Background).(ImageBrush.Opacity)
as msdn shows here: http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.media.animation.storyboard.settargetproperty.aspx but it doesn't seem to work. Can someone help me with this problem?
The solution was to create an image control rather than drawing the image with ImageBrush and then defining visual states for fading:
<Grid Style="{StaticResource LayoutRootStyle}" x:Name="mainGrid">
<Image Grid.RowSpan="2" x:Name="gridBackgroundImageBrush" Source="{Binding BackgroundImage}" />
</Grid>
<VisualStateGroup x:Name="FadeStates">
<VisualState x:Name="FadeOutState">
<Storyboard>
<DoubleAnimation Duration="{Binding fadeDuration}" From="0.5" To="0.0" x:Name="fadeOutAnimation"
Storyboard.TargetProperty="Opacity"
Storyboard.TargetName="gridBackgroundImageBrush" />
</Storyboard>
</VisualState>
<VisualState x:Name="FadeInState">
<Storyboard>
<DoubleAnimation Duration="{Binding fadeDuration}" From="0.0" To="0.5" x:Name="fadeInAnimation"
Storyboard.TargetProperty="Opacity"
Storyboard.TargetName="gridBackgroundImageBrush" />
</Storyboard>
</VisualState>
</VisualStateGroup>

Create ControlTemplate with Attached Property

I am essentially trying to create a Button with an image background and border that changes color based off if it is hovered, clicked or default state. I will several of these types of buttons, and I want to have a ControlTemplate defined that I can reuse and change the ImageSource. Here is what I have so far, but for some reason the TemplateBinding doesn't seem to work. The buttons have no background image set.
Template:
<ControlTemplate x:Name="SkillIconTemplate" TargetType="Button">
<Border CornerRadius="10" BorderThickness="2" Margin="5">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition To="MouseOver" GeneratedDuration="0:0:0.1"/>
<VisualTransition To="Pressed" GeneratedDuration="0:0:0.1"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BorderBrush"
Storyboard.TargetProperty="Color"
To="Yellow" />
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BorderBrush"
Storyboard.TargetProperty="Color"
To="Black"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border.BorderBrush>
<SolidColorBrush x:Name="BorderBrush" Color="White"/>
</Border.BorderBrush>
<Border.Background>
<ImageBrush ImageSource="{TemplateBinding local:SkillIcon.IconImageSource}"/>
</Border.Background>
</Border>
</ControlTemplate>
Buttons:
<Button x:Name="skillIcon0" Width="75" Height="75" ClickMode="Press" local:SkillIcon.IconImageSource="ms-appx:/data/images/icons/skill_icon_0.png" Template="{StaticResource SkillIconTemplate}"/>
<Button x:Name="skillIcon1" Width="75" Height="75" ClickMode="Press" local:SkillIcon.IconImageSource="ms-appx:/data/images/icons/skill_icon_1.png" Template="{StaticResource SkillIconTemplate}"/>
…
Property Code:
public abstract class SkillIcon : DependencyObject
{
public static readonly DependencyProperty IconImageSourceProperty = DependencyProperty.RegisterAttached(
"IconImageSource",
typeof(ImageSource),
typeof(SkillIcon),
new PropertyMetadata(GetIconImage(0))
);
public static ImageSource GetIconImageSource(DependencyObject obj)
{
return (ImageSource)obj.GetValue(IconImageSourceProperty);
}
public static void SetIconImageSource(DependencyObject obj, ImageSource value)
{
obj.SetValue(IconImageSourceProperty, value);
}
/// <summary>
/// Gets the image source for the button
/// </summary>
public static ImageSource GetIconImage(int index)
{
Uri source = new Uri(string.Format("ms-appx:/data/images/icons/skill_icon_{0}.png", index), UriKind.RelativeOrAbsolute);
return new BitmapImage() { UriSource = source };
}
}
Usage in code:
SkillIcon.SetIconImageSource(skillIcon0, SkillIcon.GetIconImage(0));
I ended up binding the background of the Button to the background of the border:
<ControlTemplate x:Name="SkillIconTemplate" TargetType="Button">
<Border CornerRadius="10" BorderThickness="2" Margin="5" Background="{TemplateBinding Background}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition To="MouseOver" GeneratedDuration="0:0:0.05"/>
<VisualTransition To="Pressed" GeneratedDuration="0:0:0.05"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal" />
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BorderBrush"
Storyboard.TargetProperty="Color"
To="Yellow" />
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ColorAnimation Storyboard.TargetName="BorderBrush"
Storyboard.TargetProperty="Color"
To="Black"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border.BorderBrush>
<SolidColorBrush x:Name="BorderBrush" Color="White"/>
</Border.BorderBrush>
</Border>
</ControlTemplate>

LongListSelector control strectching events are not firing

I've been trying to attach code to the StretchingBottom event of a LongListSelector with no success. This is the definition in XAML
<toolkit:LongListSelector x:Name="NewList"
IsFlatList="True"
IsBouncy="True"
Background="Transparent"
ShowListFooter="False"
ShowListHeader="{Binding ProgressBar}"
Margin="0,0,12,0"
ListHeaderTemplate="{StaticResource progressbarListHeader}"
ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource Item}"
SelectionChanged="List_SelectionChanged"
StretchingBottom="List_StretchingBottom"/>
This is the method List_SelectionChanged:
private void List_StretchingBottom(object sender, EventArgs e)
{
var listbox = (LongListSelector)sender;
var viewModel = (ItemsViewModel)listbox.DataContext;
viewModel.LoadDataAfter();
}
When I put a breakpoint on the first line of the method it never gets hit even if I stretch all the way or wait. I've tried StretchingTop and StretchingComplete with no success.
Anyone can help?
I just got this working with much help from a MSDN blog and Codeplex
The examples there are for the ScrollViewer but the LongListSelector is using the ScrollViewer...
1st: add a Template to App.XAML inside the Application.Resources
:
<Style TargetType="ScrollViewer">
<Setter Property="VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ScrollViewer">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ScrollStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="00:00:00.5"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Scrolling">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="VerticalScrollBar"
Storyboard.TargetProperty="Opacity" To="1" Duration="0"/>
<DoubleAnimation Storyboard.TargetName="HorizontalScrollBar"
Storyboard.TargetProperty="Opacity" To="1" Duration="0"/>
</Storyboard>
</VisualState>
<VisualState x:Name="NotScrolling">
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="VerticalCompression">
<VisualState x:Name="NoVerticalCompression"/>
<VisualState x:Name="CompressionTop"/>
<VisualState x:Name="CompressionBottom"/>
<VisualState x:Name="StretchingTop"/>
<VisualState x:Name="StretchingBottom"/>
</VisualStateGroup>
<VisualStateGroup x:Name="HorizontalCompression">
<VisualState x:Name="NoHorizontalCompression"/>
<VisualState x:Name="CompressionLeft"/>
<VisualState x:Name="CompressionRight"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid Margin="{TemplateBinding Padding}">
<ScrollContentPresenter x:Name="ScrollContentPresenter" Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"/>
<ScrollBar x:Name="VerticalScrollBar" IsHitTestVisible="False" Height="Auto" Width="5"
HorizontalAlignment="Right" VerticalAlignment="Stretch" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
IsTabStop="False" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0" Value="{TemplateBinding VerticalOffset}"
Orientation="Vertical" ViewportSize="{TemplateBinding ViewportHeight}" />
<ScrollBar x:Name="HorizontalScrollBar" IsHitTestVisible="False" Width="Auto" Height="5"
HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
IsTabStop="False" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0" Value="{TemplateBinding HorizontalOffset}"
Orientation="Horizontal" ViewportSize="{TemplateBinding ViewportWidth}" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This enables the visual state groups for Compression, so you can detect the Compression that appeares if the list is scrolled to an end. You want CompressionBottom as this happenes when the List is scrolled to the bottom.
Now I attach a handler to the LongListSelector.Loaded event and inside attach a handler to the ScrollViewer.State
private void LongListSelector_Loaded(object sender, RoutedEventArgs e)
{
//get TemplatedListBox inside LongListSelector
FrameworkElement tlb = VisualTreeHelper.GetChild(EventsDisplayList, 0) as FrameworkElement;
//get ScrollViewer inside TemplatedListBox
FrameworkElement sv = VisualTreeHelper.GetChild(tlb, 0) as FrameworkElement;
//MS says VisualGroups are inside first Child of ScrollViewer
FrameworkElement here = VisualTreeHelper.GetChild(sv, 0) as FrameworkElement;
var groups = VisualStateManager.GetVisualStateGroups(here);
VisualStateGroup vc = null;
foreach (VisualStateGroup g in groups)
{
if (g.Name == "VerticalCompression")
{
vc = g;
break;
}
}
vc.CurrentStateChanged +=new EventHandler<VisualStateChangedEventArgs>(LongListSelector_Compression);
}
private void LongListSelector_Compression(object sender, VisualStateChangedEventArgs e)
{
if (e.NewState.Name == "CompressionBottom")
{
//put your code for loading new items here
}
}
As you can see I don't use the LongListSelector.StretchingBottom event at all.
But it works :)

DataTrigger in WinRT?

I was able to find EventTrigger in the WinRT reference, however, I wasn't able to find DataTrigger. I wasn't able to use it in an application either.
Can anyone confirm that DataTrigger is really missing in WinRT? Is EventTrigger the only trigger available in WinRT?
DataTrigger is not currently supported in WinRT XAML.
Addendum by Mike Brown
The DataTrigger API has been replaced with the VisualStateManager a similar API to Data Triggers was provided by the Blend SDK for Silverlight. Since the Attached Behavior Pattern works in WinRT, it is possible to do the same.
What about this project that seems implement triggers in WinRT : http://winrttriggers.codeplex.com/
I don't know when it changed but i have DataTriggerBehavior and GoToStateAction combining them should solve your problem...
namespace imports
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
ViewSateManager place on root element
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="Common">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0" To="Online">
<Storyboard>
<ColorAnimation Duration="0" To="Lime" Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)" Storyboard.TargetName="Name" />
</Storyboard>
</VisualTransition>
<VisualTransition GeneratedDuration="0" To="Offline">
<Storyboard>
<ColorAnimation Duration="0" To="Red" Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)" Storyboard.TargetName="Name" />
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Online" />
<VisualState x:Name="Offline" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Interactivity:Interaction.Behaviors>
<Core:DataTriggerBehavior Binding="{Binding Active}" Value="True">
<Core:GoToStateAction StateName="Online" />
</Core:DataTriggerBehavior>
<Core:DataTriggerBehavior Binding="{Binding Active}" Value="False">
<Core:GoToStateAction StateName="Offline" />
</Core:DataTriggerBehavior>
</Interactivity:Interaction.Behaviors>
I implemented an alternate workaround that may work for you. Steps:
Create a UserControl (either from scratch or inheriting) so you can write some code-behind C# into the control.
Create a DependencyProperty in the codebehind for the databinding you want to trigger on.
Use the DependencyProperty's PropertyChangedCallback method to implement do what you need to do in code to the control.
Bind the DependencyProperty in XAML to the data you want to trigger on.
It's not as clean as a DataTrigger, but it's not too much worse and it works well (for me at least).
Declaration in XAML (DataContext is already set to a viewmodel object):
<local:PlayButton IsPlaying="{Binding IsPlaying}"/>
Example DependencyProperty that triggers storyboards to change state:
// Use this to implement storyboard changing in W8 since triggers are not supported
public static readonly DependencyProperty IsPlayingProperty = DependencyProperty.Register(
"IsPlaying",
typeof(bool),
typeof(PlayButton),
new PropertyMetadata(null,
new PropertyChangedCallback(OnIsPlayingChanged)
));
private static void OnIsPlayingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
PlayButton pb = (PlayButton)d;
bool isPlaying = (bool)e.NewValue;
if (isPlaying == false)
pb.GotoPlay.Begin();
else
pb.GotoPause.Begin();
}
public bool IsPlaying
{
get { return (bool)GetValue(IsPlayingProperty); }
set { SetValue(IsPlayingProperty, value); }
}
you can use VisualState instead of object.Triggers in Windows 8 Here is the code
<ControlTemplate TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<!--Take one half second to transition to the PointerOver state.-->
<VisualTransition To="PointerOver" GeneratedDuration="0:0:0.5"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal" />
<VisualState x:Name="PointerOver">
<Storyboard>
<ColorAnimation Storyboard.TargetName="ButtonBrush"
Storyboard.TargetProperty="Color" To="Red" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.Background>
<SolidColorBrush x:Name="ButtonBrush" Color="Green"/>
</Grid.Background>
</Grid>
</ControlTemplate>