Silverlight GotoStateAction not setting state on load

I can’t decide if this is how it’s meant to work or not.  It feels wrong…  Jason and I spent a fair amount of time today in reflector because I was having some strange behaviour in a list box.  The items didn’t have the correct visual states until I scrolled through them.

The reason why it doesn’t change visual state on load is because the StateTarget property of the GotoStateAction is null at the time the DataTrigger fires.

Once I found this out I was able to do a bit more targeted Googling…  My Google-fu was off and I couldn’t find anything to start off with.  I found this article which points out that the Style Manager in WPF and Silverlight is imperative.  The way they work around it is to create an attached property which can set the state.

You don’t notice this behaviour all the time because a lot of the time the control you’re binding to is already loaded…  If you call a service you’ll set the values once the service call completes, well after the view has loaded.  But when you’re calling a service and adding items to a list the list item hasn’t been loaded yet.  So I think it’s nasty behaviour (at least in this context), especially when in a virtulising list and it unloads / reloads the items thus changing the state!  Bug, I’m not sure…  Annoying, certainly!

What I’ve done to work around it (yet to do exhaustive testing on this but I don’t see many issues with it) is create a new trigger.  I’ve derived DataTrigger and overloaded attach / detach.  In attach I hook up to the Loaded event and call EvaluateBindingChanged.  This invokes all the attached actions and this time the StateTarget will be set.  I did think about extending GotoActionState but I thought that other actions might suffer the same problem…

So if you want to have your DataTriggers fire on load, try the code below.  I’m going to give it a go and I’ll report back any problems I find…

public class DataTriggerWhichFiresOnLoad : DataTrigger
{
    protected override void OnAttached()
    {
        base.OnAttached();
 
        var element = this.AssociatedObject as FrameworkElement;
        if (element == null)
        {
            return;
        }
        element.Loaded += InvokeActionsOnLoad;
    }
 
    protected override void OnDetaching()
    {
        var element = this.AssociatedObject as FrameworkElement;
        if (element != null)
        {
            element.Loaded -= this.InvokeActionsOnLoad;
        }
        base.OnDetaching();
    }
 
    private void InvokeActionsOnLoad(object sender, RoutedEventArgs e)
    {
        this.EvaluateBindingChange(null);
    }
}

About Tom Peplow

C# .Net developer based in London and the South Coast
This entry was posted in Uncategorized and tagged . Bookmark the permalink.

7 Responses to Silverlight GotoStateAction not setting state on load

  1. Ken says:

    I ran into this problem today as well. Interesting approach, thanks for posting it

  2. Ben says:

    SWEET! Saved me some time and headache… 🙂

  3. Kevin says:

    Thank you! I was fighting this all afternoon. I found you’re post through http://stackoverflow.com/questions/6508098/silverlight-datatrigger-not-firing-on-load

  4. Mike says:

    Alas, this doesn’t work for WPF, which has exact same problem. The reason it doesn’t work is that the DataTrigger class is built differently, and has no OnAttached / …

  5. Mike says:

    Too early comment. One needs to inherit from Microsoft.Expression.Interactivity.Core.DataTrigger, then it works. Thanks a lot!

Leave a comment