public void ChangeTrackSegmentEndFrameTest() { SetupViewModel(useRealUndoService: true); SegmentViewModelBase segmentToTest = _viewModel.TimelineSegments[0]; int newEndFrame = 15; int originalEndFrame = segmentToTest.EndFrame; Assert.True(_viewModel.CanChangeTrackSegmentEndFrame(segmentToTest, newEndFrame)); _viewModel.ChangeTrackSegmentEndFrame(segmentToTest, newEndFrame); Assert.Equal(newEndFrame, segmentToTest.EndFrame); Assert.Equal(2, segmentToTest.Model.KeyFrames.Count); Assert.Equal(2, segmentToTest.KeyFrameViewModels.Count); Assert.Equal(segmentToTest.StartFrame, segmentToTest.KeyFrameViewModels[0].FrameNumber); Assert.Equal(10, segmentToTest.KeyFrameViewModels[1].FrameNumber); Assert.True(_undoRoot.CanUndo); _undoRoot.Undo(); Assert.Equal(originalEndFrame, segmentToTest.EndFrame); Assert.Equal(3, segmentToTest.Model.KeyFrames.Count); Assert.Equal(3, segmentToTest.KeyFrameViewModels.Count); Assert.Equal(segmentToTest.StartFrame, segmentToTest.KeyFrameViewModels[0].FrameNumber); Assert.Equal(10, segmentToTest.KeyFrameViewModels[1].FrameNumber); Assert.Equal(22, segmentToTest.KeyFrameViewModels[2].FrameNumber); }
/// <summary> /// Handles the <see cref="UIElement.MouseMove"/> routed event for a <see cref="VideoTimelineSegment"/> element. /// </summary> /// <remarks> /// Can't use Preview Mouse events as the <see cref="VideoTimelineSegment"/> element's border <see cref="Thumb"/>s /// have to have the first chance to handle the event. /// </remarks> /// <inheritdoc cref="MouseEventHandler"/> private void OnTimelineSegmentMouseMove(object sender, MouseEventArgs e) { if (!_isDraggingSegment && e.LeftButton == MouseButtonState.Pressed && _segmentDragOrigin.HasValue) { Point mousePosition = e.GetPosition(tracksListBox); if (Math.Abs(mousePosition.X - _segmentDragOrigin.Value.X) >= SystemParameters.MinimumHorizontalDragDistance || Math.Abs(mousePosition.Y - _segmentDragOrigin.Value.Y) >= SystemParameters.MinimumVerticalDragDistance) { VideoTimelineSegment draggedSegmentElement = sender as VideoTimelineSegment; Debug.Assert(draggedSegmentElement != null); SegmentViewModelBase draggedSegmentViewModel = draggedSegmentElement.DataContext as SegmentViewModelBase; Debug.Assert(draggedSegmentViewModel != null); _isDraggingSegment = true; DataObject dataObject = new DataObject(); dataObject.SetData(typeof(SegmentViewModelWeakReference), new SegmentViewModelWeakReference(draggedSegmentViewModel)); dataObject.SetData(typeof(Size), draggedSegmentElement.RenderSize); DragDrop.DoDragDrop(tracksListBox, dataObject, DragDropEffects.Copy | DragDropEffects.Move); } } }
/// <inheritdoc/> public override SegmentViewModelBase CreateSegmentModelViewModel(SegmentViewModelBase sourceViewModel, int?trackNumber = null, int?startFrame = null, int?endFrame = null, string name = null, KeyFrameViewModelCollection keyFrameViewModels = null) { int newTrackNumber = trackNumber.GetValueOrDefault(sourceViewModel.TrackNumber); int newStartFrame = startFrame.GetValueOrDefault(sourceViewModel.StartFrame); int newEndFrame = endFrame.GetValueOrDefault(sourceViewModel.EndFrame); string newName = name ?? sourceViewModel.Name; KeyFrameModelCollection keyFrameModels = keyFrameViewModels != null ? GetKeyFrameModels(keyFrameViewModels) : GetKeyFrameModels(sourceViewModel.KeyFrameViewModels, true, newStartFrame - sourceViewModel.StartFrame); return(new MockSegmentViewModel( new MockSegmentModel(newStartFrame, newEndFrame, newTrackNumber, keyFrameModels, newName), _scriptVideoContext, _rootUndoObject, _undoService, _undoChangeFactory, _clipboardService, keyFrameViewModels )); }
public void CanMoveTrackSegmentTest() { SetupViewModel(useRealUndoService: false); SegmentViewModelBase segmentToMove = _timelineSegmentProvidingViewModel.SegmentViewModels[6]; Assert.True( _viewModel.CanMoveTrackSegment(segmentToMove, 2, 0) ); Assert.False( _viewModel.CanMoveTrackSegment(segmentToMove, 1, 1) ); segmentToMove = _timelineSegmentProvidingViewModel.SegmentViewModels[5]; Assert.True( _viewModel.CanMoveTrackSegment(segmentToMove, 1, 1) ); }
/// <summary> /// Handles the <see cref="VideoTimelineSegment.HorizontalResizeDragCompletedEvent"/> attached event /// for a <see cref="VideoTimelineSegment"/> element. /// </summary> /// <inheritdoc cref="HorizontalResizeDragCompletedEventHandler"/> private void OnTrackSegmentHorizontalResizeDragCompleted(object sender, HorizontalResizeDragCompletedEventArgs e) { if (_isResizingSegment) { VideoTimelineSegment segmentElement = e.OriginalSource as VideoTimelineSegment; Debug.Assert(segmentElement != null); VideoTimelineTrack trackElement = segmentElement.ParentTrackElement; SegmentViewModelBase segmentViewModel = segmentElement.DataContext as SegmentViewModelBase; Debug.Assert(segmentViewModel != null); int frameDiff = (int)Math.Round(_segmentResizeAdorner.HorizontalOffset / trackElement.PixelsPerFrame); if (frameDiff != 0) { if (e.HorizontalSide == HorizontalSide.Left) { int newStartFrame = segmentViewModel.StartFrame + frameDiff; ViewModel.ChangeTrackSegmentStartFrame(segmentViewModel, newStartFrame); } else // e.HorizontalSide == HorizontalSide.Right { int newEndFrame = segmentViewModel.EndFrame + frameDiff; ViewModel.ChangeTrackSegmentEndFrame(segmentViewModel, newEndFrame); } } segmentElement.Clip = null; _segmentResizeAdorner?.Detach(); _segmentResizeAdorner = null; _isResizingSegment = false; } e.Handled = true; }
[InlineData(20)] // 'Contract' test public void ChangeTrackSegmentStartFrame_SingleKeyFrame_Test(int newStartFrame) { SetupViewModel(useRealUndoService: true); SegmentViewModelBase segmentToTest = _viewModel.TimelineSegments[8]; int originalStartFrame = segmentToTest.StartFrame; Assert.True(_viewModel.CanChangeTrackSegmentStartFrame(segmentToTest, newStartFrame)); _viewModel.ChangeTrackSegmentStartFrame(segmentToTest, newStartFrame); Assert.Equal(newStartFrame, segmentToTest.StartFrame); Assert.Single(segmentToTest.Model.KeyFrames); Assert.Single(segmentToTest.KeyFrameViewModels); Assert.Equal(newStartFrame, segmentToTest.KeyFrameViewModels[0].FrameNumber); Assert.True(_undoRoot.CanUndo); _undoRoot.Undo(); Assert.Equal(originalStartFrame, segmentToTest.StartFrame); Assert.Single(segmentToTest.Model.KeyFrames); Assert.Single(segmentToTest.KeyFrameViewModels); Assert.Equal(originalStartFrame, segmentToTest.KeyFrameViewModels[0].FrameNumber); }
/// <summary> /// Handles the <see cref="UIElement.PreviewDrop"/> routed event for the <see cref="tracksListBox"/>. /// </summary> /// <remarks>Completes a <see cref="VideoTimelineSegment"/> dragging operation.</remarks> /// <inheritdoc cref="DragEventHandler"/> private void OnTracksListBoxPreviewDrop(object sender, DragEventArgs e) { if (e.Effects != DragDropEffects.None) { bool isAdding = false; bool isCopying = false; bool isMoving = false; SegmentViewModelBase segmentViewModel = null; Enum addableSegmentType = null; int? draggedItemStartFrame = null; int draggedItemFrameDuration = 0; if (e.Data.GetDataPresent(typeof(SegmentViewModelWeakReference))) { if (!(e.Data.GetData(typeof(SegmentViewModelWeakReference)) is SegmentViewModelWeakReference segmentViewModelRef) || !segmentViewModelRef.TryGetTarget(out segmentViewModel)) { throw new InvalidOperationException($"Invalid reference to a {nameof(SegmentViewModelBase)} object."); } draggedItemStartFrame = segmentViewModel.StartFrame; draggedItemFrameDuration = segmentViewModel.FrameDuration; if (e.Effects.HasFlag(DragDropEffects.Copy) && e.KeyStates.HasFlag(DragDropKeyStates.ControlKey)) { isCopying = true; } else if (e.Effects.HasFlag(DragDropEffects.Move)) { isMoving = true; } } else if (e.Data.GetDataPresent(typeof(WeakReference <AddTrackSegmentCommandParameters>))) { if (!(e.Data.GetData(typeof(WeakReference <AddTrackSegmentCommandParameters>)) is WeakReference <AddTrackSegmentCommandParameters> addTrackSegmentActionDataRef) || !addTrackSegmentActionDataRef.TryGetTarget(out AddTrackSegmentCommandParameters addTrackSegmentActionData)) { throw new InvalidOperationException($"Invalid reference to a {nameof(AddTrackSegmentCommandParameters)} object."); } addableSegmentType = addTrackSegmentActionData.SegmentTypeDescriptor; draggedItemStartFrame = 0; draggedItemFrameDuration = addTrackSegmentActionData.FrameDuration; isAdding = true; } if (draggedItemStartFrame.HasValue && TryFindTrackElementAndClosestFrameNumber(e, draggedItemStartFrame.Value, out VideoTimelineTrack timelineTrackElement, out int closestFrameNumber)) { if (isAdding) { ViewModel.AddTrackSegment(addableSegmentType, timelineTrackElement.TrackNumber, closestFrameNumber, draggedItemFrameDuration); } else if (isCopying) { ViewModel.CopyTrackSegment(segmentViewModel, timelineTrackElement.TrackNumber, closestFrameNumber); } else if (isMoving) { ViewModel.MoveTrackSegment(segmentViewModel, timelineTrackElement.TrackNumber, closestFrameNumber); } } } EndSegmentDrag(); e.Handled = true; }
/// <summary> /// Handles the <see cref="UIElement.PreviewDragOver"/> routed event for the <see cref="tracksListBox"/>. /// </summary> /// <remarks>Performs validation for a <see cref="VideoTimelineSegment"/> dragging operation.</remarks> /// <inheritdoc cref="DragEventHandler"/> private void OnTracksListBoxPreviewDragOver(object sender, DragEventArgs e) { e.Effects = DragDropEffects.None; if (_isDraggingSegment && _segmentDragOrigin.HasValue) { SegmentViewModelBase segmentViewModel = null; int?draggedItemStartFrame = null; int draggedItemFrameDuration = 0; if (e.Data.GetDataPresent(typeof(SegmentViewModelWeakReference))) { if (!(e.Data.GetData(typeof(SegmentViewModelWeakReference)) is SegmentViewModelWeakReference segmentViewModelRef) || !segmentViewModelRef.TryGetTarget(out segmentViewModel)) { throw new InvalidOperationException($"Invalid reference to a {nameof(SegmentViewModelBase)} object."); } draggedItemStartFrame = segmentViewModel.StartFrame; draggedItemFrameDuration = segmentViewModel.FrameDuration; } else if (e.Data.GetDataPresent(typeof(WeakReference <AddTrackSegmentCommandParameters>))) { if (!(e.Data.GetData(typeof(WeakReference <AddTrackSegmentCommandParameters>)) is WeakReference <AddTrackSegmentCommandParameters> addTrackSegmentActionDataRef) || !addTrackSegmentActionDataRef.TryGetTarget(out AddTrackSegmentCommandParameters addTrackSegmentActionData)) { throw new InvalidOperationException($"Invalid reference to a {nameof(AddTrackSegmentCommandParameters)} object."); } draggedItemStartFrame = 0; draggedItemFrameDuration = addTrackSegmentActionData.FrameDuration; } if (draggedItemStartFrame.HasValue && TryFindTrackElementAndClosestFrameNumber(e, draggedItemStartFrame.Value, out VideoTimelineTrack timelineTrackElement, out int closestFrameNumber)) { if (e.AllowedEffects == DragDropEffects.Copy || (e.AllowedEffects.HasFlag(DragDropEffects.Copy) && e.KeyStates.HasFlag(DragDropKeyStates.ControlKey))) { if (ViewModel.CanAddTrackSegment(timelineTrackElement.TrackNumber, closestFrameNumber, draggedItemFrameDuration)) { e.Effects = DragDropEffects.Copy; } } else if (e.AllowedEffects.HasFlag(DragDropEffects.Move) && ViewModel.CanMoveTrackSegment(segmentViewModel, timelineTrackElement.TrackNumber, closestFrameNumber)) { e.Effects = DragDropEffects.Move; } _segmentDragAdorner.PositionOffset = timelineTrackElement.TranslatePoint(new Point(closestFrameNumber * timelineTrackElement.PixelsPerFrame, 0d), tracksListBox); _segmentDragAdorner.ToolTipData.StartFrame = closestFrameNumber; _segmentDragAdorner.ToolTipData.EndFrame = closestFrameNumber + draggedItemFrameDuration - 1; } _segmentDragAdorner.IsDragValid = e.Effects == DragDropEffects.Move || e.Effects == DragDropEffects.Copy; } e.Handled = true; }
/// <summary> /// Handles the <see cref="VideoTimelineSegment.HorizontalResizeDraggingEvent"/> attached event /// for a <see cref="VideoTimelineSegment"/> element. /// </summary> /// <inheritdoc cref="HorizontalResizeDraggingEventHandler"/> private void OnTrackSegmentHorizontalResizeDragging(object sender, HorizontalResizeDragEventArgs e) { e.Handled = true; VideoTimelineSegment segmentElement = e.OriginalSource as VideoTimelineSegment; Debug.Assert(segmentElement != null); VideoTimelineTrack trackElement = segmentElement.ParentTrackElement; SegmentViewModelBase segmentViewModel = segmentElement.DataContext as SegmentViewModelBase; Debug.Assert(segmentViewModel != null); int frameDiff = (int)Math.Round(e.HorizontalChange / trackElement.PixelsPerFrame); if (frameDiff == 0) { return; } int proposedStartFrame = segmentViewModel.StartFrame; int proposedEndFrame = segmentViewModel.EndFrame; double framePixelOffset = trackElement.PixelsPerFrame * frameDiff; bool isContracting = false; Rect segmentElementClipRect; if (e.HorizontalSide == HorizontalSide.Left) { proposedStartFrame += frameDiff; if (!ViewModel.CanChangeTrackSegmentStartFrame(segmentViewModel, proposedStartFrame)) { return; } if (frameDiff > 0) { isContracting = true; segmentElementClipRect = new Rect(framePixelOffset, 0d, segmentElement.ActualWidth - framePixelOffset, segmentElement.ActualHeight); } } else // e.HorizontalSide == HorizontalSide.Right { proposedEndFrame += frameDiff; if (!ViewModel.CanChangeTrackSegmentEndFrame(segmentViewModel, proposedEndFrame)) { return; } if (frameDiff < 0) { isContracting = true; segmentElementClipRect = new Rect( new Size(segmentElement.ActualWidth + framePixelOffset, segmentElement.ActualHeight) ); } } if (isContracting) { if (segmentElement.Clip is RectangleGeometry rectangleGeometry) { rectangleGeometry.Rect = segmentElementClipRect; } else { segmentElement.Clip = new RectangleGeometry(segmentElementClipRect); } } else { segmentElement.Clip = null; } if (_segmentResizeAdorner == null) { UIElement segmentElementContainer = segmentElement.TemplatedParent as UIElement; Debug.Assert(segmentElementContainer != null); _segmentResizeAdorner = new TrackSegmentResizeAdorner(adornedElement: trackElement, segmentElement, segmentElementLeftCoordinate: Canvas.GetLeft(segmentElementContainer), attachPosition: e.HorizontalSide); _segmentResizeAdorner.Attach(); _isResizingSegment = true; } _segmentResizeAdorner.HorizontalOffset = framePixelOffset; _segmentResizeAdorner.ToolTipData.StartFrame = proposedStartFrame; _segmentResizeAdorner.ToolTipData.EndFrame = proposedEndFrame; }
public void MoveTrackSegmentTest(int preTestFrameNumber, int preTestTrackIndex, int segmentViewModelIndex, bool isSelectedSegmentPreMove, int newTrackNumber, int newStartFrame) { SetupViewModel(useRealUndoService: true); IScriptVideoContext svc = _scriptVideoContextMock.Object; if (svc.FrameNumber != preTestFrameNumber) { svc.FrameNumber = preTestFrameNumber; } _viewModel.SelectedTrack = _viewModel.TimelineTrackCollection[preTestTrackIndex]; SegmentViewModelBase segmentToMove = _timelineSegmentProvidingViewModel.SegmentViewModels[segmentViewModelIndex]; Assert.Equal(isSelectedSegmentPreMove, segmentToMove == _viewModel.TimelineSegmentProvidingViewModel.SelectedSegment); int originalTrackNumber = segmentToMove.TrackNumber; int originalStartFrame = segmentToMove.StartFrame; int originalEndFrame = segmentToMove.EndFrame; int newEndFrame = newStartFrame + segmentToMove.FrameDuration - 1; // Key frame tests int startFrameOffset = newStartFrame - originalStartFrame; int[] originalKeyFrameNumbers = segmentToMove.KeyFrameViewModels.Select(kfvm => kfvm.FrameNumber).ToArray(); _viewModel.MoveTrackSegment(segmentToMove, newTrackNumber, newStartFrame); Assert.Equal(newTrackNumber, segmentToMove.TrackNumber); Assert.Equal(newStartFrame, segmentToMove.StartFrame); Assert.Equal(newEndFrame, segmentToMove.EndFrame); Assert.Equal(1, _viewModel.TimelineSegments.Count(segment => segment == segmentToMove)); Assert.DoesNotContain(segmentToMove, _viewModel.TimelineTrackCollection[originalTrackNumber].TrackSegments); Assert.Contains(segmentToMove, _viewModel.TimelineTrackCollection[newTrackNumber].TrackSegments); // Key frame tests for (int i = 0; i < segmentToMove.KeyFrameViewModels.Count; i++) { Assert.Equal(originalKeyFrameNumbers[i] + startFrameOffset, segmentToMove.KeyFrameViewModels[i].FrameNumber); } if (isSelectedSegmentPreMove) { Assert.False(segmentToMove == _viewModel.TimelineSegmentProvidingViewModel.SelectedSegment); } Assert.True(_undoRoot.CanUndo); _undoRoot.Undo(); Assert.Equal(originalTrackNumber, segmentToMove.TrackNumber); Assert.Equal(originalStartFrame, segmentToMove.StartFrame); Assert.Equal(originalEndFrame, segmentToMove.EndFrame); Assert.Equal(1, _viewModel.TimelineSegments.Count(segment => segment == segmentToMove)); Assert.DoesNotContain(segmentToMove, _viewModel.TimelineTrackCollection[newTrackNumber].TrackSegments); Assert.Contains(segmentToMove, _viewModel.TimelineTrackCollection[originalTrackNumber].TrackSegments); // Key frame tests for (int i = 0; i < segmentToMove.KeyFrameViewModels.Count; i++) { Assert.Equal(originalKeyFrameNumbers[i], segmentToMove.KeyFrameViewModels[i].FrameNumber); } Assert.Equal(isSelectedSegmentPreMove, segmentToMove == _viewModel.TimelineSegmentProvidingViewModel.SelectedSegment); }
public void JoinTrackSegmentRightCommandTest(int frameNumber, int trackIndex, int trackSegmentIndex, bool expectedCanExecute, bool expectedRightSelectedSegment) { SetupViewModel(useRealUndoService: expectedCanExecute); IScriptVideoContext svc = _scriptVideoContextMock.Object; if (svc.FrameNumber != frameNumber) { svc.FrameNumber = frameNumber; } IVideoTimelineTrackViewModel timelineTrack = _viewModel.TimelineTrackCollection[trackIndex]; SegmentViewModelBase segmentLeftViewModel = timelineTrack.TrackSegments[trackSegmentIndex]; int segmentLeftEndFrame = segmentLeftViewModel.EndFrame; int segmentLeftKeyFrameCount = segmentLeftViewModel.KeyFrameViewModels.Count; SegmentViewModelBase segmentRightViewModel; int segmentRightKeyFrameCount; Assert.Equal(expectedCanExecute, _viewModel.MergeTrackSegmentRightCommand.CanExecute(segmentLeftViewModel)); if (expectedCanExecute) { segmentRightViewModel = timelineTrack.TrackSegments[trackSegmentIndex + 1]; Assert.Equal(expectedRightSelectedSegment, segmentRightViewModel == _viewModel.TimelineSegmentProvidingViewModel.SelectedSegment); segmentRightKeyFrameCount = segmentRightViewModel.KeyFrameViewModels.Count; _viewModel.MergeTrackSegmentRightCommand.Execute(segmentLeftViewModel); RunPreUndoTests(); _undoRoot.Undo(); RunPostUndoTests(); _undoRoot.Redo(); RunPreUndoTests(); } void RunPreUndoTests() { Assert.Empty(segmentRightViewModel.KeyFrameViewModels); Assert.Empty(segmentRightViewModel.Model.KeyFrames); Assert.DoesNotContain(segmentRightViewModel, _viewModel.TimelineSegments); Assert.DoesNotContain(segmentRightViewModel, timelineTrack.TrackSegments); Assert.Equal(segmentLeftKeyFrameCount + segmentRightKeyFrameCount, segmentLeftViewModel.KeyFrameViewModels.Count); Assert.Equal(segmentLeftKeyFrameCount + segmentRightKeyFrameCount, segmentLeftViewModel.Model.KeyFrames.Count); Assert.Equal(segmentRightViewModel.EndFrame, segmentLeftViewModel.EndFrame); if (expectedRightSelectedSegment) { Assert.False(segmentRightViewModel == _viewModel.TimelineSegmentProvidingViewModel.SelectedSegment); Assert.True(segmentLeftViewModel == _viewModel.TimelineSegmentProvidingViewModel.SelectedSegment); } Assert.True(_undoRoot.CanUndo); } void RunPostUndoTests() { Assert.Contains(segmentRightViewModel, _viewModel.TimelineSegments); Assert.Contains(segmentRightViewModel, timelineTrack.TrackSegments); Assert.Equal(segmentLeftEndFrame, segmentLeftViewModel.EndFrame); Assert.Equal(segmentLeftKeyFrameCount, segmentLeftViewModel.KeyFrameViewModels.Count); Assert.Equal(segmentLeftKeyFrameCount, segmentLeftViewModel.Model.KeyFrames.Count); Assert.Equal(segmentRightKeyFrameCount, segmentRightViewModel.KeyFrameViewModels.Count); Assert.Equal(segmentRightKeyFrameCount, segmentRightViewModel.Model.KeyFrames.Count); if (expectedRightSelectedSegment) { Assert.False(segmentLeftViewModel == _viewModel.TimelineSegmentProvidingViewModel.SelectedSegment); Assert.True(segmentRightViewModel == _viewModel.TimelineSegmentProvidingViewModel.SelectedSegment); } Assert.True(_undoRoot.CanRedo); } }
public void SplitSelectedTrackSegmentCommandTest(int trackNumber, int frameNumber, int[] expectedToSplitKeyFrameNumbers, int[] expectedSplitKeyFrameNumbers) { SetupViewModel(useRealUndoService: true); IScriptVideoContext svc = _scriptVideoContextMock.Object; if (_viewModel.SelectedTrack.TrackNumber != trackNumber) { _viewModel.SelectedTrack = _viewModel.TimelineTrackCollection[trackNumber]; } if (svc.FrameNumber != frameNumber) { svc.FrameNumber = frameNumber; } Assert.NotNull(_viewModel.TimelineSegmentProvidingViewModel.SelectedSegment); SegmentViewModelBase segmentViewModelToSplit = _viewModel.TimelineSegmentProvidingViewModel.SelectedSegment; int originalEndFrame = segmentViewModelToSplit.EndFrame; int[] originalKeyFrameNumbers = segmentViewModelToSplit.KeyFrameViewModels.Select(kfvm => kfvm.FrameNumber).ToArray(); Assert.True( _viewModel.SplitSelectedTrackSegmentCommand.CanExecute() ); _viewModel.SplitSelectedTrackSegmentCommand.Execute(); SegmentViewModelBase splitSegmentViewModel; RunPreUndoTests(); _undoRoot.Undo(); RunPostUndoTests(); _undoRoot.Redo(); RunPreUndoTests(); void RunPreUndoTests() { Assert.NotNull(_viewModel.TimelineSegmentProvidingViewModel.SelectedSegment); Assert.NotSame(segmentViewModelToSplit, _viewModel.TimelineSegmentProvidingViewModel.SelectedSegment); Assert.False( _viewModel.SplitSelectedTrackSegmentCommand.CanExecute() ); splitSegmentViewModel = _viewModel.TimelineSegmentProvidingViewModel.SelectedSegment; Assert.Equal(frameNumber - 1, segmentViewModelToSplit.EndFrame); Assert.Equal(expectedToSplitKeyFrameNumbers.Length, segmentViewModelToSplit.KeyFrameViewModels.Count); for (int i = 0; i < expectedToSplitKeyFrameNumbers.Length; i++) { Assert.Equal(expectedToSplitKeyFrameNumbers[i], segmentViewModelToSplit.KeyFrameViewModels[i].FrameNumber); } Assert.Equal(frameNumber, splitSegmentViewModel.StartFrame); Assert.Equal(originalEndFrame, splitSegmentViewModel.EndFrame); Assert.Equal(expectedSplitKeyFrameNumbers.Length, splitSegmentViewModel.KeyFrameViewModels.Count); for (int i = 0; i < expectedSplitKeyFrameNumbers.Length; i++) { Assert.Equal(expectedSplitKeyFrameNumbers[i], splitSegmentViewModel.KeyFrameViewModels[i].FrameNumber); } Assert.True(_undoRoot.CanUndo); } void RunPostUndoTests() { Assert.Same(segmentViewModelToSplit, _viewModel.TimelineSegmentProvidingViewModel.SelectedSegment); Assert.DoesNotContain(splitSegmentViewModel, _viewModel.TimelineSegments); Assert.True( _viewModel.SplitSelectedTrackSegmentCommand.CanExecute() ); Assert.Equal(originalEndFrame, segmentViewModelToSplit.EndFrame); Assert.Equal(originalKeyFrameNumbers.Length, segmentViewModelToSplit.KeyFrameViewModels.Count); for (int i = 0; i < originalKeyFrameNumbers.Length; i++) { Assert.Equal(originalKeyFrameNumbers[i], segmentViewModelToSplit.KeyFrameViewModels[i].FrameNumber); } Assert.True(_undoRoot.CanRedo); } }