Skip to main content
Skip Navigation LinksHome  Extending the Spotfire Platform  Common Tasks and Idioms  Writing Timer Based Code

©Spotfire 2011

Writing Timer Based Code

The framework provides methods to move execution between threads. This way periodic updates can be applied to the document.

Overview

A common purpose for timer based updates is the refreshing of data tables. The following methods are used to implement scenarios periodically updating the document:

Note: Do NOT attach an event handler to Windows.Forms.Application.Idle or Windows.Forms.Timer.Tick to update the document. This is NOT safe: Sometimes, for instance during a progress operation, the UI thread is not the application thread, and accessing the document on the UI thread will cause an exception. For the same reason, avoid the use of the Windows.Forms.Form.Invoke/BeginInvoke methods.

Example

The following example shows how to periodically refresh the data.

public static void PeriodicallyRefreshData(AnalysisApplication application)
{
    // Create and start a RefreshDataWorker.
    RefreshDataWorker refreshDataWorker = new RefreshDataWorker(application);
    refreshDataWorker.Start();
}

private class RefreshDataWorker
{
    private readonly AnalysisApplication application;
    private readonly ApplicationThread applicationThread;
    private bool shallQuit;

    public RefreshDataWorker(AnalysisApplication application)
    {
        this.shallQuit = false;
        this.application = application;

        // Fetch the application thread. It is available as an analysis service.
        this.applicationThread = application.GetService<ApplicationThread>();
    }

    public void Start()
    {
        // Ask the application thread to spawn a new thread that executes the RefreshDataLoop.
        this.applicationThread.ExecuteOnWorkerThread("Data Refresh Thread", RefreshDataLoop);
    }

    // Get or set the quit-flag in a thread safe manner.
    private bool ShallQuit
    {
        get
        {
              lock (this)
              {
                  return this.shallQuit;
              }
          }
          set
          {
              lock (this)
              {
                  this.shallQuit = value;
              }
          }
      }

    // Refresh the data every 10 seconds until the ShallQuit flag is set.
    // Note: This method is executed on the worker thread.
    private void RefreshDataLoop()
    {
        while (!ShallQuit)
        {
            // Sleep for 10 seconds.
            Thread.Sleep(TimeSpan.FromSeconds(10));

            // Invoke to the application thread to synchronously 
            // execute the RefreshData on the application thread.
            // This call will block until the application thread has 
            // executed the RefreshData method.
            this.applicationThread.Invoke(RefreshData);
        }
    }

    // Refresh all data tables in the currently open document.
    // Note: This method is executed on the application thread.
    private void RefreshData()
    {
        Document document = this.application.Document;

        // If there is no open document, set the quit flag and return.
        if (document == null)
        {
            this.ShallQuit = true;
            return;
        }

        // There is an open document. Refresh data.
        // This is done in a progess operation so that it becomes a bit more clear to
        // the user what is going on.
        ProgressService progressService = application.GetService<ProgressService>();
        progressService.ExecuteWithProgress(
            "Automatic data refresh",
            "The API example is refreshing data.",
            delegate
            {
                document.Data.Tables.RefreshAll();
            });
    }
}