How to check if an application is it's first run or not in xamarin crosspaltform - xaml

I want to show some pages in the first time app is installed, and the next time when I open the app show some other pages.
I tried this code
protected override void OnStart()
{
if (Application.Current.Properties.ContainsKey("id"))
{
MainPage = new NavigationPage(new Page2());
}
else
{
Application.Current.Properties["id"] = 2;
MainPage = new NavigationPage(new Page1());
}
}
The values in the Properties dictionary are only stored when the app goes to sleep

For a cross-platform approach, you can use the Settings Plugin
Then you can create a boolean property, for example, DidOpenOnce, and if it is false, show your initial welcome page or whatever. Then afterwards, set it to true.

protected void checkApplicationInstallState()
{
//retreive
var prefs = Application.Context.GetSharedPreferences("MyApp", FileCreationMode.Private);
var somePref = prefs.GetBool("IsApplicationOpenedForOnce", null);
if (!somePref) {
// Your Application is opened for the very first time. Now change the value to true as you have now opened the app so next time opening this application should get a true value.
var prefEditor = prefs.Edit();
prefEditor.PutBool(true, "IsApplicationOpenedForOnce");
prefEditor.Commit();
}
}

public MainPage()
{
InitializeComponent();
if (Application.Current.Properties.ContainsKey("FirstUse"))
{
//Do things when it's NOT the first use...
loadinit();
}
else
{
Application.Current.Properties["FirstUse"] = false;
//Do things when it IS the first use...
}
}
public async void loadinit()
{
await Navigation.PushAsync(new LoadPage());
}

Related

how i know blazor OnInitializedAsync exec in once or twice

I want get data from db once on OnInitializedAsync. I try to use tableLoading to judue,but it's not work.
protected override async Task OnInitializedAsync()
{
if (tableLoading)
{
return;
}
tableLoading = true;
users = await userService.GetSome(1, userType);
_total = await userService.GetCount(userType);
tableLoading = false;
Console.WriteLine("OnInitializedAsync");
}
This is the official way to solve your problem. You have to persist component state during first load so that your services won't be called second time during second load.
First add <persist-component-state /> tag helper inside your apps body:
<body>
...
<persist-component-state />
</body>
Then inject PersistentComponentState in your component and use like this:
#implements IDisposable
#inject PersistentComponentState ApplicationState
#code {
private IEnumerable<User> _users;
private int _total;
private PersistingComponentStateSubscription _persistingSubscription;
protected override async Task OnInitializedAsync()
{
_persistingSubscription =
ApplicationState.RegisterOnPersisting(PersistState);
if (!ApplicationState.TryTakeFromJson<IEnumerable<User>>("users", out var restoredUsers))
{
_users = await userService.GetSome(1, userType);
}
else
{
_users = restoredUsers;
}
if (!ApplicationState.TryTakeFromJson<int>("total", out var restoredTotal))
{
_total = await userService.GetCount(userType);
}
else
{
_total = restoredTotal;
}
}
private Task PersistState()
{
ApplicationState.PersistAsJson("users", _users);
ApplicationState.PersistAsJson("total", _total);
return Task.CompletedTask;
}
void IDisposable.Dispose()
{
_persistingSubscription.Dispose();
}
}
How i know blazor OnInitializedAsync exec in once or twice?
It usually loads twice.
Once when the component is initially rendered statically as part of the page.
A second time when the browser renders the component.
However, If you want to load it once, in that case, you could go to _Host.cshtml and change render-mode="ServerPrerendered" to render-mode="Server", and it would be called only once as a result it would then load your data from the database once only.
Note: For more information you could refer to the official documents here.
I know it's usually loads twice, i want to know when the function is run, how to konw it's run on once or twice. This is my solution.
static bool first = true;
protected override async Task OnInitializedAsync()
{
if (first)
{
first = false;
Console.WriteLine("first time");
return;
}
Console.WriteLine("second time");
}

Codename One location sometimes not working

