Focusable WinRT UserControl with image background - image

I'm having difficulty developing a WinRT control that can display an image as well as be focusable and receive keyboard input. The first part - displaying an image in a UserControl - is straightforward; using a child Rectangle whose background is an ImageBrush works fine.
However, calling UserControl.Focus(FocusState.Programmatic) (or any other focus state) does not work - it returns false and focus is not set to the user control.
Incidentally, this UserControl is currently being tested inside a ContentControl, not sure if that makes any difference.
How can I make this UserControl focusable and able to receive keyboard input?

You need to set IsTabStop="True" to let it focus. UserControl's default is False.
Another thing you need to do is to display a focus indicator, which you don't get with UserControl for free. Here's the way you can add the visuals for it - copied from a Button template:
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup
x:Name="FocusStates">
<VisualState
x:Name="Focused">
<Storyboard>
<DoubleAnimation
Duration="0"
To="1"
Storyboard.TargetProperty="Opacity"
Storyboard.TargetName="FocusVisualWhite" />
<DoubleAnimation
Duration="0"
To="1"
Storyboard.TargetProperty="Opacity"
Storyboard.TargetName="FocusVisualBlack" />
</Storyboard>
</VisualState>
<VisualState
x:Name="Unfocused" />
<VisualState
x:Name="PointerFocused" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Rectangle
x:Name="FocusVisualWhite"
IsHitTestVisible="False"
Opacity="0"
StrokeDashOffset="1.5"
StrokeEndLineCap="Square"
Stroke="{ThemeResource FocusVisualWhiteStrokeThemeBrush}"
StrokeDashArray="1,1" />
<Rectangle
x:Name="FocusVisualBlack"
IsHitTestVisible="False"
Opacity="0"
StrokeDashOffset="0.5"
StrokeEndLineCap="Square"
Stroke="{ThemeResource FocusVisualBlackStrokeThemeBrush}"
StrokeDashArray="1,1" />
</Grid>
You still need to switch the visual state and so you could do something like this:
protected override void OnGotFocus(RoutedEventArgs e)
{
base.OnGotFocus(e);
this.UpdateVisualState(true);
}
protected override void OnLostFocus(RoutedEventArgs e)
{
base.OnLostFocus(e);
this.UpdateVisualState(true);
}
private void UpdateVisualState(bool useTransitions)
{
switch (this.FocusState)
{
case FocusState.Programmatic:
case FocusState.Keyboard:
VisualStateManager.GoToState(this, "Focused", useTransitions);
break;
case FocusState.Pointer:
VisualStateManager.GoToState(this, "PointerFocused", useTransitions);
break;
case FocusState.Unfocused:
VisualStateManager.GoToState(this, "Unfocused", useTransitions);
break;
}
}

Related

Blend Animation Playing Issue

I don't know if I named the question right but here it is
First of all I am very new to Blend and never used it before in my life. I decided to make a simple animation today and things happened but not as expected.
I'm animating a button and the animation is just a simple 360 degrees flip on the Y axis. I created the animation for a specific button. It worked exactly how I wanted with this code
TiltAnimation.Begin();
However when I tried to create a ControlTemplate with this animation this happened. I need to click and hold the button in order for the animation to finish. I set the animation to play on a specific state: 'Pressed' (to be more specific it was pressed -> * which I suppose means 'from pressed state to any state'). Am I doing something wrong or am I missing something
Note: I'm experimenting on the windows phone platform.
If you need any code tell me in the comments
EDIT:Here is the XAML code from the page and from the App.xaml
Page code:
<Button Grid.Column="1"
Height="60"
Width="60"
BorderThickness="1"
Background="White"
Opacity="0.8"
Template="{StaticResource ButtonControlTemplate1}"
Click="PlayButton_Click">
</Button>
App.xaml code:
<ControlTemplate x:Key="ButtonControlTemplate1" TargetType="Button">
<Grid x:Name="grid">
<Grid.Resources>
<Storyboard x:Name="Storyboard1">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)" Storyboard.TargetName="grid">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="360"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Grid.Resources>
<Grid.Projection>
<PlaneProjection/>
</Grid.Projection>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition From="Pressed" GeneratedDuration="0">
<VisualTransition.GeneratedEasingFunction>
<BackEase EasingMode="EaseIn"/>
</VisualTransition.GeneratedEasingFunction>
<Storyboard>
<DoubleAnimation Duration="0:0:1" Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)" Storyboard.TargetName="grid"/>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Pressed">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Projection).(PlaneProjection.RotationY)" Storyboard.TargetName="grid">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="360"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Image x:Name="image" Source="/Assets/Icons/Previous.png">
<Image.Projection>
<PlaneProjection/>
</Image.Projection>
</Image>
<Ellipse Height="Auto" Width="Auto" Stroke="White" StrokeThickness="4"/>
</Grid>
</ControlTemplate>

