IoTBrowser, navigate webview from task/thread - c#

There's a webview:
<WebView x:Name="webView" Margin="0,10" Grid.RowSpan="3" LoadCompleted="webView_LoadCompleted"/>
And there's a basic snippet of code, which starts a task that will listen to an azure device. Some code is missing from the below example, presume the device was created normally.
The problem, is that I'd like to tell the Webview to navigate to a certain webpage, depending on the content of the received message.
The problem is,. "Window.Current" is null, so it crashes.
public App()
{
Task.Run(ReceiveC2dAsync);
}
private async static Task ReceiveC2dAsync()
{
while (true)
{
Microsoft.Azure.Devices.Client.Message receivedMessage = await deviceClient.ReceiveAsync();
if(receivedMessage != null)
{
// Snip
Task.Run(Navigate);
}
}
}
private async static Task Navigate()
{
try
{
if(Window.Current.Content != null)
((Frame)Window.Current.Content).Navigate(typeof(MainPage), "http://www.google.com");
}
catch(Exception e)
{
Debug.WriteLine("{0} Exception caught.", e);
}
}
In the override code:
protected override void OnLaunched(LaunchActivatedEventArgs e)
The following code can be used to navigate to a desired website when the application launches:
Frame rootFrame = Window.Current.Content as Frame;
if(rootFrame == null) rootFrame = new Frame();
rootFrame.Navigate(typeof(MainPage), "ms-appx-web:///help.html");
So, current is not null at this point.
If i save rootframe as a static, and use it at a later point in the task, I get a marshal error - basically stating the object is referenced to be marshaled to another thread.
My C# knowledge is,. in progress I fear.
So far I've been unable to find a proper explanation on how to have the webview respond to the internal task. Is it possible? And if so, how?
PS: The initial sample code is from: https://github.com/ms-iot/samples/tree/develop/IoTBrowser

The problem, is that I'd like to tell the Webview to navigate to a certain webpage
According to your code snippet, you are developing a UWP app. If you want to know how WebView navigate to a web site, you should be able to use Navigate method of WebView, for example:
webView.Navigate(new Uri("http://www.google.com"));
The following code can be used to navigate to a desired website when the application launches:
The code snippet by default inside OnLaunched navigate to one page by Frame. Frame control supports navigation to Page instances, not web pages, you cannot navigate to a website by Frame. Your above code snippet can only let the rootFrame navigate to MainPage, not the help.html. But you can get the ms-appx-web:///help.html parameter on MainPage and navigate to it by a WebView on MainPage.
I get a marshal error - basically stating the object is referenced to be marshaled to another thread.
If you want to invoke UIElement in a different thread, you should be able to use Core​Dispatcher, cannot invoke directly.
For a conclusion, I think what you actually want to do is navigate to a web site by WebView from a non UI thread. For example:
await Task.Run(Navigate);
private async Task Navigate()
{
try
{
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
webView.Navigate(new Uri("http://www.google.com"));
});
}
catch (Exception e)
{
Debug.WriteLine("{0} Exception caught.", e);
}
}

Related

Xamarin.forms iOS navigation issue

I have a strange problem.I used latest of Xamarin.forms(v 3.1.0.583944).
On iOS, I need to navigate from one page to another page. so I used following code:
NavigationPage Root;
public void SetRootView(NavigationPage root)
{
try
{
App.Instance.MainPage = root;
Root = root;
}
catch (System.Exception ex)
{
// handle exception
}
}
in another method(generic) i declare that has code to push to navigation stack:
public async Task PushViewAsync<TView>() where TView : Page
{
var view = GetView<TView>();
await Root.PushAsync(view);
}
but it does not push it to another page. There are no error or exception. But it just stay there. However if i tap on the screen, it goes to next page.
This is absolutely working fine on android. So not sure what it cause on iOS.
Any thoughts?
You need to be on the UI thread when navigating.
Device.BeginInvokeOnMainThread (async() => {
await Root.PushAsync(view);
});

Navigation Page Exception in C# using Xamarin forms

I have implemented a hybrid web view in my Xamarin PCL app.
I am calling a C# function from an Html page using JavaScript in the aforementioned, hybrid web view.
The problem is that although my function is being called, an exception is thrown when I try to redirect from it.
Android.Util.AndroidRuntimeException:
Only the original thread that created a view hierarchy can touch its views.
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.
My code is as follows:
var isValid = AreCredentialsCorrect(user);
if (isValid)
{
try
{
await Navigation.PushAsync(new UserDashboard("local.html?auth_admin=true"));
}
catch { }
}
public UserDashboard(string uriname)
{
InitializeComponent();
hybridWebView.Uri = uriname;
hybridWebView.RegisterAction(data => userLogin(data));
}
Sounds like you're trying to update UI from a background thread. Try doing the navigation from the main thread:
Device.BeginInvokeOnMainThread(async () => await Navigation.PushAsync(new UserDashboard("local.html?auth_admin=true")));

Issues resuming app with PickFolderAndContinue method

