Silverlight: Switching VisualStates of CustomVisualStateManager in code-behind - c#

i've been trying to deal with the following problem:
When creating a custom animations for different visual states in Expression Blend 3, which change size/opacity of multiple elements on the grid, it creates the visual state groups in the grid itself rather than in control style and defines it as CustomVisualStateManager.
<Grid x:Name="LayoutRoot" Background="White" Height="500" HorizontalAlignment="Left" VerticalAlignment="Top" Width="500">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="MyVisualStateGroup">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="00:00:00.3000000">
<VisualTransition.GeneratedEasingFunction>
<CircleEase EasingMode="EaseIn"/>
</VisualTransition.GeneratedEasingFunction>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="State1"/>
<VisualState x:Name="State2">
<Storyboard>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="myBox" Storyboard.TargetProperty="(FrameworkElement.Height)">
<EasingDoubleKeyFrame KeyTime="00:00:00" Value="360"/>
<!-- omitting other storyboard animations here for clarity -->
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<VisualStateManager.CustomVisualStateManager>
<ic:ExtendedVisualStateManager/>
</VisualStateManager.CustomVisualStateManager>
<!-- omitting other grid elements here for clarity -->
</Grid>
It's ok with me, but problem is, i can't switch states, in code-behind when i try
VisualStateManager.GoToState(this, "State1", true);
nothing happens, because the control itself doesn't have these visualstates defined, as shown by
VisualStateManager.GetVisualStateGroups(this);
If i try
VisualStateManager.GetVisualStateGroups(LayoutRoot);
it shows exactly what i need. But i cannot pass LayoutRoot to VisualStateManager because it needs an argument of Control type, which Grid isn't.
My question is - how can i access/ change states of this CustomVisualStateManager in code-behind?

The CustomVisualStateManager is just there when you enable FluidLayout. Unless you have layout morphing involved in your project (i.e. you are trying to use states to animate smoothly from one layout to another), you can switch it off. The presence of the custom VSM should not make any difference in the usage of VSM.
The visual state markup always is inside the top level container, so that is perfectly normal. BTW, this might be just a typo in your sample, but the code you show actually tries to set a state that has nothing in it, so that might not be the desired result.
Otherwise, calling VisualStateManager.GoToState on the UserControl should work. Here is an example I just made that works:
This is a simple Silverlight example app, with a main page and a user control that I added to the main page. The main page is really simple:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SLStateTest"
x:Class="SLStateTest.MainPage"
Width="640" Height="480">
<Grid x:Name="LayoutRoot" Background="White">
<local:UserControl1 x:Name="TestControl" Height="100" HorizontalAlignment="Left" Margin="24,32,0,0" VerticalAlignment="Top" Width="100"/>
<Button Height="40" HorizontalAlignment="Left" Margin="192,32,0,0" VerticalAlignment="Top" Width="104" Content="State 1" Click="OnClick"/>
<Button Height="40" HorizontalAlignment="Left" Margin="192,76,0,0" VerticalAlignment="Top" Width="104" Content="State 2" Click="OnClickState2"/>
</Grid></UserControl>
There is an instance of my user control, and two buttons. We'll look at what the buttons do in a second. First let's look at the UserControl (UserControl1):
<UserControl
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"
xmlns:ic="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
x:Class="SLStateTest.UserControl1"
d:DesignWidth="280" d:DesignHeight="264">
<Grid x:Name="LayoutRoot" Background="#FF6FFE22">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="Test" ic:ExtendedVisualStateManager.UseFluidLayout="True">
<VisualState x:Name="State1">
<Storyboard>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
<EasingColorKeyFrame KeyTime="00:00:00" Value="#FF003AFF"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="State2">
<Storyboard>
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)">
<EasingColorKeyFrame KeyTime="00:00:00" Value="#FFFF0202"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<VisualStateManager.CustomVisualStateManager>
<ic:ExtendedVisualStateManager/>
</VisualStateManager.CustomVisualStateManager>
</Grid></UserControl>
As you can see, there are two visual states defined in one visual state group that just set a color on the layout root of the user control.
The two buttons on the main page are wired up to event handlers that look as follows:
private void OnClick(object sender, System.Windows.RoutedEventArgs e)
{
// TODO: Add event handler implementation here.
VisualStateManager.GoToState(TestControl, "State1", true);
}
private void OnClickState2(object sender, System.Windows.RoutedEventArgs e)
{
// TODO: Add event handler implementation here.
TestControl.SetState();
}
The first one just calls VisualStateManager.GoToState on the UserControl on the page. The second one calls a function iside of the user control that does the same thing. I just used both methods to show that both options are available - you can call VSM.GoToState from the outside or the inside of a UC. The SetState() method of the user control looks as follows:
public void SetState()
{
VisualStateManager.GoToState(this, "State2", true);
}
When you run the app, the user control will first show up in its base state , which is green. When you press the State 1 button it goes to State1, which sets the UC to blue by calling VSM.GoToState() from the outside. When you press the State 2 button, it switches to red, by calling VSM from the inside.
From the snippets you posted, I can't see what is going wrong, short of the one issue that I mentioned at the beginning. However, my little sample might help you to see what is different in your case.
Hope that helps...

