private static void OnItemsSet(DependencyObject d, DependencyPropertyChangedEventArgs e) { // If the Items property is set, create new ScoreBoardItem controls for each item, bind the appropriate values, and subscribe to any events. var scoreBoard = d as ScoreBoard; if (e.NewValue != null) { var collection = (ObservableCollection <CountryResultsViewModel>)e.NewValue; foreach (var countryResultsViewModel in collection) { var scoreBoardItem = new ScoreBoardItem() { DataContext = countryResultsViewModel, Opacity = 0 }; var binding = new Binding("TotalPoints"); binding.Source = countryResultsViewModel; scoreBoardItem.SetBinding(ScoreBoardItem.TotalPointsProperty, binding); scoreBoardItem.CurrentPointsUpdated += scoreBoard.ScoreBoardItem_CurrentPointsUpdated; scoreBoard.AddScoreBoardItem(scoreBoardItem); } } }
private static void BindItemWidthToScoreBoardWidth(ScoreBoardItem scoreBoardItem) { Binding widthBinding = new Binding("ActualWidth"); widthBinding.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(ScoreBoard), 1); scoreBoardItem.SetBinding(ScoreBoardItem.WidthProperty, widthBinding); }
private void AddScoreBoardItem(ScoreBoardItem scoreBoardItem) { BindItemWidthToScoreBoardWidth(scoreBoardItem); rootCanvas.Children.Add(scoreBoardItem); Canvas.SetTop(scoreBoardItem, nextScoreBoardItemTop); Debug.WriteLine($"AddItem: Canvas.SetTop({(scoreBoardItem.DataContext as CountryResultsViewModel).Name}, {nextScoreBoardItemTop});"); // Update the next top and animation delay values for any subsequently added ScoreBoardItems. nextScoreBoardItemTop += scoreBoardItemHeight; nextScoreBoardItemAnimationDelay = nextScoreBoardItemAnimationDelay + TimeSpan.FromSeconds(0.1); }
private void SetAnimationForScoreBoardItem(ScoreBoardItem item, double yOffset, TimeSpan beginTime) { // Add an animation that instantly sets this item's inital opacity to 0. AddDoubleAnimationToStoryboard(item, UIElement.OpacityProperty, EntranceStoryboard); // Add an animation that animates the opacity from 0 to 1 AddDoubleAnimationToStoryboard(item, UIElement.OpacityProperty, EntranceStoryboard, beginTime, TimeSpan.FromSeconds(0), 0, 1); var translateYAnimation = AddDoubleAnimationToStoryboard(item, Canvas.TopProperty, EntranceStoryboard, beginTime, TimeSpan.FromSeconds(0.7), yOffset + 180.0, yOffset); translateYAnimation.FillBehavior = FillBehavior.Stop; // This animation has to be on Stop because otherwise we can't set Canvas.Top anymore after the animation. translateYAnimation.EasingFunction = new ExponentialEase() { EasingMode = EasingMode.EaseOut, Exponent = 2.0 }; // Because FillBehavior has to be on stop, we have to manually reset the top position at the end of the animation. We do this in the Completed Event Handler. Debug.WriteLine("-------- Setting completed event"); translateYAnimation.Completed += (sender, e) => { Debug.Write("Hold on enter"); HoldEndPosition(sender); // Keep track of how many ScoreboardItem-animations we have had. When we've seen them all, fire an event so that // any subscribers know the entire animation is completed. numAnimationsCompleted++; const int numPropertiesSetInAnimation = 3; if (numAnimationsCompleted == EntranceStoryboard.Children.Count / numPropertiesSetInAnimation) // Divide the number of animations by the number of properties we set in each animation to know the "real" number of animations. { EntranceAnimationCompleted?.Invoke(this, EventArgs.Empty); numAnimationsCompleted = 0; } }; Debug.WriteLine($"ENTERING {(item.DataContext as CountryResultsViewModel).Name}({((item.DataContext as CountryResultsViewModel)).TotalPoints} points, position {Canvas.GetTop(item)}) from {translateYAnimation.From} to {translateYAnimation.To}"); }