3

In a wpf project I have this XAML code

<Window
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="WpfApplication1.MainWindow"
xmlns:vsm="clr-namespace:System.Windows;assembly=WPFToolkit"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480">
<vsm:VisualStateManager.VisualStateGroups>
    <vsm:VisualStateGroup x:Name="VisualStateGroup">
        <vsm:VisualState x:Name="Loading">
            <Storyboard>
                <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="control" Storyboard.TargetProperty="(UIElement.Visibility)">
                    <DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Visible}"/>
                </ObjectAnimationUsingKeyFrames>
                <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="button" Storyboard.TargetProperty="(UIElement.Visibility)">
                    <DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Collapsed}"/>
                </ObjectAnimationUsingKeyFrames>
                <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="button1" Storyboard.TargetProperty="(UIElement.Visibility)">
                    <DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Visible}"/>
                </ObjectAnimationUsingKeyFrames>
            </Storyboard>
        </vsm:VisualState>
        <VisualState x:Name="Normal">
            <Storyboard>
                <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="control" Storyboard.TargetProperty="(UIElement.Visibility)">
                    <DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Collapsed}"/>
                </ObjectAnimationUsingKeyFrames>
            </Storyboard>
        </VisualState>
    </vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>
<Grid x:Name="LayoutRoot">
    <Grid.Resources>
        <ControlTemplate x:Key="loadingAnimation">
            <Image x:Name="content" Opacity="1">
                <Image.Source>
                    <DrawingImage>
                        <DrawingImage.Drawing>
                            <DrawingGroup>
                                <GeometryDrawing Brush="Transparent">
                                    <GeometryDrawing.Geometry>
                                        <RectangleGeometry Rect="0,0,1,1"/>
                                    </GeometryDrawing.Geometry>
                                </GeometryDrawing>
                                <DrawingGroup>
                                    <DrawingGroup.Transform>
                                        <RotateTransform x:Name="angle" Angle="0" CenterX="0.5" CenterY="0.5"/>
                                    </DrawingGroup.Transform>
                                    <GeometryDrawing Geometry="M0.9,0.5 A0.4,0.4,90,1,1,0.5,0.1">
                                        <GeometryDrawing.Pen>
                                            <Pen Brush="Green" Thickness="0.1"/>
                                        </GeometryDrawing.Pen>
                                    </GeometryDrawing>
                                    <GeometryDrawing Brush="Green" Geometry="M0.5,0 L0.7,0.1 L0.5,0.2"/>
                                </DrawingGroup>
                            </DrawingGroup>
                        </DrawingImage.Drawing>
                    </DrawingImage>
                </Image.Source>
            </Image>
            <ControlTemplate.Triggers>
                <Trigger Property="Visibility" Value="Visible">
                    <Trigger.EnterActions>
                        <BeginStoryboard x:Name="animation">
                            <Storyboard>
                                <DoubleAnimation From="0" To="359" Duration="0:0:1.5" RepeatBehavior="Forever"
                                    Storyboard.TargetName="angle" Storyboard.TargetProperty="Angle"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </Trigger.EnterActions>
                    <Trigger.ExitActions>
                        <StopStoryboard BeginStoryboardName="animation"/>
                    </Trigger.ExitActions>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Grid.Resources>
    <Grid.ColumnDefinitions>
        <ColumnDefinition MinWidth="76.128" Width="Auto"/>
        <ColumnDefinition MinWidth="547.872" Width="Auto"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="0.05*"/>
        <RowDefinition Height="0.95*"/>
    </Grid.RowDefinitions>
    <Button x:Name="button" Margin="0,0,1,0.04" Width="100" Content="Load" d:LayoutOverrides="Height" Click="Button1_Click"/>
    <Button x:Name="button1" HorizontalAlignment="Left" Margin="0,0,0,0.04" Width="100" Content="Stop" Grid.Column="1" d:LayoutOverrides="Height" Click="Button2_Click" Visibility="Collapsed"/>
    <Control x:Name="control" Margin="10" Height="100" Grid.Row="1" Grid.ColumnSpan="2" Width="100" Template="{DynamicResource loadingAnimation}" Visibility="Collapsed"/>
</Grid>
</Window>

and the following code behind on the window

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            this.InitializeComponent();

        }


        private void Button1_Click(object sender, System.Windows.RoutedEventArgs e)
        {
                VisualStateManager.GoToState(this, "Loading", true);
        }

        private void Button2_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            VisualStateManager.GoToState(this, "Normal", true);
        }
    }

However, when I click the first button (button1) the state change is not being triggered. What am I doing wrong?

Thanks in advance

Román
  • 1,943
  • 2
  • 18
  • 28
  • Fix your code. Your XAML don't match your codebehind. Where is Button_Click handler? – majocha Apr 11 '10 at 23:31
  • @majocha: Sorry about that, I copied the XAML prior to doing the change. That wouldn't build, and that's not the deal here – Román Apr 12 '10 at 22:32

4 Answers4

7

According to MSDN, when you use the Visual State Manager outside of a control template, you should use the GoToElementState method, not the GoToState method. I have not tested it, though.

Timores
  • 14,439
  • 3
  • 46
  • 46
5

In fact, it is by design on .net 3.5. This guy has a workaround.

Román
  • 1,943
  • 2
  • 18
  • 28
0

Create one attached property to change the visual state. This will work for you

  public class StateManager : DependencyObject
        {
            public static string GetVisualStateProperty(DependencyObject obj)
            {
                return (string)obj.GetValue(VisualStatePropertyProperty);
            }

            public static void SetVisualStateProperty(DependencyObject obj, string value)
            {
                obj.SetValue(VisualStatePropertyProperty, value);
            }
                public static readonly DependencyProperty VisualStatePropertyProperty =
              DependencyProperty.RegisterAttached(
              "VisualStateProperty",
              typeof(string),
              typeof(StateManager),
              new PropertyMetadata((s, e) =>
              {
                  var propertyName = (string)e.NewValue;
                  var ctrl = s as Grid;  
                  if (ctrl == null)
                      throw new InvalidOperationException("This attached property only supports types derived from FrameworkElement.");
                  var transitionWorked = System.Windows.VisualStateManager.GoToElementState(ctrl, (string)e.NewValue, true);
                               }));
        }
pramod
  • 1
0

I tried your code and got an error in the designer (VS2008 SP1):

Value cannot be null.
Parameter name: value

whenever I edit the storyboard code. Reloading the xaml "fixes" the problem temporarily. The code still builds and runs, but I suspect that the cause of this error might have a bearing on your problem.

The definition of the DiscreteObjectKeyFrame looks a little off to me. The only way I've seen it done in the past is as described on this page where it's done like this:

<vsm:VisualState x:Name="Focused">
  <Storyboard>
    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="FocusVisualElement"
                          Storyboard.TargetProperty="Visibility" Duration="0">
      <DiscreteObjectKeyFrame KeyTime="0">
        <DiscreteObjectKeyFrame.Value>
          <Visibility>Visible</Visibility>
        </DiscreteObjectKeyFrame.Value>
      </DiscreteObjectKeyFrame>
    </ObjectAnimationUsingKeyFrames>
  </Storyboard>
</vsm:VisualState>

However, I tried that with your code and still couldn't get it to work, so I even if that is a problem it's not the whole problem.

ChrisF
  • 134,786
  • 31
  • 255
  • 325
  • That code was generated by Blend, so I don't know what could be wrong about it. I'm still surprised no one has come yet with a quick solution to a seemingly small problem. – Román Apr 11 '10 at 23:25
  • The problem is the code you posted don't build because there is no handler in codebehind for your first button. Make sure your code builds without errors and runs, then post it again. – majocha Apr 12 '10 at 00:54
  • @Román - OK - if Blend generated it, it must be legit. My point about the error still remains. – ChrisF Apr 12 '10 at 11:56