Related

Which layout elements should I use to implement a submenu with an animation transition

I'am very new to this WinRT and XAML stuff and not sure how to achieve this goal. For my page layout I have basically 2 rows. The first row is representing my (static) basic menu with some buttons and pictures (about 130 height). The rest of the screen should be used to display content. Like this:
screen layout
now when a user clicks on a main menu button the submenu "filter settings" should be move down with an animation. The main content is also responding to this event and moving accordingly ("filter settings" should not overlay the main content).
My current idea to define this layout is using a grid with 3 rows and 2 frames placed inside it. When no filter is activated, I use rowspan for my main content to span over the whole area. When a click event is recognized, I change the rownum of the frame which hold the main content (ModuleContentFrame) to 2 and its rowspan to 1. Then I'am loading the filter page to frame ModuleFadeInFrame.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="130"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<Frame
x:Name="ModuleFadeInFrame"
Grid.Row="1"/>
<Frame
x:Name="ModuleContentFrame"
Grid.Row="1"
Grid.RowSpan="2"/>
</Grid>
My question is: is this layout definition with a grid and frames inside it a suitable solution to solve this problem and how can I achieve a "moving" animation when displaying a sub-menu. I tried this with an Storyboard but there the main content is just "jumping" to row 2
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ModuleContentFrame"
Storyboard.TargetProperty="(Grid.Row)">
<DiscreteObjectKeyFrame KeyTime="1" Value="2" />
</ObjectAnimationUsingKeyFrames>
You can't really animate Grid row/col/etc... changes. Also any animation that'll result in a layout change is a dependent animation - and has bad performance. What I'd do is something like this:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity" xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
x:Class="App1.MainPage"
mc:Ignorable="d">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="MenuState">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.3">
<VisualTransition.GeneratedEasingFunction>
<ExponentialEase EasingMode="EaseInOut"/>
</VisualTransition.GeneratedEasingFunction>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="ClosedState"/>
<VisualState x:Name="OpenState">
<Storyboard>
<DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="grid" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid>
<Grid Margin="0,50,0,0" Background="Black">
<TextBlock>
Long text blablabla
</TextBlock>
</Grid>
<Grid x:Name="grid" Margin="0,50,0,0" Height="50" VerticalAlignment="Top" Background="#77ffff00">
<Grid.RenderTransform>
<CompositeTransform TranslateY="-50"/>
</Grid.RenderTransform>
<Button Content="Close" >
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="Click">
<Core:GoToStateAction StateName="ClosedState"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</Button>
</Grid>
<Grid Margin="0,0,0,0" Height="50" VerticalAlignment="Top" Background="Red">
<Button Content="Open" >
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="Click">
<Core:GoToStateAction StateName="OpenState"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</Button>
</Grid>
</Grid>
</Grid>
</Page>
This way there's no layout change, as your submenu is going to end up on top of the content.
if you're really insisting on the 'not obscuring content' way
You could just have your submenu before your content with a Height="0", and animate the height of the element with a DoubleAnimation. If you do this, you'll have to set EnableDependentAnimation to true.
More info: https://msdn.microsoft.com/en-us/library/windows/apps/xaml/windows.ui.xaml.media.animation.pointanimation.enabledependentanimation.aspx
Thank you Tamás, you helped me a lot getting my solution. I'am doing this now as follows:
This code goes into the edit:UserControl for each submenu. On the main page I then only have to handle my Button click events and call the appropriate Animation. Next Step is getting familiar with Blend as you suggested :-)
I marked your post as answer because it was the most helpful in finding my solution
<Grid x:Name="maingrid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" >
<Grid.RenderTransform>
<CompositeTransform TranslateY="-360"/>
</Grid.RenderTransform>
<Grid.Resources>
<Storyboard x:Name="myStoryboardOpen">
<DoubleAnimation Duration="0:0:0.3" To="0" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)"
Storyboard.TargetName="maingrid"
d:IsOptimized="True"/>
</Storyboard>
<Storyboard x:Name="myStoryboardClose">
<DoubleAnimation Duration="0:0:0.3" To="-360" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)"
Storyboard.TargetName="maingrid"
d:IsOptimized="True"/>
</Storyboard>
</Grid.Resources>

