The answer to this is that it is not possible - not in Silverlight 3 anyway.
Using a debugger i was able to find a private property of the Storyboard that when i walked it up the object tree i got to the containing template item - however i couldn't touch this from code using reflection due to the security restrictions placed upon silverlight apps (this may well be possible in WPF though).
My eventual solution involved using a Dictionary<Storyboard, Grid>
, and a couple of event handlers. With the template i attached a Loaded
handler, this means my handler gets called everytime an instance of the template is created and loaded (i.e. for every data item that is bound to the listbox). At this point, i have a reference to the physical instance of the template, so i can search its children for the storyboard:
private void ItemTemplate_Loaded(object sender, RoutedEventArgs e)
{
Storyboard s = getStoryBoard(sender);
if (s != null)
{
if (!_startedStoryboards.ContainsKey(s))
_startedStoryboards.Add(s, (Grid)sender);
}
}
private Storyboard getStoryBoard(object container)
{
Grid g = container as Grid;
if (g != null)
{
if (g.Resources.Contains("FadeOut"))
{
Storyboard s = g.Resources["FadeOut"] as Storyboard;
return s;
}
}
return null;
}
private Dictionary<Storyboard, Grid> _startedStoryboards = new Dictionary<Storyboard, Grid>();
Then when the storyboard's Completed
event is fired, i can easily use this dictionary as a lookup to retrieve the item template it was hosted within, and from there i can get the DataContext
of the item template and do the nasty things i planned:
private void FadeOut_Completed(object sender, EventArgs e)
{
if (_startedStoryboards.ContainsKey((Storyboard)sender))
{
Grid g = _startedStoryboards[(Storyboard)sender];
if (g.DataContext != null)
{
MyDataItem z = g.DataContext as MyDataItem;
if (z != null)
{
... do my thing ...
}
}
}
}
[Note: this code has been sanitized for public viewing, excuse any small discrepancies or syntactical errors you may spot]