The way you are doing it will work just fine. The documentation for Sytem.Timers.Timer says:
If the SynchronizingObject property is null, the Elapsed event is raised on a ThreadPool thread.
The SynchronizingObject property is null by default, so your Elasped event will run on a ThreadPool thread, not on the UI thread. That means it will not stop your application from responding to user input.
If there is a chance that ElapsedTime() will run longer than your interval, and you don't want the events overlapping, then you can set AutoReset to false and reset it manually at the end of ElapsedTime(). Just make sure that everything is wrapped in a try/catch block, otherwise the timer won't get reset if there's an exception. My code below shows how that would look.
You don't need to use async/await anywhere here. Since it won't be running on the UI thread, using asynchronous code won't really help you any. In a desktop app, it's not a big deal to have a separate (non-UI) thread wait.
public class Timer
{
    private System.Timers.Timer timer;
    private void InitTimer()
    {
        timer = new System.Timers.Timer(4000);
        timer.Elapsed += ElapsedTime;
        timer.AutoReset = false;
        timer.Enabled = true;
    }
    private void ElapsedTime()
    {
        try {
            //send request and update data
        }
        catch (Exception e)
        {
            //log the error
        }
        finally
        {
            //start the timer again
            timer.Enabled = true;
        }
    }
}