//
        void FrameUpdate(object sender, EventArgs e)
        {
            if (_isRunningFrameUpdate)
            {
                return;
            }

            _isRunningFrameUpdate = true;

            // Movement range
            var max = SliderBottom;
            var min = -max;

            _stopwatch.Start();


            if (IsMouseMoveEnabled)
            {
                // Draw all points always
                // Draw on the drawing context
                using (DrawingContext dc = _drawingVisual.RenderOpen())
                {
                    // --- logic
                    _animation.SelectMovingDots(DotsMovingCount);                                                    // Select p to be moved
                    _animation.UpdateMovingPosition(min, max);                                                       // Update moving pos
                    _elapsedAlgoUpdateKnn = string.Format("msec {0}", _algorithm.UpdateKnn(_origin, Configuration)); // Update KNN

                    var nns    = _algorithm.Knn.GetNNs();
                    var notnns = PointUtil.Exclusive(nns, _algorithm.Points);

                    // --- Draw
                    DrawUtil.ClearBackground(dc, Rect);                          // Clear all
                    DrawUtil.DrawDots(dc, notnns, Rect);                         // Draw all not nearest neighbors
                    DrawUtil.DrawDots(dc, nns, Rect, ShapeType.NearestNeighbor); // Draw updated KNN
                    DrawUtil.DrawDots(dc, new[] { _origin }, Rect, ShapeType.Selected);
                    DrawUtil.DrawGrid(dc, SliderLeft == 1, Rect, Pens.PenGrid2);

                    dc.Close();
                }
            }

            else
            {
                // Draw updates only
                // Draw on the drawing context
                using (DrawingContext dc = _drawingVisual.RenderOpen())
                {
                    _animation.SelectMovingDots(DotsMovingCount);

                    // Clear prev frame knn
                    DrawUtil.RedrawDots(dc, new[] { _algorithm.Knn.Origin }, Rect, ShapeType.Selected);
                    DrawUtil.RedrawDots(dc, _algorithm.Knn.GetNNs(), Rect, ShapeType.NearestNeighbor);
                    DrawUtil.ClearDots(dc, _animation.Moving, Rect);                                                 // Clear prev frame moving dots

                    _animation.UpdateMovingPosition(min, max);                                                       // Update moving pos
                    _elapsedAlgoUpdateKnn = string.Format("msec {0}", _algorithm.UpdateKnn(_origin, Configuration)); // Update KNN
                    var nns = _algorithm.Knn.GetNNs();

                    // Draw updated KNN
                    DrawUtil.DrawDots(dc, _animation.Moving, Rect); // Draw updated pos
                    DrawUtil.DrawDots(dc, nns, Rect, ShapeType.NearestNeighbor);
                    DrawUtil.DrawDots(dc, new[] { _origin }, Rect, ShapeType.Selected);
                    DrawUtil.DrawGrid(dc, SliderLeft == 1, Rect);

                    dc.Close();
                }
            }


            _stopwatch.Stop();

            var sb = new StringBuilder();

            sb.AppendFormat("\n\nK Nearest Neighbors: \n\n");
            sb.AppendFormat("{0}\n", _algorithm.Strategy.Name);
            sb.AppendFormat("Origin: {0}\n", _algorithm.Knn.Origin);
            //sb.AppendFormat(_algorithm.Knn.NNs.Aggregate("", (a, b) => a + b + "\n"));
            sb.AppendFormat("K: {0}\n", _algorithm.Knn.K);
            sb.AppendFormat("NNs: {0}\n", _algorithm.Knn.NNs.Count);
            sb.AppendFormat("MaxDistance: {0}\n", _algorithm.Rectangle.MaxDistance);
            sb.AppendFormat("Square: {0}\n\n", _algorithm.Rectangle.Square);
            sb.AppendFormat("SliderTop\nmsec per frame: {0}\n\n", SliderTop);
            sb.AppendFormat("SliderLeft\nshow grid: {0}\n\n", SliderLeft);
            sb.AppendFormat("SliderBottom\nmovement speed: {0}\n\n", SliderBottom);
            sb.AppendFormat("dots: {0}\n", _algorithm.Points.Count);
            sb.AppendFormat("moving dots: {0}\n", _animation.Moving.Count);
            sb.AppendFormat("grid: {0};{1}\n", _algorithm.Rectangle.XGrid, _algorithm.Rectangle.YGrid);
            sb.AppendFormat("Draw enabled: {0}\n", DrawUtil.IsDrawEnabled);
            sb.AppendFormat("\nElapsed Algo Init: \n{0}\n", _elapsedAlgoInit);
            sb.AppendFormat("\nElapsed Algo update Knn: \n{0}\n", _elapsedAlgoUpdateKnn);
            sb.AppendFormat("\n\nTime per frame: \n{0}\n", _stopwatch.Elapsed.ToString());

            _textBlock.Text = sb.ToString();

            _dispatcherTimer.Interval = TimeSpan.FromMilliseconds(SliderTop); // update
            _renderTargetBitmap.Render(_drawingVisual);                       // Render the drawing to the bitmap

            _stopwatch.Reset();
            _isRunningFrameUpdate = false;
        }