I am having issues resuming my app after utilizing the PickFolderAndContinue method. I've been trying to go off the directions from this MSDN sample. I haven't been able to figure out how to change the OnActivated method to return to my Settings page (the sample uses only the mainpage with different frames of content).
protected async override void OnActivated(IActivatedEventArgs e)
{
base.OnActivated(e);
ContinuationManager continuationManager = new ContinuationManager();
Frame rootFrame = CreateRootFrame();
await RestoreStatusAsync(e.PreviousExecutionState);
if (rootFrame.Content == null)
{
rootFrame.Navigate(typeof(SettingsPage));
}
var continuationEventArgs = e as IContinuationActivatedEventArgs;
if (continuationEventArgs != null)
{
// What do i do here to return to my settings page?
Frame scenarioFrame = SettingsPage.Current.FindName("ScenarioFrame") as Frame;
if (scenarioFrame != null)
{
// Call ContinuationManager to handle continuation activation
continuationManager.Continue(continuationEventArgs, scenarioFrame);
}
}
Window.Current.Activate();
}
Thanks.
When your OnActivated is called if you know you always want to go to the SettingsPage then all you need is this code:
Frame rootFrame = CreateRootFrame();
await RestoreStatusAsync(e.PreviousExecutionState);
if (rootFrame.Content == null)
{
rootFrame.Navigate(typeof(SettingsPage));
}
That code creates the applications root frame, and tells it to navigate to that specific page.
The code after this uses ContinuationManager. This is a mechanism set up to call into the page to let it know it is coming back from a AndContinue method. This will allow the page to do any functionality to occur for that Page.
FilePicker also has a ContinuationData property which you can set prior to calling the AndContinue method. This data is available in OnActivated via the IContinuationActivatedEventArgs.
This blog has a good description of the AndContinue Methods:
http://blogs.msdn.com/b/wsdevsol/archive/2014/05/08/using-the-andcontinue-methods-in-windows-phone-silverlight-8-1-apps.aspx

Windows Phone ContactPicker won't await properly

Although this has been posted before on StackOverflow but i think none of those reflect my issue and none of those solutions work for me either. So i'm developing a Windows Phone app and my workflow is a bit like this:
App starts
ContactPicker opens up
User selects one or multiple contacts
Based on how many contacts he selected, that many PivotItems are added into the Pivot.
My code is as follows:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
// TODO: Prepare page for display here.
// TODO: If your application contains multiple pages, ensure that you are
// handling the hardware Back button by registering for the
// Windows.Phone.UI.Input.HardwareButtons.BackPressed event.
// If you are using the NavigationHelper provided by some templates,
// this event is handled for you.
SelectContacts();
}
private async Task SelectContacts()
{
var picker = new ContactPicker();
picker.DesiredFieldsWithContactFieldType.Add(ContactFieldType.PhoneNumber);
ContactsList = (List<Contact>)await picker.PickContactsAsync();
DisplayContacts();
}
private void DisplayContacts()
{
if (ContactsList != null)
{
foreach (var item in ContactsList)
{
PivotItem pivotItem = new PivotItem();
pivotItem.Header = item.FirstName.ToString();
ContentRoot.Items.Add(pivotItem);
}
}
}
According to me, in SelectContacts() method, the app should wait at the await call and once it gets back the list of contacts, than it should execute the DisplayContacts() method but its not working. I've tried multiple other variations of this code and they aren't working either.
await the SelectContacts() method and add the DisplayContacts() method beneath it. Remove the DisplayContacts() method from SelectContacts()
await SelectContacts();
DisplayContacts();
I don't know the complete reason why but i figured it out that since i was making the PickContactsAsync() call in the OnNavigatedTo() event, that is why it wasn't working as expected. Once i moved the PickContactsAsync() call into the PageLoaded() event handler, it started working as usual.

Don't have OnActivated method in app.xaml.cs Windows Phone 8.1

I'm actually working on an application which was a blank Windows Phone app 8.1 at the beginning. I wanted to implement the app with a FileOpenPicker to get a picture from the device. In WP 8.1, I have to use PickSingleFileAndContinue method of the OpenFilePicker. So I've read about configuring my project to handle Continue event here: your Windows Phone Store app after calling an AndContinue method MSDN. One of the steps is to implement the OnActivated method in the app.xaml.cs file.But there is no OnActivated method in my app.xaml.cs.
I've copy paste that method from the above link but the MainPage object used in that method doesn't have a Current state:
protected async override void OnActivated(IActivatedEventArgs e)
{
base.OnActivated(e);
continuationManager = new ContinuationManager();
Frame rootFrame = CreateRootFrame();
await RestoreStatusAsync(e.PreviousExecutionState);
if (rootFrame.Content == null)
{
rootFrame.Navigate(typeof(MainPage));
}
var continuationEventArgs = e as IContinuationActivatedEventArgs;
if (continuationEventArgs != null)
{
Frame scenarioFrame = MainPage.Current.FindName("ScenarioFrame") as Frame;
if (scenarioFrame != null)
{
// Call ContinuationManager to handle continuation activation
continuationManager.Continue(continuationEventArgs, scenarioFrame);
}
}
Window.Current.Activate();
}
As I'm knew to Windows Phone and just facing the states management of an app, I cannot really figure out where that error comes from. Maybe someone got an idea ?
It won't be 100% clear until you download the full source code example off that link. They neglected to post the full example (too much code). Download the C# demo project and look at it.
MSDN FilePicker FULL SOURCE
public sealed partial class MainPage : Page
{
public static MainPage Current;
public MainPage()
{
this.InitializeComponent();
// This is a static public property that allows downstream pages to get a handle to the MainPage instance
// in order to call methods that are in this class.
Current = this;
Windows.Phone.UI.Input.HardwareButtons.BackPressed += HardwareButtons_BackPressed;
}
}
As you can see it's just a static declaration.

Categories