I am creating an app with a timer in it. I want to display a toast notification(or some sort of notification) if the person leaves the app so they know the timer is over. I used the "PeriodicTask" using ".FromSeconds", but it seemed it didn't fire it at the specified time.
PeriodicTask periodicTask = new PeriodicTask("TaskTest");
periodicTask.Description = "Task";
try
{
IsolatedStorageSettings.ApplicationSettings["TimerForSchedule"] = TimeNum;
ScheduledActionService.Add(periodicTask);
ScheduledActionService.LaunchForTest("TaskTest", TimeSpan.FromSeconds(((TimeNum*60))));
}
On the "OnInvoke" method for the scheduled agent project, I have the following:
protected override void OnInvoke(ScheduledTask task)
{
if (task.Name == "TaskTest")
{
int time = Convert.ToInt32(IsolatedStorageSettings.ApplicationSettings["TimerForSchedule"]);
bool periodic = (bool)(task is PeriodicTask);
ShellToast toast = new ShellToast();
toast.Title = "Done";
toast.Content = "Timer is over";
toast.Show();
}
NotifyComplete();
ScheduledActionService.Remove("TaskTest");
}
Everything seems to fire properly because I DO get a notification, but I do not get it at the expected time.
Any help would be appreciated.
Is your app running in the foreground? If so, the ShellToast won't show up. Your app must be in the background for it to show up. Read more about that and potential workaround at my other # How can I create a shelltoast?
I think that the time you set to run your PeriodicTask is just a hint for the OS, it does not mean that it will fire it exactly at that time.
Related
From what I understand you need to track Activation and Deactivation of the Explorers. During activation, you need to add SelectionChange event handlers for the current explorer.
This seems to work perfectly for single clicks on AppointmentItems. But it crashes the Addin when double-clicking on an appointment series and selecting a single Appointment.
Here is the source:
On class level
private Outlook.Explorer currentExplorer = null;
private Outlook.AppointmentItem currentAppointmentItem = null;
within Startup:
currentExplorer = this.Application.ActiveExplorer();
((Outlook.ExplorerEvents_10_Event)currentExplorer).Activate +=
new Outlook.ExplorerEvents_10_ActivateEventHandler(
Explorer_Activate);
currentExplorer.Deactivate += new
Outlook.ExplorerEvents_10_DeactivateEventHandler(
Explorer_Deactivate);
The event handlers:
void Explorer_Activate()
{
currentExplorer.SelectionChange += new Outlook.ExplorerEvents_10_SelectionChangeEventHandler(Selection_Change);
}
void Explorer_Deactivate()
{
currentExplorer.SelectionChange -= new Outlook.ExplorerEvents_10_SelectionChangeEventHandler(Selection_Change); ;
}
private void Close_Explorer()
{
}
private void Selection_Change()
{
Outlook.MAPIFolder selectedFolder = currentExplorer.CurrentFolder;
if (currentExplorer.Selection.Count > 0)
{
Object selObject = currentExplorer.Selection[1];
if (selObject is Outlook.AppointmentItem)
{
currentAppointmentItem = (Outlook.AppointmentItem)selObject;
}
else
{
currentAppointmentItem = null;
}
}
}
What am I overlooking? Is the form of deregistering a problem?
Try to add try/catch blocks to the event handlers. The Outlook object model can give you unpredictable results sometimes. It is worth adding them and find where an exception is thrown.
currentExplorer.Selection.Count
Also, you may subscribe to the SelectionChange event in the NewExplorer event and don't switch between explorers when they are activated or deactivated. The event is fired whenever a new explorer window is opened, either as a result of user action or through program code.
The only thing which I added was a handler for NewInspector and InspectorClose events along with Marshal.ReleaseComObject(). The only thing which I can imagine that double clicking while debugging I got in some kind of race condition (because double clicking also triggers the Selection_Change event). But this is only a guess.
You do not need to add and remove event handlers as an explorer is activated / deactivated. Are you trying to support multiple explorers? In that case, create a wrapper class that hold the Explorer object as it member and uses its methods as event handlers.
I have an activity which has an async method in it. This async method is long running. After the async method returns, the UI needs to be updated and some of the controls reference the activity.
At the moment, everything works correctly if you do not have a configuration change (like screen rotation) while the async task is running. However, if a configuration change happens while it is running, then the exception Activity is destroyed is thrown and the UI is not updated. From what reading I have done, this seems to be because the async method captures context and then tries to update the old context which is of course destroyed after the configuration change.
My question is: What are the best ways to solve this problem or at worst case scenario work around it?
I personally think you have only three options
You can disable rotation permanently or temporary, but this is a bad practice
To disable it permanently set ConfigurationChanges
[Activity(Label = "...", ConfigurationChanges = Android.Content.PM.ConfigChanges.KeyboardHidden | Android.Content.PM.ConfigChanges.Orientation | Android.Content.PM.ConfigChanges.ScreenSize)]
To disable it temporary while task working you should disable rotation handling,
disable
this.RequestedOrientation = Android.Content.PM.ScreenOrientation.Nosensor;
enable
this.RequestedOrientation = Android.Content.PM.ScreenOrientation.Sensor;
If you are using fragment you can prevent fragment destroy with RetainInstance = true. That might work, but i never tested it.
You can cancel task with CancelationToken and restart it in OnRestoreInstanceState()
Here is example how to cancel task
{
CancellationTokenSource cts;
...
// If a download process is already underway, cancel it.
if (cts != null)
{
cts.Cancel();
}
// Now set cts to cancel the current process if the button is chosen again.
CancellationTokenSource newCTS = new CancellationTokenSource();
cts = newCTS;
try
{
//Send cts.Token to carry the message if there is a cancellation request.
await AccessTheWebAsync(cts.Token);
}
// Catch cancellations separately.
catch (OperationCanceledException)
{
ResultsTextBox.Text += "\r\nDownloads canceled.\r\n";
}
catch (Exception)
{
ResultsTextBox.Text += "\r\nDownloads failed.\r\n";
}
// When the process is complete, signal that another process can proceed.
if (cts == newCTS)
cts = null;
}
And in the task
async Task AccessTheWebAsync(CancellationToken ct)
{
...
// Retrieve the website contents from the HttpResponseMessage.
byte[] urlContents = await response.Content.ReadAsByteArrayAsync();
// Check for cancellations before displaying information about the
// latest site.
ct.ThrowIfCancellationRequested();
...
}
There are plenty of things you could do, but please don't go and disable the phones ability to turn the screen -- that is just going to ignore your users.
At a highlevel you will have to do two things:
Make sure the async task keeps running and is not restarted if the activity dies.
You can solve that by moving the task either into the application class or (cleaner) into a headless fragment with setRetainInstance set to true.
In the onDestroy method in the activity, remove it from the async task, in the onCreate task give the activity to the async task (if it exist).
This is what prevents the async task from calling the old context and can be done with a simple java setter on the async task. Don't forget to cache the result in the task if the activity is currently not connected.
In the end what I ended up doing was encapsulating the async task in another class which held a reference to the current activity, which implemented and interface which defined a method which handles the async response and updates the UI.
The activity held a static variable of the encapsulated async task, and if it was running during a config change, the encapsulated async's task reference to the activity was updated to the new activity.
Let me start by saying that I had the PeriodicTask already working a couple of days back, but when I came back to do something else I noticed the PeriodicTask's OnInvoke is not called anymore.
I think I am doing the basics correct: removing existing PeriodTask if found, calling LaunchForTest only in debug build and I've checked that the ScheduledAgent is referenced properly in the project and the WMAppManifest.xml.
This is how I setup the PeriodicTask:
try
{
PeriodicTask backgroundTask = null;
backgroundTask = ScheduledActionService.Find(BGTASK_NEW_EPISODES) as PeriodicTask;
if (backgroundTask != null)
{
ScheduledActionService.Remove(backgroundTask.Name);
}
// Start our background agent.
backgroundTask = new PeriodicTask(BGTASK_NEW_EPISODES);
backgroundTask.Description = "Foobar";
ScheduledActionService.Add(backgroundTask);
#if DEBUG
ScheduledActionService.LaunchForTest(BGTASK_NEW_EPISODES, TimeSpan.FromSeconds(5));
#endif
}
catch (InvalidOperationException e)
{
if (e.Message.Contains("BNS Error: The action is disabled"))
{
App.showNotificationToast("Background tasks have been disabled from\nsystem settings.");
}
}
catch (Exception) { }
}
Here's my WMAppManifest.xml:
<ExtendedTask Name="BackgroundTask">
<BackgroundServiceAgent Specifier="ScheduledTaskAgent" Name="PodcatcherBackgroundService" Source="PodcatcherBackgroundService" Type="PodcatcherBackgroundService.ScheduledAgent" />
</ExtendedTask>
When I install the app for the first time, then the OnInvoke is called. But if I restart the app, it's not called. The same is true for both device and emulator.
I've also verified that the background task is enabled in settings and I have a fully charged battery (device is a WP7 device and it's connected via USB to PC. For the emulator, of course, this doesn't matter).
So what should I check next?
Thanks!
Ok, seems I got it resolved.
In certain cases I forgot to call NotifyComplete() in the background task. In that case Windows Phone seems to just ignore subsequent tries to invoke the background worker.
I developed Windows service that is using System.Threading.Timer. Timer is starting every x minutes and it works fine (timer is updatet at the end of method). But, if there is an error in try block service just stops despite the fact that I'm updating timer and telling him when to start again
why is that happening? Here is code :
System.Threading.Timer serviceTimer;
protected override void OnStart(string[] args)
{
TimeSpan diff;
diff = nextRun - now;
TimerCallback timerDelegate =
new TimerCallback(MyTimerCallback);
serviceTimer = new System.Threading.Timer(timerDelegate, null,
diff, new TimeSpan(-1));
}
public void MyTimerCallback(object something)
{
try
{
//possible error that happened
}
catch(Exception)
{
}
finally
{
//diff is a new variable telling timer when to start again
serviceTimer.Change(diff, new TimeSpan(-1));
}
}
what am I missing why service stops if there was an error?
Maybe the timer wasn't able to change. Timer.Change returns a boolean:
true if the timer was successfully updated; otherwise, false.
But you're not checking that result. I'd recommend probably disposing the timer and newing up a new one each time, since it's already fired and you created it as a "one shot" timer, e.g.
finally
{
serviceTimer.Dispose();
serviceTimer = new System.Threading.Timer(timerDelegate, null,
diff, new TimeSpan(-1));
}
In case that someone deals with same problem I figured something like this:
Since I want my service to stay alive no matter what :
I 'm reporting to the service manager that the service has successfully started -
base.OnStart(args);
In configuration you can set legacyUnhandledExceptionPolicy set to true (1)
Windows Phone 7.5 / Silverlight app
If user is playing music / radio on their phone and they try to launch my application, I want to give user an option to stop the currently playing option.
Working fine:
The message popup shows up fine. When I select Cancel, the popup closes, the music keeps playing and my app starts/works as normal.
Issue:
If I select Ok i.e. to stop the currently playing music on phone, the music stops but at the same time my app also exits.
Any ideas what I am doing wrong here?
Here is the code I am using. I call this method on launching:
private void CheckAudio()
{
if (FMRadio.Instance.PowerMode == RadioPowerMode.On)
{
MessageBoxResult Choice;
Choice = MessageBox.Show("For better user experience with this application it is recommended you stop other audio applications. Do you want to stop the radio?", "Radio is currently playing!", MessageBoxButton.OKCancel);
if (Choice == MessageBoxResult.OK)
{
FMRadio.Instance.PowerMode = RadioPowerMode.Off;
}
}
if (MediaPlayer.State == MediaState.Playing)
{
MessageBoxResult Choice;
Choice = MessageBox.Show("For better user experience with this application it is recommended you stop other audio/video applications. Do you want to stop the MediaPlayer?", "MediaPlayer is currently playing!", MessageBoxButton.OKCancel);
if (Choice == MessageBoxResult.OK)
{
MediaPlayer.Stop();
}
}
}
Update:
I posted my solution below. Do let me know if I am doing anything wrong.
I found the following error was being thrown:
FrameworkDispatcher.Update has not been called. Regular
FrameworkDispatcher. Update calls are necessary for fire and forget
sound effects and framework events to function correctly.
So I added this code and now it is working fine. Now upon clicking OK, the music player stops and my app launches fine. I call the SetupTimer method from InitializeComponent in App.xaml.cs
private GameTimer gameTimer;
private void SetupTimer()
{
gameTimer = new GameTimer();
gameTimer.UpdateInterval = TimeSpan.FromMilliseconds(33);
// Call FrameworkDispatcher.Update to update the XNA Framework internals.
gameTimer.Update += new EventHandler<GameTimerEventArgs>(gameTimer_Update); //delegate { try { FrameworkDispatcher.Update(); } catch { } };
// Start the GameTimer running.
gameTimer.Start();
// Prime the pump or we'll get an exception.
FrameworkDispatcher.Update();
}
void gameTimer_Update(object sender, GameTimerEventArgs e)
{
try { FrameworkDispatcher.Update(); }
catch { }
}
If anybody sees any problem/issue with the above please do let me know. Thanks.