Storyboard can't be executed twice

I tried to use an animation in my app and I'm using only two pages to test the animation.
When the app starts for the first time, I want to animate my application title with a sliding effect. The title should come from outside the page.
I used the following code:
<StackPanel x:Name="TitlePanel"
Grid.Row="0"
Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle"
Text="{Binding LocalizedResources.ApplicationTitle, Source={StaticResource LocalizedStrings}}"
Style="{StaticResource PhoneTextNormalStyle}" RenderTransformOrigin="0.5,0.5" >
<TextBlock.RenderTransform>
<CompositeTransform x:Name="ApplicationTitleTransIn" TranslateX="-200"/>
</TextBlock.RenderTransform>
<TextBlock.Triggers>
<EventTrigger RoutedEvent="TextBlock.Loaded">
<BeginStoryboard>
<Storyboard BeginTime="00:00:0.5">
<DoubleAnimation Duration="00:00:0.7"
Storyboard.TargetName="ApplicationTitleTransIn"
Storyboard.TargetProperty="TranslateX"
From="-200" To="0">
<DoubleAnimation.EasingFunction>
<BackEase EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBlock.Triggers>
</TextBlock>
</StackPanel>
And it works pretty well.
When I click a button, my application title should move to the right side of my page and then the second page should be displayed.
I created the following storyboard:
<phone:PhoneApplicationPage.Resources>
<Storyboard x:Name="ApplicationTitleTransOut">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="ApplicationTitle">
<EasingDoubleKeyFrame KeyTime="0" Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<ExponentialEase EasingMode="EaseIn"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="600">
<EasingDoubleKeyFrame.EasingFunction>
<ExponentialEase EasingMode="EaseIn"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</phone:PhoneApplicationPage.Resources>
In the code behind, the storyboard is executed as follow:
ApplicationTitleTransOut.Completed += delegate
{
ApplicationTitleTransOut.Stop();
var vm = DataContext as MainViewModel;
if (vm != null)
{
vm.OpenPageCommand.Execute(listBox.SelectedItem as TileItem);
}
};
ApplicationTitleTransOut.Begin();
The text will move to the right side of my page and then I'll navigate to the second page.
Until now everything works.
But when I press the back button (on the phone) I've an exception.
ExceptionObject = {System.InvalidOperationException: Cannot resolve TargetName ApplicationTitleTransIn.}
Did I miss something? Is this the right way to achieve this animation?
Thank you for your help.
In your situation, I would structure the XAML layout differently. First of all, it does not seem that you need CompositeTransform, but just TranslateTransform. In this case, use this snippet for RenderTransform:
<TextBlock.RenderTransform>
<TranslateTransform x:Name="ApplicationTitleTransIn" X="-200"/>
</TextBlock.RenderTransform>
Now, when you are binding the DoubleAnimation to it, use relative property conventions:
<DoubleAnimation Duration="00:00:0.7"
Storyboard.TargetName="ApplicationTitle"
Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"
From="-200" To="0">
Same applies to your DoubleAnimationUsingKeyFrames:
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)" Storyboard.TargetName="ApplicationTitle">
Works like a charm.