How to Hide and show a button

I try to display a button that shows some text. Every X seconds the button must slide to the left and reappear with a new text inside.
Due to the other object on my page I can't use a popup.
Any ideas on how to do this ?
I already try with a grid, except that I don't find how to slide it.
XAML
<Grid x:Name="PropoCloud" VerticalAlignment="Bottom">
<tut:TutorialAwareButton Name="PropoButton"
Style="{StaticResource tplButtonCloud}"
Command="{Binding CmdCreated}"
BorderThickness="0" VerticalAlignment="Bottom"
HorizontalAlignment="Left" Width="410" Height="200">
<tut:TutorialAwareButton.CommandParameter>
<cmd:NavigationCommandParameter TargetName="QuestionCreatingView"></cmd:NavigationCommandParameter>
</tut:TutorialAwareButton.CommandParameter>
</tut:TutorialAwareButton>
</Grid>
C#
private void SuggestionCycling()
{
if (PropoCloud.Visibility == Visibility.Visible)
{
PropoCloud.Visibility = Visibility.Collapsed;
}
else
{
PropoCloud.Visibility = Visibility.Visible;
}
}
Code that you have posted will only hide and show the control back again, you need to have animation to fly it out and bring it in ... have a look at this Link to understand how animation can do that...
The provided link is not for you to copy, make changes to suit your needs and understand the concept.
This is a functionnal solution :
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="FadeStates">
<VisualState x:Name="FadeOut">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="PropoCloud" Storyboard.TargetProperty="PropoCloud.Opacity" From="1" To="0" Duration="0:0:1"/>
</Storyboard>
</VisualState>
<VisualState x:Name="FadeIn">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="PropoCloud" Storyboard.TargetProperty="PropoCloud.Opacity" From="0" To="1" Duration="0:0:2"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
Just add the FadeOut.Storyboard.Begin();and FadeIn.Storyboard.Begin();In your timer cycle.

Issue with snapped view metro app

Hey Guys Please Help To Sort out My Problem , i have made an app and i have to upload it on windows store but the problem is that it does not support snapped view. I want that it should not work in snapped view, when the app enters in snapped view it just display a message " Switch To Full Screen ". Please tell me how to code for that and where to code in XAML or XAML.cs. Thanks in Advance.
Add a Basic Page and replace XAML with this:
<common:LayoutAwarePage
x:Name="pageRoot"
x:Class="App1.OopsPage"
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App1"
xmlns:common="using:App1.Common"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<!-- Full screen content. -->
<Grid x:Name="FullScreenGrid">
<TextBlock>Here is your content.</TextBlock>
</Grid>
<!-- Snapped view content. -->
<Grid x:Name="SnappedViewGrid" Visibility="Collapsed">
<TextBlock>Please go back to full screen :(</TextBlock>
</Grid>
<VisualStateManager.VisualStateGroups>
<!-- Visual states reflect the application's view state -->
<VisualStateGroup x:Name="ApplicationViewStates">
<VisualState x:Name="FullScreenLandscape"/>
<VisualState x:Name="Filled"/>
<VisualState x:Name="FullScreenPortrait" />
<!-- The back button and title have different styles when snapped -->
<VisualState x:Name="Snapped">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="FullScreenGrid" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SnappedViewGrid" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</common:LayoutAwarePage>
Make sure to replace App1 with your app namespace and you must have LayoutAwarePage.cs in your Common folder.
One of the possible solutions
Create a new page which you would want to use for Snap
Listen to the event which is raised when the user snaps the app.
Navigate to that page which has "Switch to Full Screen"
Listen to the event which is raised when the user unsnaps
Go back to the original page
To achieve this,
In your App.xaml.cs in the OnLaunched event write this
Window.Current.SizeChanged += Current_SizeChanged;
Now for the event handler
void Current_SizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
ApplicationViewState viewState = ApplicationView.Value;
if (viewState == ApplicationViewState.Snapped)
{
//Navigate to the new common snap page
}
else{
//Write the code to check if the previous state was snapped and then navigate back
}
}

