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...