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.
Related
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);
}
}
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();
}
}
I have created a custom menu item which appears in the default menu which pops up when selecting text on my custom WebView.
On clicking on the menu item it calls EvaluateJavascript to get the selected WebView text, and then passes the text to another page.
However after performing this action once or twice, some text on certain areas of the screen start to become unresponsive to clicks eg. text on the parts of the WebView become unselectable, clicks on that part of the screen on other pages becomes unresponsive and even the soft keyboard becomes unclickable in some spots. If this continues for a while sometimes my app will then suddenly freeze the entire operating system and I have to soft reset my phone. It appears that there maybe some serious memory leakage going on.
I create my custom menu item in the MainActivity class:
public override void OnActionModeStarted(ActionMode mode)
{
if (Root.IsCurrentPageType<DictPage>() && DictP.IsWebViewFocused())
{
IMenu menu = mode.Menu;
menu.Add("To Notes");
menu.GetItem(0).SetOnMenuItemClickListener(new MyMenuItemOnMenuItemClickListener(this, mode));
}
base.OnActionModeStarted(mode);
}
It is then handled in the Listener class...
public class MyMenuItemOnMenuItemClickListener : Java.Lang.Object, IMenuItemOnMenuItemClickListener
{
private MainActivity mContext;
ActionMode _mode;
public MyMenuItemOnMenuItemClickListener(MainActivity activity, ActionMode mode)
{
this.mContext = activity;
_mode = mode;
}
public bool OnMenuItemClick(IMenuItem item)
{
WEB.CopyToMainNotes();
Device.BeginInvokeOnMainThread(() =>
{
//close menu if clicked
_mode?.Finish();
});
return true;
}
}
...which calls CopyToMainNotes on my derived WebView class and its associated Renderer and EventHandler classes:
public class WebViewEx : Xamarin.Forms.WebView
{
public static WebViewEx WEB;
//Namespace
//YourClass
public event WebViewExEventHandler CallNativeMethodEvent;
public void CallNativeMethod(WebViewExEventType type)
{
WebViewExEventArgs e = new WebViewExEventArgs();
e.EventType = type;
CallNativeMethodEvent?.Invoke(this, e);
}
public WebViewEx()
{
WEB = this;
}
public void CopyToMainNotes()
{
Device.BeginInvokeOnMainThread(() =>
{
CallNativeMethod(WebViewExEventType.copyToMainNotes);
});
}
}
public delegate void WebViewExEventHandler(object sender, WebViewExEventArgs e);
public class WebViewExEventArgs : EventArgs
{
public enum WebViewExEventType { copyToMainNotes };
public WebViewExEventType EventType = WebViewExEventType.copyToMainNotes;
public WebViewExEventArgs() : base()
{
}
}
public class WebViewExRenderer : WebViewRenderer
{
public WebViewExRenderer(Android.Content.Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if (Control != null)
{
WebViewEx ex = e.NewElement as WebViewEx;
ex.CallNativeMethodEvent += WebViewEx_CallNativeMethodEvent;
}
}
internal class JavascriptCallback : Java.Lang.Object, IValueCallback
{
public JavascriptCallback(Action<string> callback)
{
_callback = callback;
}
private Action<string> _callback;
public void OnReceiveValue(Java.Lang.Object value)
{
_callback?.Invoke(Convert.ToString(value));
}
}
private void WebViewEx_CallNativeMethodEvent(object sender, WebViewExEventArgs e)
{
switch (e.EventType)
{
case WebViewExEventType.copyToMainNotes:
{
CopyToMainNotes();
break;
}
}
}
public void CopyToMainNotes()
{
string script = "(function(){ return window.getSelection().toString()})()";
var response = string.Empty;
Control?.EvaluateJavascript(script, new JavascriptCallback((r) =>
{
response = r;
Device.BeginInvokeOnMainThread(() =>
{
DPage.CopyThisTextToAnotherPage(response.ToString().Trim('\"'));
});
}));
}
}
The CopyToMainNotes method above is where the EvaluateJavascript takes place and the selected text finally gets sent to another page.
Any ideas where I might be going wrong here? Thanks in advance!
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].
I am new to iOS, and I am using Xamarin Studio on MacOS (I already have my Xamarin.Droid app and now making it on iOS).
I am struggling using an UISearchBar, I want a really basic usage tho .. I tried to follow this recipes (https://developer.xamarin.com/recipes/ios/content_controls/search-controller/) but still can't manage to make it work.
What I am trying to get is a SearchBar, in which the user should type text then press the "search" button on the keyboard. Pressing the search button should call code that will populate an UITableView with data retrieved on my webservice.
Here's my Storyboard structure, a ViewController which contains an UITableView with a name
I tried the following code, everything seems to work fine, but when I press search on the keyboard, SearchButtonClicked event is never fired ... And I can't figure out why
public partial class SearchViewController : UIViewController
{
public SearchViewController(IntPtr handle) : base(handle)
{
}
public override void ViewDidLoad()
{
var searchController = new UISearchController(this);
searchController.SearchBar.SizeToFit();
searchController.SearchBar.ShowsCancelButton = true;
searchController.SearchBar.SearchButtonClicked += delegate {
Console.WriteLine("Hello ????");
this.Title = "This code is never called";
};
RunnersSearchTableView.TableHeaderView = searchController.SearchBar;
base.ViewDidLoad();
}
}
Also tried
public partial class SearchViewController : UIViewController
{
public SearchViewController(IntPtr handle) : base(handle)
{
}
public override void ViewDidLoad()
{
var searchController = new UISearchController(this);
searchController.SearchBar.SizeToFit();
searchController.HidesNavigationBarDuringPresentation = true;
searchController.SearchBar.ShowsCancelButton = true;
searchController.SearchBar.Delegate = new MySearchBarDelegate();
RunnersSearchTableView.TableHeaderView = searchController.SearchBar;
base.ViewDidLoad();
}
}
public class MySearchBarDelegate : UISearchBarDelegate
{
public MySearchBarDelegate()
{
}
public override void SearchButtonClicked(UISearchBar searchBar)
{
Console.WriteLine("TEST");
searchBar.ResignFirstResponder();
base.SearchButtonClicked(searchBar);
}
}
And also tried
public partial class SearchViewController : UIViewController
{
public SearchViewController(IntPtr handle) : base(handle)
{
}
public override void ViewDidLoad()
{
var searchController = new UISearchController(this);
searchController.SearchBar.SizeToFit();
searchController.HidesNavigationBarDuringPresentation = true;
searchController.SearchBar.ShowsCancelButton = true;
searchController.SearchBar.WeakDelegate = this;
RunnersSearchTableView.TableHeaderView = searchController.SearchBar;
base.ViewDidLoad();
}
[Export("searchBarSearchButtonClicked:")]
public virtual void SearchButtonClicked(UISearchBar searchBar)
{
Console.WriteLine("hello??");
searchBar.ResignFirstResponder();
}
}
None of them seems to work
You need to register delegate for searchbar .
[Foundation.Register("UISearchBar", true)]
for more : https://developer.xamarin.com/api/type/UIKit.UISearchBar/