Can one set visual state for PhoneApplicationPage?

I have a question about visual state management of PhoneApplicationPage. Basically, can one use VisualStateManager approach to set states of the page itself? In the end, it inherits the Control class, so this stuff should be applicable.
I'm asking because I've tried and failed. Here's my code:
<phone:PhoneApplicationPage
x:Class="Encountered.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="Common">
<VisualState x:Name="State1">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="button" Storyboard.TargetProperty="(UIElement.Opacity)" To="1" Duration="0"/>
</Storyboard>
</VisualState>
<VisualState x:Name="State2">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="button" Storyboard.TargetProperty="(UIElement.Opacity)" To="0" Duration="0"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackPanel Orientation="Vertical">
<HyperlinkButton x:Name="button" NavigateUri="/Views/EditPage.xaml" Content="Go"/>
<Button Click="Button_Click">state</Button>
</StackPanel>
</phone:PhoneApplicationPage>
In the code-behind:
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
VisualStateManager.GoToState(this, "State1", true);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
VisualStateManager.GoToState(this, "State2", true);
}
}
Any ideas what could be wrong?
The VisualStateManager enables you to specify when a control enters a specific state.
So, simply wrap all in a grid :
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="Common">
<VisualState x:Name="State1">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="button" Storyboard.TargetProperty="(UIElement.Opacity)" To="1" />
</Storyboard>
</VisualState>
<VisualState x:Name="State2">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="button" Storyboard.TargetProperty="(UIElement.Opacity)" To="0" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackPanel Orientation="Vertical">
<HyperlinkButton x:Name="button" NavigateUri="/Views/EditPage.xaml" Content="Go" />
<Button Click="Button_Click" >state</Button>
</StackPanel>
</Grid>

What kind of controls should I use in Windows Phone 7 to make a "star" control

