Вместо выполнения ваших задач в CellEndEdit поместите их в CellValueChanged. Он запускается только при изменении значения ячейки. Обратите внимание, что он будет срабатывать при первоначальном заполнении ваших DataGridView, но чтобы справиться с этим, вы можете поместить только одну переменную, скажем, formInitialized или что-то подобное, чтобы убедиться, что вы не выполняете свой CellEndEdit при заполнении своих сеток данных.
И чтобы ответить на ваш вопрос, нет способа выяснить, изменяется ли значение при запуске CellEndEdit, потому что оно всегда срабатывает, когда ячейка выходит из режима редактирования. Единственное решение, как вы и предлагали, - сохранять старое значение извне, но вы уже заметили, почему это плохо (хотя в большинстве случаев оно работает действительно хорошо).