简体   繁体   中英

Issue with updating a textblock in WP7 with a timer

I working on an app that will (as a minor subset of it's functionality) provide a countdown timer. However, there can and will be instances where there are multiple count downs going at the same time. Each Count Down has it's own pivot item in a pivot view. Since these countdowns are dynamically created, I'm adding the textblock (that serves as the output for the time remaining) for each countdown to a list, and I've set a timer to call a method that cycles through each one of those textblocks in the list and update them accordingly. However, I'm receiving an exception of "System.UnauthorizedAccessException" but I'm not entirely sure why. I am being told it's a error of "Invalid cross-thread access."

Here's the line that is the offending line:

c.Label.Dispatcher.BeginInvoke(delegate() { c.Label.Text = timeRemaining; });

Here is the full method:

private static void TimeRemainingCallback(object state)
    {
        if (countDowns.Count == 0)
        {
            return;
        }

        foreach (CountDown c in countDowns)
        {
            DateTime rightNow = DateTime.Today;

            if (c.ExpirationDate >= rightNow)
            {
                DateTime offsetExpiration = c.ExpirationDate.Add(c.LocalNow);
                TimeSpan timeDifference = offsetExpiration.Subtract(rightNow);


                String timeRemaining = "";
                String timeDays = "";
                String timeHours = "";
                String timeMinutes = "";
                String timeSeconds = "";

                if (timeDifference.Days == 1)
                {
                    timeDays = "1 Day";
                }
                else
                {
                    timeDays = timeDifference.Days + " Days";
                }

                if (timeDifference.Hours == 1)
                {
                    timeHours = "1 Hour";
                }
                else
                {
                    timeHours = timeDifference.Hours + " Hours";
                }

                if (timeDifference.Minutes == 1)
                {
                    timeMinutes = "1 Minute";
                }
                else
                {
                    timeMinutes = timeDifference.Minutes + " Minutes";
                }

                if (timeDifference.Seconds == 1)
                {
                    timeSeconds = "1 Second";
                }
                else
                {
                    timeSeconds = timeDifference.Seconds + " Seconds";
                }

                if (timeDifference.Days == 0 && timeDifference.Hours >= 1)
                {
                    timeRemaining = timeHours + " " + timeMinutes;
                }
                else if (timeDifference.Days == 0 && timeDifference.Hours == 0 && timeDifference.Minutes >= 1)
                {
                    timeRemaining = timeMinutes + " " + timeSeconds;
                }
                else if (timeDifference.Days == 0 && timeDifference.Hours == 0 && timeDifference.Minutes == 0)
                {
                    timeRemaining = timeSeconds;
                }
                else
                {
                    timeRemaining = timeDays + " " + timeHours + " " + timeMinutes;
                }

                c.Label.Dispatcher.BeginInvoke(delegate() { c.Label.Text = timeRemaining; });
            }
        }
    }

Here is how I create the timer, the only time the CallBack is mentioned:

Timer updateRemainingTime = new Timer(TimeRemainingCallback, null, 0, 1000);

The list is really full of objects that contain a datetime and a textblock (which here is called label) thus the c.Label deal.

timeRemaining is the string of the time remaining that is formed in the timercallback.

Any ideas of what's going on here? Any better ideas on how to do this?

Invoke the Dispatcher for the entire loop iteration, and remove your current Dispatcher invocation.

Dispatcher.BeginInvoke(() =>
{
    foreach (CountDown c in countDowns)
    {
       // Actions here.
       c.Label.Text = timeRemaining;
    }
});

I am assuming you have countDowns bound to the list UI control you're working with.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM