private void FloatEditButton_ValueChangedHandler(float newValue)
        {
            newValue = Math.Max(_metaInput.Min, Math.Min(_metaInput.Max, newValue));  // ToDo: clamping should be done by FloatEdit

            // Update animation curve
            if (IsAnimated && _addKeyframeCommand != null)
            {
                _addKeyframeCommand.KeyframeValue.Value = newValue;
                _addKeyframeCommand.Do();
            }
            else if (_updateValueCommand != null)
            {
                _updateValueCommand.Value = new Float(newValue);
                _updateValueCommand.Do();
            }
            App.Current.UpdateRequiredAfterUserInteraction = true; // ToDo: This line should be moved to the source of interaction. Here, we only deal with result.
        }
        private void OnDragDelta(object sender, DragDeltaEventArgs e)
        {
            var delta = new Vector(e.HorizontalChange, e.VerticalChange);

            double deltaU = CurveEditor.xToU(delta.X) - CurveEditor.xToU(0);
            double deltaV = CurveEditor.yToV(delta.Y) - CurveEditor.yToV(0);

            if (m_MoveDirection == MoveDirection.Undecided)
            {
                if (Math.Abs(delta.X) + Math.Abs(delta.Y) > DRAG_THRESHOLD)
                {
                    if (Math.Abs(delta.X) > Math.Abs(delta.Y))
                    {
                        m_MoveDirection     = MoveDirection.Horizontal;
                        XCenterThumb.Cursor = Cursors.ScrollWE;
                    }
                    else
                    {
                        m_MoveDirection     = MoveDirection.Vertical;
                        XCenterThumb.Cursor = Cursors.ScrollNS;
                    }
                }
            }
            else
            {
                CurveEditor.DisableRebuildOnCurveChangeEvents();

                if (m_MoveDirection == MoveDirection.Vertical)
                {
                    V += deltaV;
                }

                if (m_MoveDirection == MoveDirection.Horizontal)
                {
                    // Snap when pressing Shift
                    if (TV != null &&
                        TV.TimeSnapHandler != null &&
                        Keyboard.Modifiers == ModifierKeys.Shift)
                    {
                        var snapU = TV.TimeSnapHandler.CheckForSnapping(U + deltaU);
                        if (!Double.IsNaN(snapU))
                        {
                            deltaU = snapU - U;
                        }
                    }

                    // Prevent overwriting existing keys
                    ManipulateU(U + deltaU);
                }

                switch (m_MoveDirection)
                {
                case MoveDirection.Vertical:
                    _addOrUpdateKeyframeCommand.KeyframeValue = m_vdef;
                    _addOrUpdateKeyframeCommand.Do();
                    break;

                case MoveDirection.Horizontal:
                    _moveKeyframeCommand.NewTime = U;
                    //_moveKeyframeCommand.Do();
                    break;
                }

                m_vdef = Curve.GetV(U);     // since SetOrUpdateV clones vdef, we have to get a new value

                if (TV != null)
                {
                    TV.TriggerRepaint();
                }

                UpdateControlTangents();
                CurveEditor.EnableRebuildOnCurveChangeEvents();
                App.Current.UpdateRequiredAfterUserInteraction = true;
                CurveEditor.UpdateLine(Curve);
                //CurveEditor.UpdateEditBox();
            }
        }