Xamarin forms : bug in master detail Page - c#

I have a bug in my Xamarin Forms app. When I was coding page to appear content "master-detail" when the user chose on the last page. The content doesn't appear.
During debugging, the app work without any code errors; however, it appears without any content. I am using the Firebase database.
Firebase helper:
public async Task<List<Cuts>> GetAction()
{
return (await firebase
.Child("Action")
.OnceAsync<Cuts>()).Select(item => new Cuts
{
name = item.Object.name,
link = item.Object.link,
poster = item.Object.poster
}).ToList();
}
The page which the users choose from:
public partial class ActionFilms : ContentPage
{
FirebaseHelper firebaseHelper = new FirebaseHelper();
public ActionFilms()
{
InitializeComponent();
}
protected async override void OnAppearing()
{
base.OnAppearing();
var allPersons = await firebaseHelper.GetAction();
act.ItemsSource = allPersons;
}
public void act_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var acctionn = e.PreviousSelection as Cuts;
App.Current.MainPage.Navigation.PushAsync(new ActionMaster(acctionn));
}
}
The code of master-detail Page "which the content does not appear at here":
public partial class ActionMaster : ContentPage
{
public ActionMaster(Cuts acctionn)
{
BindingContext = acctionn;
InitializeComponent();
}
}

Related

Xamarin Forms QueryParameter Being Ignored

I have a shell app and I want to navigate from one page to another. I have followed the documentation and turotials step by step but for some reason the QueryParameter is being ignored(Since the Init method is not being called). Am I missing something?
First Page:
List<int> rowColumn = Methods.GetGridRowColumn((Frame)s);
HomeTab homeTab = dict[rowColumn[0]+""+rowColumn[1]];
var content = JsonConvert.SerializeObject(homeTab);
await Shell.Current.GoToAsync($"{nameof(CategoriesPage)}?homeTab={content}");
Page to navigate:
[XamlCompilation(XamlCompilationOptions.Compile)]
[QueryProperty(nameof(HomeTab), "homeTab")]
public partial class CategoriesPage : ContentPage
{
private HomeTab homeTab;
public string HomeTab
{
set
{
string content = Uri.UnescapeDataString(value);
homeTab = JsonConvert.DeserializeObject<HomeTab>(content);
Init();
}
}
public CategoriesPage()
{
InitializeComponent();
}
}

Why doesn't navigation work for me after calling Navigation.InsertPageBefore() in Xamarin Forms?

