Assume I am making an assembly (WindowsPhoneClassLibrary or PortableClassLibrary) for a Windows Phone Application (Silverlight).
Is there a way for me to automatically detect/register/subscribe for the moment where Application.Current.RootVisual
will be not null?
My current (not working because of Exception) approach is in the idea of:
var rootVisualTask = new TaskCompletionSource<UIElement>();
var application = Application.Current;
TaskEx.Run(() =>
{
while (application.RootVisual == null)
Thread.Sleep(1);
rootVisualTask.TrySetResult(application.RootVisual);
});
var rootVisual = await rootVisualTask.Task;
Answer to McGarnagle to explain how my assembly gets usually initialized.
In App.xaml.cs:
static readonly PhoneApplicationFrame RootFrame = new PhoneApplicationFrame();
public App()
{
InitializeComponent();
RootFrame.Navigated += RootFrame_Navigated;
}
void RootFrame_Navigated(object sender, NavigationEventArgs e)
{
RootVisual = RootFrame;
RootFrame.Navigated -= RootFrame_Navigated;
}
void Application_Launching(object sender, LaunchingEventArgs e)
{
MyPlugin.Start();
}
void Application_Activated(object sender, ActivatedEventArgs e)
{
MyPlugin.Start();
}
Things happen in this order:
Application.Startup
(unused)Application.Launching
(plugin starts)RootFrame.Navigated
(RootVisual is set, but RootFrame is private)I could require a MyPlugin.HeyRootVisualIsSetAndNowYouCanUseIt()
manually inserted after RootVisual = ...
but I was trying to avoid that.
Unlike Obj-C, KVO is not implementable on Fields/Properties you don't own. Which means probably nobody is going to find a better solution.
After experimenting for hours, I found this working:
var dispatcher = Deployment.Current.Dispatcher;
var application = Application.Current;
UIElement rootVisual = null;
while (rootVisual == null)
{
var taskCompletionSource = new TaskCompletionSource<UIElement>();
dispatcher.BeginInvoke(() =>
taskCompletionSource.TrySetResult(application.RootVisual));
rootVisual = await taskCompletionSource.Task;
}
The Thread.Sleep(1);
from the loop of my question is replaced with a call to Deployment.Current.Dispatcher.BeginInvoke()
to avoid Exception being thrown.