Old question: Codename One app not provide real location
We still have problem getting current location.
Sometimes it's ok, "Localizzazione..." dialog shows, then location ok callback dispose the dialog.
Sometimes the dialog is never disposed and I don't see GPS in the top bar, which is visible when location is ok and dispose the dialog.
Slider s1 = new Slider();
Display.getInstance().callSerially(() -> {
blocco_loc_in_corso = makeDialog("Localizzazione...", s1, null, 'a');
blocco_loc_in_corso.show();
});
LocationManager locationManager = LocationManager.getLocationManager();
locationManager.setLocationListener(new LocationListener() {
#Override
public void locationUpdated(Location location) {
if(location != null) {
Display.getInstance().callSerially(() -> {
if(blocco_loc_in_corso != null) {
blocco_loc_in_corso.dispose();
}
});
paintLocation(location, true);
}
}
#Override
public void providerStateChanged(int newState) {
}
}, new LocationRequest(LocationRequest.PRIORITY_HIGH_ACCUARCY, 1000));
I have this problem for at least 6 months. We only need to block user until we have his GPS location which may can change (GPS updates callback).
Edited:
public Dialog makeDialog(String label, Component c, String buttonText, char btIcon) {
Dialog dlg_r = new Dialog();
Style dlgStyle = dlg_r.getDialogStyle();
dlgStyle.setBorder(Border.createEmpty());
dlgStyle.setBgTransparency(255);
dlgStyle.setBgColor(0xffffff);
Label title = dlg_r.getTitleComponent();
title.getUnselectedStyle().setFgColor(0xff);
title.getUnselectedStyle().setAlignment(Component.LEFT);
dlg_r.setLayout(BoxLayout.y());
Label blueLabel = new Label(label);
blueLabel.setShowEvenIfBlank(true);
blueLabel.getUnselectedStyle().setBgColor(0xff);
blueLabel.getStyle().setFgColor(0x0a0afc);
blueLabel.getStyle().setAlignment(Component.CENTER);
blueLabel.getUnselectedStyle().setPadding(1, 1, 1, 1);
blueLabel.getUnselectedStyle().setPaddingUnit(Style.UNIT_TYPE_PIXELS);
dlg_r.add(blueLabel);
dlg_r.add(c);
if (buttonText != null) {
Button dismiss = new Button(buttonText);
dismiss.getAllStyles().setBorder(Border.createEmpty());
dismiss.getAllStyles().setFgColor(0);
dismiss.getAllStyles().set3DText(true, true);
dismiss.setIcon(FontImage.createMaterial(btIcon, dismiss.getStyle()));
dismiss.addActionListener(((evt) -> {
dlg_r.dispose();
}));
dlg_r.add(dismiss);
}
return dlg_r;
}
To make sure this code is threadsafe make the following change:
public void locationUpdated(Location location) {
locationFound = true;
// ...
}
Then in the make dialog method:
dlg_r.addShowListener(e -> {
if(locationFound) {
dlg_r.dispose();
}
});
Since this event can happen in the dead time of showing the dialog transition.

Xamarin forms: Multiple navigation patterns in the same app

Can we have multiple navigation patterns in a single app?
In my app.xaml page I added a function
void SetUpNavigation()
{
var page = FreshPageModelResolver.ResolvePageModel<LaunchPageModel>();
var navPage = new FreshNavigationContainer(page);
MainPage = navPage;
}
But after a user signs in I want to use master detail page. Is there a way to do that ??
Yes. You just have to set the MainPage of your app again. In our projects, we use a helper class which have a method Restart with following logic:
public static void Restart(View view, NavigationType navtype)
{
// Reset the mainpage depending on the navigation type
if (navtype == NavigationType.RestartWithMasterPage)
{
Application.Current.MainPage = new MasterPage(view);
}
else if (navtype == NavigationType.Restart)
{
Application.Current.MainPage = new NavigationPage(view);
}
else
{
// Just show the page
Application.Current.MainPage = view;
}
}
The NavigationType is an enum:
public enum NavigationType
{
Normal,
Restart,
RestartWithMasterPage
}

pageState and viewModelState is null on Page Navigation in UWP

