There's nothing pretty about having to solve this problem. Note that using lock is a very bad idea, it will make your threadpool explode when the callback consistently takes too much time. This happens easily when the machine gets loaded. Using Monitor.TryEnter() is the safe alternative. Definitely not pretty either, you'll arbitrarily lose callbacks.
It gets a heckofalot easier if you simply set the period argument to 0. So that the timer can tick only once. Now you automatically have a hard guarantee that the callback cannot be re-entered. All you have to do is call Change() at the end of the method to restart the timer. It is up to you to use a fixed value or calculate a new dueTime value based on the actual amount of time that expired, either are reasonable choices.