Warning : This page has been marked as an archive because the author consider that its content is no longer relevant.

I’ve been developing for WinRT for quiet some time now in XAML and C#. I’ve faced an issue where I needed to wait that an animation was completed before starting a piece of work in a view model. The problem was that this animation was a VisualState transition inside one of my custom controls.

My custom control represents a reversi token which has two sides, black and white. When its IsBlack property changes it triggers a visual state transition. As my application uses the MVVM pattern I needed to find a way to propagate the information that an animation has started and stopped from the custom control to the view model.

I first created added a property to my Token control :

public bool IsColourChanging
{
    get { return (bool) GetValue(IsColourChangingProperty); }
    set { SetValue(IsColourChangingProperty, value); }
}

public static readonly DependencyProperty IsColourChangingProperty =
    DependencyProperty.Register("IsColourChanging", typeof (bool), typeof(Token), new PropertyMetadata(false));

Then in the OnApplyTemplate method of the control I call the following method which is used to subscribed to the CurrentStateChanging and CurrentStateChanged events of the VisualStateGroup containing the states representing each colour :

private void HandleColourChanging()
{
    var child = VisualTreeHelper.GetChild(this, 0) as FrameworkElement;

    Debug.Assert(child != null, "Token's template must be defined !");

    var groups = VisualStateManager.GetVisualStateGroups(child);

    Debug.Assert(groups != null, "Token's VisualStateGroups should be defined!");

    // The Cast operator is not necessary in Windows 8 Metro Style Apps
    var colourGroup = groups.Cast<VisualStateGroup>().FirstOrDefault(g => g.Name == ColourStatesGroupName);

    Debug.Assert(colourGroup != null, "Token's VisualState Transition should be defined!");

    colourGroup.CurrentStateChanging += ColourGroupCurrentStateChanging;
    colourGroup.CurrentStateChanged += ColourGroupCurrentStateChanged;
}

In the ColourGroupCurrentStateChang[ing/ed] methods I now just have to set the IsColourChanging property accordingly :

private void ColourGroupCurrentStateChanging(object sender, VisualStateChangedEventArgs e)
{
    IsColourChanging = true;
}

private void ColourGroupCurrentStateChanged(object sender, VisualStateChangedEventArgs e)
{
    IsColourChanging = false;
}

At this step, every time a transition between two colours is run, the IsColourChanging is set to true until the transition complete.

So now how to propagate this information to my view models ? Using bindings of course and here’s how it can be done assuming the ItemsControl ItemsSource property is set to a collection of TokenViewModels :

<ItemsControl>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <local:Token IsBlack="{Binding IsBlack}"
                         IsColourChanging="{Binding IsAnimating, Mode=TwoWay}"
                         Width="100"
                         Height="100" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

You can see here that the IsColourChanging property of the control is bound to the IsAnimating control of its view model in a two way manner. Now it’s up to to viewmodel to react to the change of the IsAnimating property as wanted.

I consider this trick to be important as WinRT application are made to be fast and fluid and so using a lot a animations. As fast and fluid does not mean unmaintainable it’s a way among others to separate your logic between the view and the view model.

You can see a sample code in WPF in my skydrive as usual.

Hope it’ll help.

Comments