I show some items from the database in the list and I want the user to be able to mark some of them as favorites. The best way would be to show some star icon for user to click on which then would turn into slightly different star to indicate that the item is now favorite. What controls should I use for those stars? Could I bind them to some boolean property of the item?
You can also use vector graphics to achieve this without using png icons.
I created this style a while a go, basically it is for CheckBox but I think it also works for ToggleButton by simply changing the TargetType from CheckBox to ToggleButton.
By setting the IsChecked of either CheckBox or ToggleButton to True, the star will be filled with the accent color of the phone.
The Style
<Style x:Key="StarCheckBoxStyle" TargetType="CheckBox">
<Setter Property="Background" Value="{StaticResource PhoneAccentBrush}" />
<Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilySemiBold}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CheckBox">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused" />
<VisualState x:Name="Unfocused" />
</VisualStateGroup>
<VisualStateGroup x:Name="CheckStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="00:00:00.2000000" />
</VisualStateGroup.Transitions>
<VisualState x:Name="Checked">
<Storyboard>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="check" Storyboard.TargetProperty="(UIElement.Opacity)">
<EasingDoubleKeyFrame KeyTime="00:00:00" Value="1" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Indeterminate" />
<VisualState x:Name="Unchecked" />
</VisualStateGroup>
<VisualStateGroup x:Name="ValidationStates">
<VisualState x:Name="Valid" />
<VisualState x:Name="InvalidUnfocused" />
<VisualState x:Name="InvalidFocused" />
</VisualStateGroup>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="00:00:00.2000000" />
</VisualStateGroup.Transitions>
<VisualState x:Name="MouseOver" />
<VisualState x:Name="Pressed" />
<VisualState x:Name="Disabled" />
<VisualState x:Name="Normal" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Path x:Name="check" Stretch="Fill" Height="48" Width="48" UseLayoutRounding="False" Data="M16.000002,0 L19.77688,12.223213 L32,12.222913 L22.111122,19.776972 L25.888546,32 L16.000002,24.445454 L6.1114569,32 L9.8888807,19.776972 L8.574415E-09,12.222913 L12.223121,12.223213 z" Opacity="0" Fill="{TemplateBinding Background}" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" />
<Path x:Name="stroke" Stretch="Fill" Stroke="{TemplateBinding Background}" Height="48" Width="48" UseLayoutRounding="False" Data="M16.000002,0 L19.77688,12.223213 L32,12.222913 L22.111122,19.776972 L25.888546,32 L16.000002,24.445454 L6.1114569,32 L9.8888807,19.776972 L8.574415E-09,12.222913 L12.223121,12.223213 z" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" />
<ContentPresenter VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="0,0,8,0" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Apply the style
<CheckBox Content="unchecked state" Style="{StaticResource StarCheckBoxStyle}" />
<CheckBox IsChecked="True" Content="checked state" Style="{StaticResource StarCheckBoxStyle}" />
How they look
You can use a ToggleButton to do this. Keep 2 star images in your project, one for clicked and the other for not clicked. You can use data binding along with the IsChecked property to switch between the 2 images.
XAML:
<ToggleButton IsChecked="{Binding IsFavorited, Mode=TwoWay}">
<ToggleButton.Content>
<Image Source="{Binding FavoriteImage}" />
</ToggleButton.Content>
</ToggleButton>
C#:
Image ClickedImage = new Image() {
Source = new BitmapImage(new Uri("/clicked.png", UriKind.Relative));
};
Image NotClickedImage = new Image() {
Source = new BitmapImage(new Uri("/not_clicked.png", UriKind.Relative));
};
bool _isFavorited = false;
Image _favoriteImage = NotClickedImage;
public bool IsFavorited
{
get { return _isFavorited; }
set
{
if( _isFavorited != value ) {
_isFavorited = value;
NotifyPropertyChanged( "IsFavorite" );
FavoriteImage = _isFavorited ? ClickedImage : NotClickedImage;
}
}
}
public Image FavoriteImage
{
get { return _favoriteImage; }
private set
{
if( _favoriteImage != value ) {
_favoriteImage = value;
NotifyPropertyChanged( "FavoriteImage" );
}
}
}
The class containing the code behind needs to implement the INotifyPropertyChanged interface.
Refer here for a list of star controls available for the silverlight toolkit for the windows phone.

create image style in xaml

I don't know why I'm having so much trouble doing this, it shouldn't be hard, but I must be Blend-incompetent. Can someone give me the xaml for an image style where the image is at 60% opacity, on mouseover fades in to 100, mouseout back to 60% and onclick glows for a 0,2 sec.
Or just tell me how to do in blend?
thank you
Solution turned out to be simple enough:
<Style x:Key="FadeImageButton" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid x:Name="grid" Width="16" Height="16">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.2"/>
<VisualTransition GeneratedDuration="0:0:0.2" To="Normal"/>
<VisualTransition GeneratedDuration="0:0:0.2" To="MouseOver"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal">
<Storyboard>
<DoubleAnimation Duration="0" To="0.6" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="grid" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
<VisualState x:Name="MouseOver">
<Storyboard>
<DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="grid" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed"/>
<VisualState x:Name="Disabled"/>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused"/>
<VisualState x:Name="Unfocused"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You are certainly not incompetent. Images do not have states, so a style is not the answer.
The only styles you can create for images are for one fixed state, so you could add the 60% opacity, but not much else.
Your options are:
Create EnterImage and LeaveImage
storyboards that are played with ControlStoryboardAction behaviours (on MouseEnter and MouseLeave events).
Create a custom behaviour and attach that to the images.
Place the image in another control that has states (maybe a button)
Place the image in a user control with an image property
Create a custom control
The simplest is option 1, but it requires attaching several properties to each image so more drags and clicks to author them.
If you let us know which option you prefer I may be able to post an example.

Resources