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);
});
Related
I have a project that needs notifications about upcoming events to show when the user opens the main page, and I'm having problems with async and await (I think). I am using the LocalNotifications Nuget plugin, because that's the only one I was allowed to use for this project. I have some methods that are intended to check for and display notifications. I have tried loading them from my App file, My MainPage.Xaml.cs's OnAppearing method, and from my MainPageViewModel.cs, and the closest that I've gotten to something working is with a combination of creating the Notifications as a class, adding them from the ViewModel and displaying them in the OnAppearing Method of the code behind. The code works right up until the if statement's body in the OnAppearing Method tries to execute and then it just stops and continues on with displaying the main page, but never showing the notifications. I am really new to using asynchronous programming, as well as Xamarin, so I'm pretty confused. This is my relevant code.
//Code starts in MainPageViewModel.cs
public MainPageViewModel()
{
Task.Run(async() => await CheckNotifications());
}
private async Task CheckNotifications()
{
await DatabaseService.Init();
var eventList = await DatabaseService.db.Table<Event>().ToListAsync();
if (eventList.Count > 0)
{
foreach (Event event in eventList)
{
if (event.NotifyStartDate && (event.StartDate.Date == DateTime.Today))
{
Notifications notification = new Notifications
{
Name = $"{event.Name}",
NotifyDate = event.StartDate,
Occurrence = "Starting"
};
await DatabaseService.AddNotification(notification);
}
if (event.NotifyEndDate && (event.EndDate.Date == DateTime.Today))
{
Notifications notification = new Notifications
{
Name = $"{event.Name}",
NotifyDate = event.EndDate,
Occurrence = "Ending"
};
await DatabaseService.AddNotification(notification);
}
}
}
}
This all seems to work fine, it creates a Notification with the event that starts today and adds it to the Notifications Table in the database. Next it moves to my MainPage Code Behind's OnAppearing method--> which is an async void method and I can't figure out any other way to do this, because I get an error that "MainPage.OnAppearing() return type must be void" if I try to make it a Task.
protected override async void OnAppearing()
{
//List fills fine here and holds my Test Event starting today information with a count of 1
var notifications = await DatabaseService.db.Table<Notifications>().ToListAsync();
if (notifications.Count > 0)
{
foreach(Notifications notification in notifications)
{
CrossLocalNotifications.Current.Show("Reminder", $"Event {notification.Name} is {notification.Occurrence} Today" +
$"on {notification.NotifyDate}");
//code stops at this line and continues the rest of the program without executing notification
}
}
base.OnAppearing();
}
My Init, FillSampleData, and AddNotifications methods in the database are all async tasks, and they all await other methods, but the problem seems to occur at OnAppearing. To add to that I am Navigating to the Main Page from App.Xaml.cs Synchrounously, because when I tried to make it an asynchronous method it got ignored there.
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new MainPage());
}
Everywhere else in my app the navigation awaits. I don't know if I'm just doing the notifications all wrong, if I'm just doing Asynchronous programming all wrong, or a little bit of both. Any help would be much appreciated. Thanks guys.
I created a custom Toast Notification for my Winforms application, whenever a custom result is returned, I use a ShowMessage extension to display the notification.
On my login screen, I have a unlock application button that will show the toaster message whenever the password is incorrect.
When I put a breakpoint right before the result.ShowMessage(); the notification appears. But when I remove the breakpoint, it does not appear anymore. I do not change any debug values.
How can I resolve this? I did try implementing a thread.sleep but it did not change anything, the notification only appears when I insert a breakpoint and continue over it.
It is worth noting that the notification works perfectly everywhere else in the application.
Code for the Unlock Application:
private void UnlockApplication()
{
var result = new Business.Server.User().Get(_loginModel.UserName, _loginModel.Password.Encrypt());
if (result.IsSuccessful)
{
// Perform log in process
}
else
{
result.ShowMessage(); //Only works when I put breakpoint here
}
}
Code for ShowMessage extension
public static void ShowMessage<T>(this Models.Result<T> result) where T : class
{
Helpers.ToasterNotificationHelper.ShowNotification(result.ResultTypeKey.ToDescription(), result.Message, result.ResultImage(), result.ResultColor(), result.ResultTypeKey == Enums.ResultTypeEnum.Warning ? 5000 : 2500);
}
public static void ShowNotification(string header, string message, Image icon, Color backgroundColor, int durationInMilliseconds = 1000)
{
if (Application.OpenForms[0] is MyApplication)
{
var toasterNotification = new ToasterNotificationControl(header, message, icon, backgroundColor);
(Application.OpenForms[0] as MyApplication).toastNotificationCollectionControl1.AddNotification(toasterNotification, durationInMilliseconds);
}
}
My Toast Notification control is a DevExpress flyout panel control that gets added to the Main application form
Your "Get(_loginModel.UserName ..." seems to be asynchronous. Try to do the next to make the call awaitable:
private async System.Threading.Tasks.Task UnlockApplicationAsync()
{
var result = await new Business.Server.User().Get(_loginModel.UserName, _loginModel.Password.Encrypt());
...
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);
}
}
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")));
Hi everyone i am using a WCF Soap Webservice and consuming it inside a Xamarin.Forms MVVM Client. (Mvvm light with MvvmLightNavigationExtension.
The Problem is when i use the Async Methods from the Webservice and corresponding Completed Event in my ViewModel the Navigation stucks / the screen is not changing.
When i debug the current Navigation Page says to be my second page but the first Page is still showing.
I Also tried it with Messengers but that wont work eather.
Down Below is some example Code.
Fun fact: When i make a second Button/Command and navigate to my second page after i called the GetLoginResponseCommand i can navigate Back two times to the first page.
Its Probably some weird Threading/UI Thread thing but i don't get it.
public LoginViewModel(INavigationService navigationService, MyWebService service)
{
_navigationService = navigationService;
_myWebService = service;
_myWebService.GetLoginInfoCompleted += MyWebServiceOnGetLoginInfoCompleted;
}
public RelayCommand GetLoginResponseCommand
{
get
{
return _getLoginResponseCommand ?? (_getLoginResponseCommand = new RelayCommand(
() =>
{
_orkaWebService.GetLoginInfoAsync(request);
}));
}
}
private void MyWebServiceOnGetLoginInfoCompleted(object sender, GetLoginInfoCompletedEventArgs e)
{
_navigationService.NavigateTo(VmKeys.ArtikelBestandKey);
}
Try to use async/ await in your async methods.
return _getLoginResponseCommand ?? (_getLoginResponseCommand = new RelayCommand(
async () =>
{
await _orkaWebService.GetLoginInfoAsync(request);
}));
I Got it myself.
The MyWebServiceOnGetLoginInfoCompleted runs in an own Thread. But the _navigationService needs to be run on the UIThread.
(Same for ContentPage.DisplayAlert or ContentPage.DisplayActionSheet)
When you run it like Device.BeginInvokeOnMainThread(() => _navigationService.NavigateTo(VmKeys.ArtikelBestandKey)); it works like a charm!
private void MyWebServiceOnGetLoginInfoCompleted(object sender, GetLoginInfoCompletedEventArgs e)
{
Device.BeginInvokeOnMainThread(() => _navigationService.NavigateTo(VmKeys.ArtikelBestandKey));
}
Thanks to Rohit for leading me to the right solution.