I am playing with a Metro Style Application at the moment (.NET 4.5 RC [C#\XAML], VS2012 RC) and I have one problem which I am unable to solve.
I would like to achieve that my app will change the layout when hosting device is rotated (+-45). I have prepared two layouts in XAML - one for landscape and second one for portrait, and I have done some animation for Visual States:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ApplicationViewStates">
<VisualState x:Name="FullScreenLandscape"/>
<VisualState x:Name="Filled"/>
<VisualState x:Name="FullScreenPortrait">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ControlContentLandscape" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ControlContentPortrait" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Snapped"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
But I do not know what to do next. How to set my app that it will perform these animations when my device is turned into portrait mode?
I have analysed the Grid App template. And I have noticed that the main page there inherits from the LayoutAwarePage class which is present in the Common folder. The LayoutAwarePage class provide the handler for WindowSizeChanged event which is using the VisualStateManager to switch between states - this was the missing part in my current project. The solution is:
Manually handle the WindowsSizeChanged event and use the VisualStateManager class and GoToState() method
Create new project (Grid App) and fit into it the current project.
Related
I'm writing a custom renderer for a submit button in order to provide a uniform style with my Xamarin.Forms application. I'm having trouble setting the foreground (text) color for a disabled button on the Windows (UWP) side of things.
changing the color for an active button is as simple as
Control.Foreground = new SolidColorBrush(Windows.UI.Colors.Green);
but attempting to figure out how to set the foreground color for a disabled button has led me down a rabbit-hole.
I would like to be able to set this without having to use XAML (like this approach) because I plan to extract these renderers later.
The best would be if you could edit the style of your button, or define it somewhere in resources and then apply it to your button, even from code.
There is other way, theoretically simpler and available from code. If you take a look at button's style, you will see the section for disabled visual state:
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="RootGrid">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlBackgroundBaseLowBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentPresenter">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ContentPresenter">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledTransparentBrush}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
You see the names of brush resources which are used it that state. It should be enough to change them in code to make all disabled buttons look like you want. Though you need to remember that this will also change behavior when user changes theme and your app is suspended.
private void Button_Click(object sender, RoutedEventArgs e)
{
App.Current.Resources["SystemControlBackgroundBaseLowBrush"] = new SolidColorBrush(Colors.Yellow); // background
App.Current.Resources["SystemControlDisabledBaseMediumLowBrush"] = new SolidColorBrush(Colors.Red); // content
App.Current.Resources["SystemControlDisabledTransparentBrush"] = new SolidColorBrush(Colors.Green); // border
}
Not sure if am framing the question right. So please bear with me if I'm expecting something absurd. I am building a C#/XAML win10 UWP application following the MVVM pattern.
I've some visual states defined for handling wider screens and also some for running some animations. The problem am facing is that, when the visual state to run the animation is called using the VisualStateManager's GoToState method, the setters effected by the VisualState containing the adaptive triggers are lost.
Here's the sample code:
//Defining my grid here
<Grid x:Name="gridNewDrawing" Margin="4">
<Button x:Name="Confirm" Click="Button_Confirm_Click" Width="180" MaxWidth="220" Height="36" HorizontalAlignment="Left" Style="StaticResource StyleButtonGeneral}"/>
<Button x:Name="Cancel" Click="Button_Cancel_Click" Width="180" MaxWidth="220" Height="36" HorizontalAlignment="Left" Style="StaticResource StyleButtonGeneral}"/>
</Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="WideLayoutTrigger">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="640" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="gridNewDrawing.Margin" Value="16" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="AnimationState">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="Cancel" Storyboard.TargetProperty="Visibility" Duration="0">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
When the width is above 640px; the margin on the gridNewDrawing switches to 16; but when I explicitly call the animation using
GoToState("AnimationState")
The margin on the grid defaults to 4 once again. Is there any way I can have the changes made by the adaptivetrigger persist when setting other visual styles?
The margin of the grid changes to default again because your VisualState are in same VisualStateGroup. You can set the AnimationState in another VisualStateGroup to maintain changes made by the AdaptiveTrigger.
See the Remarks of VisualStateGroup class.
The set of visual states within each VisualStateGroup should be mutually exclusive in the group. In other words, the control should be using exactly one of the visual states from each of its defined VisualStateGroup groups at all times. Whenever there's a case where a control is intended to be simultaneously in two states, make sure that the two states are in different groups.
So apply the following code should get what you want:
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="WindowStates">
<VisualState x:Name="WideLayoutTrigger">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="640" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="gridNewDrawing.Margin" Value="16" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="OtherStates">
<VisualState x:Name="AnimationState">
<Storyboard>
<ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="Cancel" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
my task seemed to me as something easy (WinRT).
All I want is to change color of Rectangle depending on state.
I know how to do it in a "cool" animated way.
The thing is that I just want my color to be changed immediately without any animation.
This is a standard, cool way:
<VisualState x:Name="UnFocused">
<Storyboard Duration="1">
<ColorAnimation To="{ThemeResource LightGrayColor}"
Storyboard.TargetName="borderBrush"
Storyboard.TargetProperty="Color"/>
</Storyboard>
</VisualState>
I thought that if I change Duration to zero then the change will be instant.
It does not work this way, color did not change at all.
So I tried "0:0:0.1" but it did not change color either.
So...
What is the current approach to change color in instant using VisualState functionality?
Thank you :-)
I don't know whether WinRT has some restrictions. At least I would also have expected that zero works fine. But you have some more options and still being cool:
<ObjectAnimationUsingKeyFrames Duration="00:00:00"
Storyboard.TargetName="borderBrush"
Storyboard.TargetProperty="Color">
<DiscreteObjectKeyFrame KeyTime="00:00:00">
<DiscreteObjectKeyFrame.Value>
<SolidColorBrush Color="{ThemeResource LightGrayColor}"/>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
or
<ColorAnimationUsingKeyFrames Storyboard.TargetName="borderBrush"
Storyboard.TargetProperty="Color">
<EasingColorKeyFrame KeyTime="0"
Value="{ThemeResource LightGrayColor}" />
</ColorAnimationUsingKeyFrames>
Turning #Jacek-Wojcik's comment into an answer:
Don't set a duration on the storyboard, set it on the ColorAnimation instead:
<VisualState x:Name="UnFocused">
<Storyboard >
<ColorAnimation Duration="0" To="{ThemeResource LightGrayColor}"
Storyboard.TargetName="borderBrush"
Storyboard.TargetProperty="Color"/>
</Storyboard>
</VisualState>
In a Windows Phone 8 app, I would like to use the animation / transition /effect used into the Windows Phone Store app when an item is selected.
Here the explanation of the animation / transition :
open the Official Windows Phone Store app
do a research
in the list of results click on an app
watch the behaviour of the title of the app (it is going on the bottom right to reappear on the page with an animation too).
I am pretty sure that I have seen this effect on several other apps. So my question could be stupid, but is there a method or something into the SDK to do this effect / animation / transition or should I do "manually" ?
Thank you in advance for your tips about the subject !
I had searched for this as well some times back but could not find any template that I need to apply in order to get the same result.
At the end, I was creating my own animations to get a similar effect.
I have a Button control which is used for a selection within my list. For the button template, I applied my own style that contains the following defintion for Visual State changes:
You can create button templates and style templates in Blend.
<Style x:Key="LongListSelectorButtonStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid Background="Transparent">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Pressed">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.Y)"
Storyboard.TargetName="ButtonBackground"
From="0"
To="-6"
Duration="00:00:0.04"/>
<DoubleAnimation Storyboard.TargetProperty="(Border.RenderTransform).(TranslateTransform.X)"
Storyboard.TargetName="ButtonBackground"
From="0"
To="2"
Duration="00:00:0.04"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Disabled"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
This animation will move the button a bit to the top right from its current position. You can change the animation to any other direction.
I've the following issue:
When I change orientation of my c#+xaml page from landscape to portrait or vice versa there is a half a second or so in which the user can see big blue parts on the screen, before the layout gets recalculated and re-rendered. These spots seem like leftovers from the previous orientation state.
I am looking for a way to hide or smoothen this extremely ragged and bumpy transition.
I tried adding an orientation change handler with a ProgressRing to cover it for 1 second, but it did not help - the handler executes after the blue spots.
Here is the code of my animation StoryBoard
<!-- The entire page respects the narrower 100-pixel margin convention for portrait -->
<VisualState x:Name="FullScreenPortrait">
<Storyboard>
<!-- Change the back button and the logo -->
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="backButton" Storyboard.TargetProperty="Style">
<DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PortraitBackButtonStyle}"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="headerLogoImage" Storyboard.TargetProperty="Width">
<DiscreteObjectKeyFrame KeyTime="0" Value="430"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="headerLogoImage" Storyboard.TargetProperty="Height">
<DiscreteObjectKeyFrame KeyTime="0" Value="49"/>
</ObjectAnimationUsingKeyFrames>
<!--Change section title and navButtons to be in two rows, by moving navButtons to the second row, first column-->
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="navButtons" Storyboard.TargetProperty="(Grid.Row)">
<DiscreteObjectKeyFrame KeyTime="0" Value="1"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="navButtons" Storyboard.TargetProperty="(Grid.Column)">
<DiscreteObjectKeyFrame KeyTime="0" Value="0"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="navButtons" Storyboard.TargetProperty="(Grid.ColumnSpan)">
<DiscreteObjectKeyFrame KeyTime="0" Value="2"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="navButtons" Storyboard.TargetProperty="Margin">
<DiscreteObjectKeyFrame KeyTime="0" Value="0,15,0,0"/>
</ObjectAnimationUsingKeyFrames>
<!--Change the grid-->
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemGridView" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="itemPortraitGridView" Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0" Value="Visible"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
Any help is appreciated, thanks!
EDIT:
I solved this by using the following method (and the help of my colleague):
/// <summary>
/// On Orientation change collapse all views, and make visible only the views for the particular new orientation
/// Also change the font size for portrait mode
/// </summary>
/// <param name="sender"></param>
private async void OnOrientationChanged(object sender)
{
headerGrid.Visibility = Visibility.Collapsed;
itemGridView.Visibility = Visibility.Collapsed;
itemPortraitGridView.Visibility = Visibility.Collapsed;
itemListView.Visibility = Visibility.Collapsed;
//Make the loading spinner temporarily visible and stop it in the StoryBoard animation for every orientation separately
LoadingView.Visibility = Visibility.Visible;
//Change the font size
if (ScreenHelper.IsInPortraitMode())
{
_viewModel.FontSizeMethod = _viewModel.GetPortraitFontSize;
}
else
{
//change font size method back
_viewModel.FontSizeMethod = _viewModel.GetLandscapeFontSize;
}
// Change visibility back to normal in case the xaml approach failed.
await Task.Delay(1000);
if (ScreenHelper.IsInPortraitMode())
itemPortraitGridView.Visibility = Windows.UI.Xaml.Visibility.Visible;
else if (ApplicationView.Value == ApplicationViewState.Snapped)
itemListView.Visibility = Windows.UI.Xaml.Visibility.Visible;
else
itemGridView.Visibility = Windows.UI.Xaml.Visibility.Visible;
headerGrid.Visibility = Visibility.Visible;
LoadingView.Visibility = Visibility.Collapsed;
}
I know you marked this complete but since I cant post a comment I have to ask here. Could you have just used easing to solve this?