Assume that i'm in the Page_1 while click the button have to navigate to Page_2.In Page_2 Api call has to done.
MyIssue is when i'm clicking the Button it doesn't navigate to Page_2 immediately it waits for the API response.
How to Navigate Immediately to Page_2 without waiting for the APi response.
Code:
Page_1.cs
public partial class Page_1 : ContentPage
{
public Page_1()
{
InitializeComponent();
}
private void Btn_click(object sender, EventArgs e)
{
Navigation.PushAsync(new Page_2());
}
}
Page_2:
public Page_2()
{
InitializeComponent();
}
protected override void OnAppearing()
{
HttpClient httpClient = new HttpClient();
var obj = httpClient.GetAsync("//Api//").Result;
if (obj.IsSuccessStatusCode)
{
}
}
Same code works good in iOS as expected
You could load your data in an other Task to prevent blocking the UI.
protected override void OnAppearing()
{
Task.Run( () => LoadData());
base.OnAppearing();
}
private async void LoadData()
{
HttpClient httpClient = new HttpClient();
var obj = await httpClient.GetAsync("//Api//");
if (obj.IsSuccessStatusCode)
{
// If you need to set properties on the view be sure to use MainThread
// otherwise you won't see it on the view.
Device.BeginInvokeOnMainThread(() => Name = "your text";);
}
}
As per your question you are calling the API on Page constructor that's why it's taking time to load web API then navigating on page2. If you want to navigate on page2 before a load the api. Check below code
public partial class Page2 : ContentPage
{
bool IsLoading{ get; set; }
public Page2()
{
InitializeComponent();
IsLoading = false;
}
protected async override void OnAppearing()
{
base.OnAppearing();
if (!IsLoading)
{
IsLoading=true
**Call the Web API Method Here**
}
IsLoading=false
}
}
Related
I am trying to consume an interface but I am having some difficulty here.
I am trying to set it to a xamrin list view in behind a content page
public class xxxApiClient : IApi
{
readonly string url = "http://localhost:81/ ";
readonly IHttpService httpService;
public xxxApiClient(IHttpService httpService)
{
this.httpService = httpService;
}
public Task<List<JobsList>> GetJobs() => httpService.Get<List<JobsList>>($"{url}JobsLists");
}
How ever I am not to sure how I cosume getjobs correclty I am trying the following
public partial class JobsPage : ContentPage ,xxxWC.Interface.IApi
{
public xxxWC.Interface.IApi api = new ful;
public JobsPage ()
{
InitializeComponent ();
}
private Task SetItemSource()
. {
. JobListing.ItemsSource = FuelAp
}
How do I use the get jobs correctly above in the method setItemSource?.
The bit I am having hard time to understand is here.
How do I call the base GetJobs method I have already created in API Client.
Task<List<JobsList>> IApi.GetJobs()
{
throw new NotImplementedException();
}
private Task SetItemSource()
{
JobListings.ItemsSource =await GetJobs();
}
}
Edit 2
Ok based on suggestions below I updated My Code as such
IHttpService httpService;
xxxApiClient _api = newxxxApiClient(httpService);
public JobsPage ()
{
InitializeComponent ();
}
private Task SetItemSource()
{
JobListings.ItemsSource =await GetJobs();
}
But i get the below error
Severity Code Description Project File Line Suppression State
Error CS0236 A field initializer cannot reference the non-static
field, method, or property
'JobsPage.httpService' xxxCallManagmentAppMobile C:\Work\xxxCallAppDev\XamForms\xxxCallManagmentApp\xxxCallManagmentAppMobile\FuelCallManagmentAppMobile\Views\JobsPage.xaml.cs 17 Active
Can someone explain why
Edit 3
Ok i got a bit further but still having some issues. as the main method is not awaited how do I call set SetItemSource.
xxxApiClient _api ;
public JobsPage ()
{
InitializeComponent ()
SetItemSource();
}
private async Task SetItemSource()
{
JobListings.ItemsSource = await client.GetJobs();
}
Assuming that IApi has been mapped to xxxApiClient implementation
Try resolving the service using the DependencyService so that it is available to be used in the view
public partial class JobsPage : ContentPage {
public readonly IApi client;
public JobsPage () {
InitializeComponent ();
client = DependencyService.Get<IApi>();
}
private async Task SetItemSource() {
JobListing.ItemsSource = await client.GetJobs();
//...
}
}
As for calling the SetItemSource, it is async so should be awaited. That can't be done in the constructor.
Consider creating a event that can be raised and its handler used to await the desired behavior.
private event EventHandler loadingData = delegate { };
private async void onLoadingData(object sender, Eventargs args) {
JobListing.ItemsSource = await client.GetJobs();
}
Full code
public partial class JobsPage : ContentPage {
public readonly IApi client;
public JobsPage () {
InitializeComponent ();
//resolving client
client = DependencyService.Get<IApi>();
//subscribing to event
loadingData += onLoadingData;
//raising event
loadingData(this, EventArgs.Empty);
}
private async Task SetItemSource() {
JobListing.ItemsSource = await client.GetJobs();
//...
}
private event EventHandler loadingData = delegate { };
private async void onLoadingData(object sender, Eventargs args) {
JobListing.ItemsSource = await client.GetJobs();
}
}
Although a custom event was created, you could just as easily used on of the event/eventhandler of the view.
All of that code should actually live inside of a view model and then bound to the view in a binding context.
I'm developing an application with windows-10-t platform on raspberry-pi3. The application has several pages and listens GPIO ports asyncrhonously in the background. It collects data from GPIO and sends to the WCF-Service, after a bit the UI should be updated by the data coming from the WCFService. I've also tried using Tasks, Dispatcher.Invoke etc. but nothing worked properly. I can collect data coming from GPIO but cannot update UI. What am I doing wrong?
Here is the background GPIO listener class with static variables (I'm listening GPIO in other pages too.):
public sealed class GPIO{
private static MainPage mainpage;
public static event EventHandler ProgressUpdate;
public static void InitGPIO(MainPage sender)
{
mainpage = sender;
DataPin.DebounceTimeout = TimeSpan.FromMilliseconds(50);
DataPin.ValueChanged += DataPin_ValueChanged;
}
public static void DataPin_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs e)
{
if (e.Edge == GpioPinEdge.FallingEdge)
{
Task.Run(() => AddData(0));
}
}
public static async void AddData(int prm_Data)
{
// WCF-Service Operation
await Service.wsClient.GPIOValueAddition(prm_Data);
GPIO.ProgressUpdateOperation();
}
private static void ProgressUpdateOperation()
{
mainpage.GPIO_ProgressUpdate(typeof(GPIO), new EventArgs());
}
}
And here is the page that contains the UI to be updated:
public sealed partial class MainPage : Page
{
public MainPage()
{
GPIO.InitGPIO(this);
GPIO.ProgressUpdate += GPIO_ProgressUpdate;
}
public void GPIO_ProgressUpdate(object sender, EventArgs e)
{
// WCF-Service Operation
service_data = (int)Service.wsClient.GetDataFromServicetoUpdateUI(parameter).Result;
// UI-update
txtUpdate.Text = service_data.ToString();
}
}
EDIT: I forgot to add the exception. "The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))" exception is thrown at AddData function called in DataPin_Valuechanged.
I found the solution in here : https://stackoverflow.com/a/27698035/1093584
Here is the new update-UI function :
public void GPIO_ProgressUpdate(object sender, EventArgs e)
{
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
service_data = await Service.wsClient.GetDataFromServicetoUpdateUI(parameter);
// UI-update
txtUpdate.Text = service_data.ToString();
});
}
I'm trying to call an async function but when I try and do it it has the red line underneath it. I want the function to be called when the page is opened, thanks in advance.
public partial class Home : ContentPage
{
public class GoogleProfile
{
public string Id { get; set;}
}
public Home()
{
InitializeComponent();
}
protected override async void OnAppearing()
{
await Check(/*What do i put in here*/);
}
public async Task Check(GoogleProfile googleprofile)
{
if (String.IsNullOrEmpty(googleprofile.Id))
{
}
else {
await Navigation.PushAsync(new LoginPage());
}
}
}
how would i call this? Sorry im new to C# and xamarin
You should make your async calls in ContentPage.OnAppearing(). The OnAppearing() event will be called, as the name suggest, right when your page is being displayed. This is the expected behavior by the user. Also note that I changed your Check() method to return Task because, if you are able to edit the method signature, always try to change the return type of async methods from void to Task:
public partial class LoginPage : ContentPage {
public LoginPage() {
InitializeComponent();
}
protected override async void OnAppearing() {
await Check(/* Add code here to get your GoogleProfile object */);
}
public async Task Check(GoogleProfile googleprofile) {
var ID = googleprofile.Id;
if (string.IsNullOrEmpty(ID)) {
return;
} else {
await Navigation.PushAsync(new Home());
}
}
}
Technically, if you are dead set to not use OnAppearing() you could do the Check() before pushing your LoginPage, though without seeing more code, that would seem like it would defeat the purpose of the LoginPage.
I want to pass data from a child page of the MainPage in my app. The problem, from what I can tell is that there is a splash loading screen that navigates to the MainPage and I want to write an "If navigated from child page" block to include in the OnNavigatedTo.
Here is my MainPage.xaml.cs code:
protected override void OnNavigatedTo(NavigationEventArgs args)
{
if (base.OnNavigatedFrom(args) = ChildPage)
{
// Code for: If navigated from child page
ReturnData returnData = args.Parameter as ReturnData;
this.myNewString = returnData.myString;
}
base.OnNavigatedTo(args);
}
I found out that you cannot return data the way it is used by passing data to another page for Windows 8 Apps. You cannot return data they way you pass it i.e. this.Frame.Navigate(typeof(MainPage), passData); For the solution, I created a 'Completed' event and and called it from the MainPage C# code behind.
MainPage.xaml.cs:
protected override void OnNavigatedFrom(NavigationEventArgs args)
{
if (args.SourcePageType.Equals(typeof(ChildPage)))
(args.Content as ChildPage).Completed += OnChildPageCompleted;
base.OnNavigatedFrom(args);
}
void OnChildPageCompleted(object sender, ReturnData args)
{
// Code to run if returned back to MainPage from ChildPage
this.myNewString = returnData.myString;
(sender as ChildPage).Completed -= OnChildPageCompleted;
}
ReturnData.cs:
namespace MyTestApp
{
class ReturnData
{
public String myString { set; get; }
}
}
ChildPage.xaml.cs:
public event EventHandler<ReturnData> Completed;
ChildPage.xaml.cs:
protected override void OnNavigatedFrom(NavigationEventArgs args)
{
if (Completed != null)
{
// Create ReturnData object
ReturnData returnData = new ReturnData();
returnData.myString = newStringChanged;
// Fire Completed event
Completed(this, returnData);
}
base.OnNavigatedFrom(args);
}
In a background agent I create (or update) one of application live tiles and this works as expected.
Problem is that when I click this live tile screen flickers but my app is not "restarted" nor "shown".
What's wrong?
I attach small part of the code, but ask for more is you need.
MAIN PAGE
public partial class MainPage : PhoneApplicationPage
{
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
}
public MainPage()
{
InitializeComponent();
// Runs background agent: code is simplified
StartAgent();
}
}
BACKGROUND AGENT
public class TileAgent : ScheduledTaskAgent
{
protected override void OnInvoke(ScheduledTask task)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
Vars.UpdateTiles();
});
NotifyComplete();
}
}
STATIC CLASS
public class Vars
{
private static Uri uri = new Uri(
"/MainPage.xaml?tile",
UriKind.RelativeOrAbsolute);
private static RadExtendedTileData ExtendedData
{
get
{
return new RadExtendedTileData()
{
VisualElement = frontTile,
BackVisualElement = backTile,
};
}
}
public static void UpdateTiles()
{
// I perform some task here
// Then I create/update live tile
Telerik.Windows.Controls.LiveTileHelper.CreateOrUpdateTile(
ExtendedData, uri);
}
}
Try /MainPage.xaml?tile=true instead of /MainPage.xaml?tile...
And move NotifyComplete() into the dispatcher call. Otherwise it will be called before the operation has been completed...