private void MainGrid_MouseUp(object sender, MouseButtonEventArgs e) { Mouse.Capture(null); MainGrid.MouseMove -= MainGrid_MouseMoveWhenDown; MainGrid.MouseMove += MainGrid_MouseMoveWhenUp; if (pmm != null) { pmm = null; // End of visual feed-back, align on grid, and update ViewModel // Round position to closest square on the grid List <PositionOrientation> topLeftList = new List <PositionOrientation>(); foreach (WordAndCanvas wac in m_Sel.WordAndCanvasList) { WordCanvas wc = wac.WordCanvas; int top = (int)Math.Floor((double)wc.GetValue(Canvas.TopProperty) / UnitSize + 0.5); int left = (int)Math.Floor((double)wc.GetValue(Canvas.LeftProperty) / UnitSize + 0.5); topLeftList.Add(new PositionOrientation(top, left, wac.WordPosition.IsVertical)); } // Do not accept Illegal placements, adjust to only valid placements AdjustToSuitableLocationInLayout(m_FixedLayout, m_Sel.WordAndCanvasList, topLeftList, true); // Move to final, rounded position viewModel.UpdateWordPositionLocation(m_Sel.WordAndCanvasList, topLeftList, true); // Update WordPosition with new location MoveWordAndCanvasList(m_Sel.WordAndCanvasList); // Visual animation FinalRefreshAfterUpdate(); } }
internal void MoveWordAndCanvasList(IList <WordAndCanvas> wordAndCanvasList) { if (wordAndCanvasList == null) { throw new ArgumentNullException(nameof(wordAndCanvasList)); } if (wordAndCanvasList.Count == 0) { throw new ArgumentException("Zero words in list", nameof(wordAndCanvasList)); } // If bounding rectangle is updated, need to redraw background grid BoundingRectangle r = viewModel.Layout.Bounds; if (!r.Equals(gridBounding)) { UpdateBackgroundGrid(); } // Compute distance moved on 1st element to choose animation speed (duration) WordPosition wp1 = wordAndCanvasList.First().WordPosition; WordCanvas wc1 = wordAndCanvasList.First().WordCanvas; double deltaX = (double)wc1.GetValue(Canvas.LeftProperty) - wp1.StartColumn * UnitSize; double deltaY = (double)wc1.GetValue(Canvas.TopProperty) - wp1.StartRow * UnitSize; double distance = Math.Sqrt(deltaX * deltaX + deltaY * deltaY); // If distance is null, for instance after a selection click, we're done if (distance <= 0.0001) { return; } // Group animations in a storyboard to simplify premature ending var sb = new Storyboard(); var duration = new Duration(TimeSpan.FromSeconds(distance >= UnitSize ? 0.35 : 0.1)); finalMoveWordAnimationData = new List <(Canvas, DependencyProperty, double)>(); foreach (WordAndCanvas wac in wordAndCanvasList) { WordCanvas wc = wac.WordCanvas; double finalLeftValue = wac.WordPosition.StartColumn * UnitSize; DoubleAnimation daLeft = new DoubleAnimation { Duration = duration, From = (double)wc.GetValue(Canvas.LeftProperty), To = finalLeftValue }; Storyboard.SetTarget(daLeft, wc); Storyboard.SetTargetProperty(daLeft, new PropertyPath("Left")); sb.Children.Add(daLeft); finalMoveWordAnimationData.Add((wc, Canvas.LeftProperty, finalLeftValue)); double finalTopValue = wac.WordPosition.StartRow * UnitSize; DoubleAnimation daTop = new DoubleAnimation { Duration = duration, From = (double)wc.GetValue(Canvas.TopProperty), To = finalTopValue }; Storyboard.SetTarget(daTop, wc); Storyboard.SetTargetProperty(daTop, new PropertyPath("Top")); sb.Children.Add(daTop); finalMoveWordAnimationData.Add((wc, Canvas.TopProperty, finalTopValue)); } IsMoveWordAnimationInProgress = true; sb.Completed += Sb_Completed; sb.Begin(); }