Search code examples
c#windows-phone-8.1background-processlifecyclestopwatch

How to run stopwatch after app tombstone?


Issue:

I've implemented a Stopwatch which runs and the value is added to a live tile. But when I tombstone or close the app the stopwatch stops running.

So this presents a problem where the initial value of the stopwatch's elapsed time is only updated to the live tile after the app is closed.

Question:

I'm wondering what options are available to run a stopwatch while the app has been killed off and subsequently call the CreateLiveTile method periodically with the updated stopwatch value?

I haven't attempted this type of feature before so I'm looking for some feedback on what this platform has to offer in order to achieve that.

Code:

This is essentially the code that runs the stopwatch and the separate method CreateLiveTile() which creates a new live tile with the elapsed time as a parameter:

    private async Task ShowTimerConfirmationDialog()
    {
         //Set timer for current parking tag
         SetParkingTagTimer();

         //Create the live tile
         CreateLiveTile();

    }


    private void SetParkingTagTimer()
    {

        //set timer to current elapsed time
        StopWatch.Start();
        // Get the elapsed time as a TimeSpan value.
        var ts = (SelectedParkDuration ?? StopWatch.Elapsed) - StopWatch.Elapsed;

        // Format and display the TimeSpan value. 
        ElapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
            ts.Hours, ts.Minutes, ts.Seconds,
            ts.Milliseconds / 10);
    }

    private void CreateLiveTile()
    {
        var tileXml = TileUpdateManager.GetTemplateContent(TileTemplateType.TileSquare150x150PeekImageAndText01);

        var tileImage = tileXml.GetElementsByTagName("image")[0] as XmlElement;
        tileImage.SetAttribute("src", "ms-appx:///Assets/Logo.scale-140.png");

        var tileText = tileXml.GetElementsByTagName("text");
        (tileText[2] as XmlElement).InnerText = "Time remaining:";
        (tileText[3] as XmlElement).InnerText = " " + ElapsedTime;

        var tileNotification = new TileNotification(tileXml);
        TileUpdateManager.CreateTileUpdaterForApplication().Update(tileNotification);

    }


}

Solution

  • You could save off your start time, either in a static variable or to a file if you want it to persist after the app is closed. I would recommend using a DateTimestructure.

    Here is an extremely simplified example

    private static DateTime startTime;
    private const string START_TIME_FILENAME = "./your/path.txt"
    
    public static void StartStopWatch()
    {
        // Persist this variable until the app is closed
        startTime = DateTime.Now;
    
        //Persist this variable until it is overwritten
        System.IO.File.WriteAllText(START_TIME_FILENAME, startTime.ToString());
    }
    
    // Get the difference in time since you started the stopwatch and now
    public static TimeSpan Elapsed()
    {
        if (startTime == null)
        {
            startTime = GetStartTime();
        }
    
        return DateTime.Now - startTime;
    }
    
    // Call this method to get the start time after the app has been closed
    private static DateTime GetStartTime()
    {
        return Convert.ToDateTime(System.IO.File.ReadAllText(START_TIME_FILENAME));
    }
    

    In order to keep track of when the timer was started even after the app is closed, you must save the variable to your hard drive.

    Also this is just one very simple (and in my opinion convenient) way of storing a DateTime to a file. There are other ways of doing it but for something this simple plain text is nice to see incase something goes wrong.