I'm trying to implement logging in on Xamarin Forms (5.0.0, using ActiveDirectory's built in Login page). Any ideas on how to make this work?
In the constructor of App.xaml.cs, I have:
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new LoginPage());
}
I implement the Login page w/ a view model, in which I pass in a callback that should (according to the documentation), set my navigation root to my HomePage:
public partial class LoginPage : ContentPage
{
private async Task _handleLoginAsync()
{
Navigation.InsertPageBefore(new HomePage(), this);
await Navigation.PopAsync();
}
public LoginPage()
{
InitializeComponent();
BindingContext = new LoginPageViewModel(_handleLoginAsync);
}
}
In the view model, I try to login using Device.BeginInvokeOnMainThread, calling my(note, I didn't include login logic for brevity/cleanliness)
public Command LoginCommand => new Command(LoginUsingAzureAsync);
private Func<Task>_handleLoginAsync;
public LoginPageViewModel(Func<Task> handleLoginAsync)
{
_handleLoginAsync = handleLoginAsync;
LoginCommand.Execute(null);
}
internal void LoginUsingAzureAsync()
{
Device.BeginInvokeOnMainThread(async () =>
{
try
{
if (await Login()) == true)
{
UserDialogs.Instance.HideLoading();
await _handleLoginAsync();
return;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
UserDialogs.Instance.Alert("The login has failed.");
}
});
}
It successfully goes to the homepage, but navigating to other pages afterwards doesn't work. When I call the following, it enters the OtherPage() constructor, but fails to render the new page.
Navigation.PushAsync(new OtherPage());
Note, the navigation works as expected if I use PushAsync(new HomePage()) rather than removing the login, but I'd prefer to remove the login page from the navigation stack.
Thanks in advance!
Update: Here's the initial HomeViewModel:
public class HomeViewModel
{
private readonly INavigation _navigation;
public Command GoToOtherPageCommand => new Command(GoToOtherPage);
public async void GoToOtherPage()
{
await App.Navigation.PushAsync(new OtherPage());
}
}
The problem wasn't in the login, it was in the HomePageViewModel, which was initially referencing App.Navigation (see update in question).
Passing in the navigation into my ViewModel did the trick:
public class HomeViewModel
{
private readonly INavigation _navigation;
public Command GoToOtherPageCommand => new Command(GoToOtherPage);
public async void GoToOtherPage()
{
await _navigation.PushAsync(new OtherPage());
}
public HomeViewModel(INavigation navigation)
{
_navigation = navigation;
}
}
public partial class HomePage : ContentPage
{
public HomePage()
{
InitializeComponent();
BindingContext = new HomeViewModel(Navigation);
}
}

How to change the toolbar back icon in xamarin forms android

I am working on xamarin forms. I wanted to change the Toolbar back icon how to do it. I searched lot about it. I didn't get proper solution. Any help would be appreciated.
Thanks
praveen
Try this
LoadApplication(new App());
var upArrow = Resources.GetDrawable(Resource.Drawable.abc_ic_ab_back_mtrl_am_alpha);
upArrow.SetColorFilter(Resources.GetColor(Resource.Color.white), PorterDuff.Mode.SrcIn);
ActionBar.SetHomeAsUpIndicator(upArrow);
References
https://forums.xamarin.com/discussion/57791/cant-change-android-back-button-in-xamarin-forms
https://forums.xamarin.com/discussion/103317/change-navigation-bar-back-button-color-in-xamarin-android
How to change the toolbar back icon in xamarin forms android
You could refer to my answer: How to change navigation page back button in xamarin forms.
I write it here again:
We need to custom a NavigationPageRenderer, override the OnPushAsync method to set the Toolbar's navigation icon.
using AToolbar = Android.Support.V7.Widget.Toolbar;
[assembly: ExportRenderer(typeof(CustomNavigationPage), typeof(NavigationPageRendererDroid))] // APPCOMP
...
public class NavigationPageRendererDroid : Xamarin.Forms.Platform.Android.AppCompat.NavigationPageRenderer // APPCOMP
{
public AToolbar toolbar;
public Activity context;
protected override Task<bool> OnPushAsync(Page view, bool animated)
{
var retVal = base.OnPushAsync(view, animated);
context = (Activity)Xamarin.Forms.Forms.Context;
toolbar = context.FindViewById<Android.Support.V7.Widget.Toolbar>(Droid.Resource.Id.toolbar);
if (toolbar != null)
{
if (toolbar.NavigationIcon != null)
{
toolbar.NavigationIcon = Android.Support.V4.Content.ContextCompat.GetDrawable(context, Resource.Drawable.Back);
//toolbar.SetNavigationIcon(Resource.Drawable.Back);
}
}
return retVal;
}
}
The CustomNavigationPage are defined in PCL :
public class CustomNavigationPage : NavigationPage
{
public CustomNavigationPage(Page startupPage) : base(startupPage)
{
}
}
Usage :
public App()
{
InitializeComponent();
MainPage = new CustomNavigationPage(new MainPage());
}
...
// In MainPage
private async void Button_Clicked(object sender, EventArgs e)
{
await Navigation.PushAsync(new TestPage());
}
[Effect].

Get result of an int changed in a ContentPage

I have an app with the following page structure:
MainPage
->SettingsPage
->InputLanguagePage
->OutputLanguagePage
All pages are ContentPages.
InputLanguagePage and OutputLanguagePage are the very same pages, so I don't want to program the very same page twice.
I can surely instantiate the same page twice, but I have no idea how I should get the return value.
I spent really long trying to describe my problem.
Perhaps the code below demonstrates the problem much better.
As you can see, I seem to be unable to get the return value of the LanguageSelectionPage since it's shown asynchronous.
Also changing it to Navigation.PushModalAsync() didn't change anything.
What would be the best way to have a ContentPage return a value or change a value and be notified about it?
Thank you.
MainPage:
public class MainPage : ContentPage
{
private async void OnSettingsSelected(object sender, EventArgs e)
{
SettingsPage nSettings = new SettingsPage();
await this.Navigation.PushAsync(nSettings);
}
(...)
SettingsPage:
public class SettingsPage : ContentPage
{
public SettingsPage()
{
protected override async void OnAppearing()
{
base.OnAppearing();
_btnInputLanguage.Clicked += async (sender, e) =>
{
LanguageSelectionPage nInputLanguage = new LanguageSelectionPage();
nInputLanguage.SelectedLCID = App.Settings.InputLanguageLCID;
await Navigation.PushAsync(nInputLanguage);
//The user can change "int SelectedLCID" within the ContentPage, but I have no idea how I could access it
return;
};
_btnOutputLanguage.Clicked += async (sender, e) =>
{
LanguageSelectionPage nOutputLanguage = new LanguageSelectionPage();
nOutputLanguage.SelectedLCID = App.Settings.OutputLanguageLCID;
await Navigation.PushAsync(nOutputLanguage);
//The user can change "int SelectedLCID" within the ContentPage, but I have no idea how I could access it
return;
};
(...)
LanguageSelectionPage:
public class LanguageSelectionPage : ContentPage
{
public int SelectedLCID { get; set; }
protected override async void OnAppearing()
{
base.OnAppearing();
(...)
I will give solutin to pass it ass parameter when yu ask to load page
public partial class InputLanguagePage : ContentPage
{
public InputLanguagePage(string Selection)
{
InitializeComponent();
}
}
public partial class OutputLanguagePage : ContentPage
{
public OutputLanguagePage(string Selection)
{
InitializeComponent();
}
}
In settingsPage Button Click
_btnInputLanguage.Clicked += async (sender, e) =>
{
Navigation.PushAsync(new InputLanguagePage ("SelectLanguage"));
return;
};
_btnOutputLanguage.Clicked += async (sender, e) =>
{
Navigation.PushAsync(new OutputLanguagePage("SelectLanguage"));
return;
};
There are a lot of ways to solve this:
pass a completion handler to the 2nd page
raise an event on the 2nd page and subscribe from the 1st page
pass an object whose value will be set by the 2nd page
use Messaging
*
// on the first page, listen for a message
MessagingCenter.Subscribe<SecondPage, string> (this, "ValueSet", (sender, arg) => {
// arg will contain the value passed by the sender
});
// when the value is set on the 2nd page, send a message
MessagingCenter.Send<SecondPage, string> (this, "ValueSet", someValue);

System.Reflection.TargetInvocationException on MessagingCenter.Send

I'm trying to build simple navigation using MessagingCenter but I'm receiving System.Reflection.TargetInvocationException when I pressed the back button (hardware button).
Here is how I get the error;
After app load,
I hit the back button (hardware button)
Then after the app got minimized, I open it in recent app
After that, I click on Login then I got this error:
Unhandled Exception:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
pointing on
MessagingCenter.Send<object>(this, App.EVENT_LAUNCH_MAIN_PAGE);
in Login Method in LoginPage.xaml.cs
PS: The code works well if I don't hit the back button (hardware button)
Here is the code:
App.xaml.cs
public partial class App : Application
{
public static string EVENT_LAUNCH_LOGIN_PAGE = "EVENT_LAUNCH_LOGIN_PAGE";
public static string EVENT_LAUNCH_MAIN_PAGE = "EVENT_LAUNCH_MAIN_PAGE";
public App()
{
InitializeComponent();
MainPage = new App3.LoginPage();
MessagingCenter.Subscribe<object>(this, EVENT_LAUNCH_LOGIN_PAGE, SetLoginPageAsRootPage);
MessagingCenter.Subscribe<object>(this, EVENT_LAUNCH_MAIN_PAGE, SetMainPageAsRootPage);
}
private void SetLoginPageAsRootPage(object sender)
{
MainPage = new NavigationPage(new LoginPage());
}
private void SetMainPageAsRootPage(object sender)
{
MainPage = new NavigationPage(new App3.MainPage());
}
protected override void OnStart()
{
// Handle when your app starts
}
protected override void OnSleep()
{
// Handle when your app sleeps
}
protected override void OnResume()
{
// Handle when your app resumes
}
}
LoginPage.xaml.cs
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class LoginPage : ContentPage
{
public Command LoginCommand { get; }
public LoginPage()
{
InitializeComponent();
LoginCommand = new Command(() => Login());
Button btn = new Button { Text = "Login", Command = LoginCommand };
Content = new StackLayout
{
Children =
{
btn
}
};
}
public void Login()
{
MessagingCenter.Send<object>(this, App.EVENT_LAUNCH_MAIN_PAGE);
}
}
MainPage.xaml.cs
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
ToolbarItems.Add(new ToolbarItem("Logout", "", () => Logout()));
}
public void Logout()
{
MessagingCenter.Send<object>(this, App.EVENT_LAUNCH_LOGIN_PAGE);
}
}
That was a bug in Xamarin.Forms Version 2.3.3.175. To fix this bug install an earlier version of Xamarin.Forms. I get my app running with version 2.3.0.107.
The bug in version 2.3.3.175 should be fixed in version 2.3.4-pre1.

Categories

Resources