I am using Prism 6 with UWP. I have a button in MainPage.xaml which redirect to DashboardPage.xaml. In DashboardPage, I am saving the view state in DashboardPage.xaml.cs :
protected override void SaveState(Dictionary<string, object> pageState)
{
base.SaveState(pageState);
pageState["viewState"] = 123;
}
and saving view model state in DashboardPageViewModel.cs :
public override void OnNavigatingFrom(NavigatingFromEventArgs e, Dictionary<string, object> viewModelState, bool suspending)
{
base.OnNavigatingFrom(e, viewModelState, suspending);
}
[RestorableState]
public string Name
{
get { return _name; }
set { SetProperty(ref _name, value); }
}
By pressing back button from topbar, I went back to MainPage.xaml. After that, when I navigate to DashboardPage.xaml again, I found that view state and view model states are being null. Which means, in the below code of DashboardPage.xaml.cs
protected override void LoadState(object navigationParameter, Dictionary<string, object> pageState)
{
if (pageState == null)
{
return;
}
base.LoadState(navigationParameter, pageState);
if (pageState.ContainsKey("viewState"))
{
var data = pageState["viewState"].ToString();
}
}
pageState is found null.
And, for view model state in DashboardPageViewModel.cs :
public async override void OnNavigatedTo(NavigatedToEventArgs e, Dictionary<string, object> viewModelState)
{
base.OnNavigatedTo(e, viewModelState);
}
viewModelState is null
By pressing back button from topbar, I went back to MainPage.xaml. After that, when I navigate to DashboardPage.xaml again, I found that view state and view model states are being null.
From your posted project. I found that you use NavigationService.Navigate to navigate to DashboardPage. It's right at first time, but after you navigating back to MainPage and again navigate back to DashboardPage. You are also using the NavigationService.Navigate API.
I downloaded Prism's Source Codes and found where the LoadState is called:
protected override void OnNavigatedTo(NavigationEventArgs navigationEventArgs)
{
...
if (navigationEventArgs.NavigationMode == NavigationMode.New)
{
var nextPageKey = _pageKey;
int nextPageIndex = frameFacade.BackStackDepth;
while (frameState.Remove(nextPageKey))
{
nextPageIndex++;
nextPageKey = "Page-" + nextPageIndex;
}
// Pass the navigation parameter to the new page
LoadState(navigationEventArgs.Parameter, null);
}
else
{
LoadState(navigationEventArgs.Parameter, (Dictionary<String, Object>)frameState[_pageKey]);
}
}
As you can see, the LoadState is called inside OnNavigatedTo and PageState is passed as argument on condition that the NavigationMode is not New. For ViewModelState it is the similar situation. And for your case, everytime navigating to a page through NavigationService.Navigate will create a totally new page, which means NavigationMode=NavigationMode.New. Therefore PageState and ViewModelState are null.
From the NavigationMode document we can see the NavigationMode.Forward fits your requirement.
So, to fix the problem. The only thing that needs to be done is to modify the OnPageChange method in MainPageViewModel.cs like codes below:
private void OnPageChange()
{
if (_navigationService.CanGoForward())
{
_navigationService.GoForward();
}
else
{
_navigationService.Navigate("Dashboard", null);
}
}

In Silverlight, how do I set focus on a control on page load?

When my Silverlight page loads, I want to set focus on a control. Simple problem with a not-so-obvious solution.
I tried the following with no luck. The page loads but my control does not have focus.
public MainPage()
{
InitializeComponent();
if( !DesignerProperties.IsInDesignTool )
{
// some init code goes here...
this.Loaded += ( s, e ) =>
{
this.InitFocus();
};
}
}
private void InitFocus()
{
this.PropNumTextBox.Focus();
}
The solution is to use System.Windows.Browser.HtmlPage.Plugin.Focus(). When I call this prior to calling Focus on my initial control, it works as expected. The correct code looks as follows:
public MainPage()
{
InitializeComponent();
if( !DesignerProperties.IsInDesignTool )
{
// init code here...
this.Loaded += ( s, e ) =>
{
this.InitFocus();
};
}
}
private void InitFocus()
{
// this call is necessary to initialize focus on page load
System.Windows.Browser.HtmlPage.Plugin.Focus();
this.PropNumTextBox.Focus();
}