private async Task PlayRecord(CBoardRecordData boardRecord, CancellationToken token) { foreach (CSerializedRecordAtom serializedRecordAtom in boardRecord.Data) { if (token.IsCancellationRequested) { return; } switch (serializedRecordAtom.Type) { case EAtomType.Movement: CMovementData movementData = Deserialize <CMovementData>(serializedRecordAtom); Thickness from = new Thickness(movementData.From.X, movementData.From.Y, 0, 0); Thickness to = new Thickness(movementData.To.X, movementData.To.Y, 0, 0); _pieces[movementData.PieceId].BeginAnimation(FrameworkElement.MarginProperty, new ThicknessAnimation { From = from, To = to, SpeedRatio = CPiece.PieceSize / from.Difference(to) }); break; case EAtomType.PieceRemoved: CPieceRemovedData pieceRemovedData = Deserialize <CPieceRemovedData>(serializedRecordAtom); _attachedRecordPlayer.BoardCanvas.Children.Remove(_pieces[pieceRemovedData.PieceId]); _pieces.Remove(pieceRemovedData.PieceId); break; case EAtomType.Wait: CWaitData waitData = Deserialize <CWaitData>(serializedRecordAtom); try { await Task.Delay(waitData.WaitTimeSpan, token); } catch { return; } break; case EAtomType.PawnTransformed: CPawnTransformedData pawnTransformedData = Deserialize <CPawnTransformedData>(serializedRecordAtom); _pieces[pawnTransformedData.PieceId].Source = new BitmapImage(new Uri( $"/Images/{(pawnTransformedData.IsWhite ? EPieceColor.White : EPieceColor.Black)}/Queen.png", UriKind.RelativeOrAbsolute)); break; default: throw new ArgumentException($"Unknown atom type: {serializedRecordAtom.Type}"); } } }