private void updateTimingGroup()
        {
            beatLength.UnbindBindings();

            var tcp = selectedGroup.Value?.ControlPoints.OfType <TimingControlPoint>().FirstOrDefault();

            if (tcp == null)
            {
                timingPoint = new TimingControlPoint();
                // During movement of a control point's offset, this clause can be hit momentarily,
                // as moving a control point is implemented by removing it and inserting it at the new time.
                // We don't want to reset the `selectedGroupStartTime` here as we rely on having the
                // last value to update the waveform display below.
                selectedGroupEndTime = beatmap.Value.Track.Length;
                return;
            }

            timingPoint = tcp;
            beatLength.BindTo(timingPoint.BeatLengthBindable);

            double?newStartTime = selectedGroup.Value?.Time;
            double?offsetChange = newStartTime - selectedGroupStartTime;

            var nextGroup = editorBeatmap.ControlPointInfo.TimingPoints
                            .SkipWhile(g => g != tcp)
                            .Skip(1)
                            .FirstOrDefault();

            selectedGroupStartTime = newStartTime ?? 0;
            selectedGroupEndTime   = nextGroup?.Time ?? beatmap.Value.Track.Length;

            if (newStartTime.HasValue && offsetChange.HasValue)
            {
                // The offset of the selected point may have changed.
                // This handles the case the user has locked the view and expects the display to update with this change.
                showFromTime(displayedTime + offsetChange.Value, true);
            }
        }