VisualStateManager in user control

I design an application for Windows RT. I used VisualStateManager for snapped in a user control. but when my application snapped the user control is not changed. where is the problem?
<Grid Width="500" Height="40" Margin="15" x:Name="questionRoot" Background="DarkSeaGreen">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" >
<TextBlock x:Name="OrginalWord" FontSize="32" Text="{Binding Question.OrginalWord}"></TextBlock>
</StackPanel>
<VisualStateManager.VisualStateGroups>
<!-- Visual states reflect the application's view state -->
<VisualStateGroup x:Name="ApplicationViewStates">
<VisualState x:Name="FullScreenLandscape"/>
<VisualState x:Name="Filled"/>
<!-- The entire page respects the narrower 100-pixel margin convention for portrait -->
<VisualState x:Name="FullScreenPortrait"/>
<!--
The back button and title have different styles when snapped, and the list representation is substituted
for the grid displayed in all other view states
-->
<VisualState x:Name="Snapped">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="OrginalWord" Storyboard.TargetProperty="FontSize">
<DiscreteObjectKeyFrame KeyTime="0" Value="88"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
Are you calling the VisualStateManager.GoToState method in codebehind? You need to detect when the application transitions from Full/Fill to Snap mode, and call this method then.
You'll find the MSDN documentation for this function here.
You generally recognize this transition when the size of your Page parent control or application Window changes. This SO question (look at the answer by Jowen) gives you a code snippet on how to do this by listening to the Window's size changed event.
I had a similar issue I found a solution that helped me and may be someone find it useful if the usercontrol is hosted in layoutawarepage
<my:usercontrole Loaded="StartLayoutUpdates" Unloaded="StopLayoutUpdates" />
otherwise you will have to de the follow (example can be found in the layout aware page)
•make event handler on sizechanged
•in the event handler check the viewstate with ApplicationView.Value
•move to that state with VisualStateManager.GoToState

How to hide or disable the TimeHint in a toolkit TimeUpDown control in Silverlight?

I looked on the internet but I can find this nowhere : I would like to disable the TimeHint popup that shows the current time when entering focus on a TimeUpDown control. Something like : <12:42AM>
There is no TimeHintEnabled property, nor any kind of member that seems to control this. There is a TimeHintContent property, but it is readonly and seems empty at first.
My code is really simple :
<Grid x:Name="LayoutRoot" Background="Transparent">
<toolkit:TimeUpDown Name="timeUpDown1"
Background="White"
Height="22"
MinWidth="55"
HorizontalAlignment="Left"
VerticalAlignment="Top" />
</Grid>
Maybe playing with the Template can do the trick, but I don't know how to do it...
Alright, thanks to Blend I found what I was looking for.
The Template can be easily modified by Blend, this part of the template is needed inside the xaml to hide the TimeHintPopup :
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="TimeHintStates">
<VisualState x:Name="TimeHintOpenedUp">
<Storyboard>
<ObjectAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetProperty="Visibility"
Storyboard.TargetName="TimeHintVisualElement">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="Collapsed"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
And your TimeUpDown should refer to this template :
<toolkit:TimeUpDown Name="timeUpDown1" Background="White" Height="22" MinWidth="55" HorizontalAlignment="Left" VerticalAlignment="Top" Style="{StaticResource TimeUpDownStyle1}" />

Categories

Resources