How to use ContextMenu in Monodroid - xamarin.android

I am trying to implement a ContextMenu from a button in the titlebar, but it doesn't appear
to be working. I register the button, but when I click it, nothing
is happening. Any ideas? I'm using MonoDroid 1.2. Thanks.
public class MainActivity : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.main);
Button btnMenu =
(Button)FindViewById(Resource.Id.btn_menu_options);
RegisterForContextMenu(btnMenu);
}
public override void OnCreateContextMenu(IContextMenu menu, View v,
IContextMenuContextMenuInfo menuInfo)
{
base.OnCreateContextMenu(menu, v, menuInfo);
menu.SetHeaderTitle(Resource.String.menu_title);
menu.Add(Resource.String.menu_option1);
}
}

What do you mean under "button in the titlebar"? I have just created demo project and all works fine. Here is a code:
[Activity(Label = "MonoAndroidApplication1", MainLauncher = true, Icon = "#drawable/icon")]
public class Activity1 : Activity
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
var button = FindViewById<Button>(Resource.Id.MyButton);
RegisterForContextMenu(button);
}
public override void OnCreateContextMenu(IContextMenu menu, View v, IContextMenuContextMenuInfo menuInfo)
{
base.OnCreateContextMenu(menu, v, menuInfo);
menu.SetHeaderTitle(Resource.String.MenuTitle);
menu.Add(Resource.String.Action1);
menu.Add(Resource.String.Action2);
}
public override bool OnContextItemSelected(IMenuItem item)
{
Toast.MakeText(this, item.TitleFormatted, ToastLength.Short).Show();
return true;
}
}

I believe the context menu is a long press. Just pressing the button normally won't activate it. You need to do a long press.

Related

Xamarin Android cannot override OnBackButtonPressed method

My problem is whenever i try to override OnBackButtonPressed visual studio just tells me that there are no method that can be override.
Here is the code
[Activity(Label = "#string/app_name", Theme = "#style/AppTheme", MainLauncher = true)]
public class MainActivity : AppCompatActivity {
protected override void OnCreate(Bundle savedInstanceState) {
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults){
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
protected override bool OnBackButtonPressed() {
return true;
}
}
}
whenever i remove "override" tag the error disapper but the evente is never triggered.
Any idea why cant override this method?
OnBackPressed is an Android method, you can override it in the file MainActivity.cs this way:
public override void OnBackPressed()
{
// your code over here
base.OnBackPressed();
}

Xamarin.iOS with MVVMCross call only constructors at ViewControllers

Does anybody face this problem? I'm trying to implement MVVM using MVVMCross in Xamarin.iOS project, but in ViewController only constructor was called, neither ViewDidLoad nor ViewWillAppear. What's wrong? Or may be I miss something? Thank you.
public partial class VideosViewController : MvxViewController<VideoListViewModel>
{
public VideosViewController() : base(nameof(VideosViewController), null)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
}
}
public class VideoListViewModel : MvxViewModel
{
private readonly IVideoService _videoService;
public CancellationTokenSource TokenSource => new CancellationTokenSource();
public VideoListViewModel(IVideoService videoService)
{
_videoService = videoService;
}
public override async Task Initialize()
{
await base.Initialize();
}
}

Navigate to ViewModel From Current View Instead of RootView

Is there a way to navigate to a ViewModel from my current view instead the root view?
I have created a view model that is presented modally from the root view and wish to present a view model within that view.
For example, when calling _navigationService.Navigate<MyViewModel>(); from my modal view, the root view navigates to MyViewModel instead of the current modal view. This leaves my modal screen with a blank page until you dismiss it and see that the navigation has taken place below.
Do I create a custom navigation, or is there a better way of going about this?
EDIT
Here is some code:
My View Model
public class ViewModel1 : MvxViewModel
{
private readonly IMvxNavigationService _navigationService;
public ViewModel1(IMvxNavigationService navigationService)
{
_navigationService = navigationService;
}
public IMvxCommand NavigateCommand => new MvxCommand(ChangeView);
void ChangeView()
{
_navigationService.Navigate<ViewModel2>();
}
}
My View
[MvxModalPresentation(WrapInNavigationController = true, ModalPresentationStyle = UIModalPresentationStyle.Custom, Animated = false)]
public partial class MyView : MvxViewController
{
ViewModel1 VM;
public MyView() : base("MyView", null)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
NavigationController.NavigationBar.Hidden = true;
var set = this.CreateBindingSet<MyView, ViewModel1 >();
set.Bind(NextButton).To(vm => vm.NavigateCommand);
set.Apply();
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
// Release any cached data, images, etc that aren't in use.
}
}
I would like to have the navigation command present ViewModel2 within the presented modal.
For this kind of customization, you may need a write a custom presenter and there you can fiddle around to achieve whatever you can achieve with native.
I am dropping some hint.
In AppDelegate, inside finish launching.
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
Window = new UIWindow(UIScreen.MainScreen.Bounds);
var presenter = new DelegatingPresenter(this, Window);
var setup = new Setup(this, presenter);
setup.Initialize();
var startup = Mvx.Resolve<IMvxAppStart>();
startup.Start();
---
---
}
DelegatingPresenter looks like:
public class DelegatingPresenter : MvxIosViewPresenter {
private UIWindow currentWindow;
public DelegatingPresenter(AppDelegate appDelegate, UIWindow window)
: base(appDelegate, window) {
currentWindow = window;
--
---
}
protected override void SetWindowRootViewController(UIViewController controller, MvvmCross.iOS.Views.Presenters.Attributes.MvxRootPresentationAttribute attribute = null)
{
base.SetWindowRootViewController(controller, attribute);
}
public override void Show(MvxViewModelRequest request)
{
var viewCreator = Mvx.Resolve<IMvxIosViewCreator>();
var controller = (UIViewController)viewCreator.CreateView(request);
Show((UIViewController)controller);
}
//public override void Show(IMvxIosView view) {
//}
public override void ChangePresentation(MvxPresentationHint hint) {
---
----
}
public override void Close(IMvxViewModel toClose) {
---
----
}
public void Show(UIViewController) {
//if (viewController is IFlyoutNavigationControllerCapable) {
//flyoutPresenter.Show(viewController, flyout);
//}
//else {
//currentWindow.RootViewController = viewController;
//navigationPresenter.Show(viewController, flyout);
//}
//Do your thing here.
}
public bool Close(FlyoutNavigationController flyout) {
---
----
}
}
Here, your point of interest are "show" method override thats gets called when load new ViewModel.
Here you have your rootviewController and new controller that you want to present, so I guess you can take it from here.

How to pass the data from modally presented ViewController to another ViewController in Xamarin.iOS?

I have to controller A and B.
From A I'm navigating to B in the B on button click I have open another ViewController using PresentModalViewController, which ask the user to enter some data. On the click of the submit button on that modally presented view I want to dismiss the modal and show the data on the B view that captured in modally presented view.
Here is what I have done:
I have InviteCollaboratorViewController from this I have modally presented AddNewCollaboratorDialogPopUpView and from there again I have modally presented another view named AddCollaboratorPopUpView.
AddCollaboratorPopUpView user will fill the details of and click on addCollaboratorButton, on this button click event I want to dismiss both the modally presented views, and want to reflects the changes in InviteCollaboratorViewController tableview.
InviteCollaboratorViewController
public partial class InviteCollaboratorViewController : UIViewController
{
public override void ViewDidLoad()
{
btnNewDialog.TouchUpInside += BtnNewDialog_TouchUpInside;
MyCollaboratorsTableView.Source = new MyCollaboratorsTableViewSource(this, _listOfMyCollaborators);
MyCollaboratorsTableView.RowHeight = UITableView.AutomaticDimension;
MyCollaboratorsTableView.ReloadData();
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
MyCollaboratorsTableView.ReloadData();
}
public void BtnNewDialog_TouchUpInside(object sender, EventArgs e)
{
AddNewCollaboratorDialogPopUpView addNewCollaboratorDialogPop = this.Storyboard.InstantiateViewController("AddNewCollaboratorDialogPopUpView") as AddNewCollaboratorDialogPopUpView;
if (addNewCollaboratorDialogPop != null)
{
addNewCollaboratorDialogPop.ModalPresentationStyle = UIModalPresentationStyle.OverCurrentContext;
addNewCollaboratorDialogPop.ModalTransitionStyle = UIModalTransitionStyle.CrossDissolve;
this.PresentViewController(addNewCollaboratorDialogPop, true, null);
}
}
}
AddNewCollaboratorDialogPopUpView
public partial class AddNewCollaboratorDialogPopUpView : UIViewController
{
public AddNewCollaboratorDialogPopUpView (IntPtr handle) : base (handle) { }
public override void ViewDidLoad()
{
base.ViewDidLoad();
SET_FONTS();
SET_UI_CONTROLS_STYLING();
createNewCollaboratorButton.TouchUpInside += CreateNewCollaboratorButton_TouchUpInside;
}
public void CreateNewCollaboratorButton_TouchUpInside(object sender, EventArgs e)
{
AddCollaboratorPopUpView addCollaboratorPopUp = this.Storyboard.InstantiateViewController("AddCollaboratorPopUpView") as AddCollaboratorPopUpView;
if (addCollaboratorPopUp != null)
{
addCollaboratorPopUp.ModalPresentationStyle = UIModalPresentationStyle.Popover;
addCollaboratorPopUp.ModalTransitionStyle = UIModalTransitionStyle.CrossDissolve;
this.PresentViewController(addCollaboratorPopUp, true, null);
}
}
}
AddCollaboratorPopUpView
public partial class AddCollaboratorPopUpView : UIViewController
{
public AddCollaboratorPopUpView (IntPtr handle) : base (handle) { }
public override void ViewDidLoad()
{
base.ViewDidLoad();
textFieldFirstName.ShouldEndEditing += TextFieldFirstName_ShouldEndEditing;
textFieldLastName.ShouldEndEditing += TextFieldLastName_ShouldEndEditing;
textFieldPhoneNumber.ShouldEndEditing += TextFieldPhoneNumber_ShouldEndEditing;
textFieldEmail.ShouldEndEditing += TextFieldEmail_ShouldEndEditing;
dismissPopupButton.TouchUpInside += DismissPopupButton_TouchUpInside;
addCollaboratorButton.TouchUpInside += AddCollaboratorButton_TouchUpInside;
}
public void DismissPopupButton_TouchUpInside(object sender, EventArgs e)
{
PresentingViewController?.PresentingViewController?.DismissModalViewController(false);
}
public void AddCollaboratorButton_TouchUpInside(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(textFieldFirstName.Text) && !string.IsNullOrEmpty(textFieldLastName.Text)
&& !string.IsNullOrEmpty(textFieldPhoneNumber.Text) && !string.IsNullOrEmpty(textFieldEmail.Text))
{
//Now from here what I want is to call the InviteCollaboratorViewController's ViewWillAppear() because that Refresh's the list of
//users which reflect the added user on list instantly as popup get dismissed.
collaborator.FirstName = textFieldFirstName.Text;
collaborator.LastName = textFieldLastName.Text;
collaborator.Email = textFieldEmail.Text;
collaborator.PhoneNumber = textFieldPhoneNumber.Text;
GlobalConstants.listOfMyCollaborators.Add(collaborator);
PresentingViewController.PresentingViewController.DismissModalViewController(false);
}
else
{
Toast.MakeToast("Please fill all required fields before submitting.").Show();
}
}
}
Try code below, I have made few modifications. It might help you
InviteCollaboratorViewController.cs
public override void ViewDidLoad()
{
btnNewDialog.TouchUpInside += BtnNewDialog_TouchUpInside;
_listOfMyCollaborators.Add(GlobalConstants.Collaborators);
GlobalConstants.Collaborators=null;
MyCollaboratorsTableView.Source = new MyCollaboratorsTableViewSource(this, _listOfMyCollaborators);
MyCollaboratorsTableView.RowHeight = UITableView.AutomaticDimension;
MyCollaboratorsTableView.ReloadData();
}
AddCollaboratorPopUpView.cs
public void AddCollaboratorButton_TouchUpInside(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(textFieldFirstName.Text) && !string.IsNullOrEmpty(textFieldLastName.Text)
&& !string.IsNullOrEmpty(textFieldPhoneNumber.Text) && !string.IsNullOrEmpty(textFieldEmail.Text))
{
var objCollab=new Collaborators();
objCollab.FirstName = textFieldFirstName.Text;
objCollab.LastName = textFieldLastName.Text;
objCollab.Email = textFieldEmail.Text;
objCollab.PhoneNumber = textFieldPhoneNumber.Text;
GlobalConstants.Collaborators=objCollab;
PresentingViewController.PresentingViewController.DismissModalViewController(false);
}
}
GlobalConstants.cs
Public class GlobalConstants
{
public static Collaborators myCollab {get;set;}
}

MvvmCross Navigating to TabViewController inside custom IosPresenter

I'm having trouble Navigating to a MvxTabBarViewController from my main view, and I think there's something I'm missing with my IosViewPresenter, which utilizes a single root view with a NavigationBar and pages in a ContentView.
public class ContainerPresenter : MvxIosViewPresenter
{
public static MvxNavigationController NavigationController = null;
public static UIView MenuView = null;
private UIView _containerView;
private MvxViewController _rootController;
public ContainerPresenter(IMvxApplicationDelegate applicationDelegate, UIWindow window)
: base(applicationDelegate, window)
{
}
public override void Show(MvxViewModelRequest request)
{
if (NavigationController == null)
{
// First controller called from main hamburger menu. Must have decorator: WrapInNavigationController = true
base.Show(request);
}
else
{
// Subsequent controllers called from main menu or other views
MvxViewController c = _rootController.CreateViewControllerFor(request) as MvxViewController;
string val = "";
if (request.PresentationValues != null)
{
request.PresentationValues.TryGetValue("NavigationMode", out val);
}
if (val.Equals("Push", StringComparison.Ordinal))
{
// Push new controller onto navigation stack
PushViewControllerIntoStack(NavigationController, c, true);
}
else
{
// Replace stack in existing navigation controller with new controller
UIViewController[] controllers = { c };
// SetViewControllers unloads all the navigation bar buttons
// Don't animate to avoid visible refresh when switching root menu items
NavigationController.SetViewControllers(controllers, false);
NavigationController.NavigationBar.TopItem.SetRightBarButtonItems(AlertItem.GetAlertItems(), false);
NavigationController.NavigationBar.TopItem.SetLeftBarButtonItem(HamburgerItem.Button, false);
}
}
}
protected override MvxNavigationController CreateNavigationController(UIViewController viewController)
{
// One NavigationController instance for all views
NavigationController = base.CreateNavigationController(viewController);
NavigationController.NavigationBarHidden = false;
//NavigationController.NavigationBar.TintColor = UIColor.FromRGB(15, 79, 140);
NavigationController.NavigationBar.BarTintColor = UIColor.FromRGB(33, 33, 33);
NavigationController.NavigationBar.Translucent = false;
NavigationController.NavigationBar.TopItem.SetLeftBarButtonItem(HamburgerItem.Button, false);
return NavigationController;
}
protected override void SetWindowRootViewController(UIViewController controller, MvxRootPresentationAttribute attribute = null)
{
if (_window.RootViewController == null)
{
// Insert MainView as root controller, subsequent root menu_item controllers will use MainView.ContainerView as root
base.SetWindowRootViewController(controller, attribute);
_rootController = controller as MvxViewController;
// Hack to get around: 'MainView.ContainerView' is inacessible due to its protection level
// _containerView = (_window.RootViewController as MainView).ContainerView;
_containerView = _window.RootViewController.View.ViewWithTag(1);
MenuView = _window.RootViewController.View.ViewWithTag(2);
}
else
{
// Move root menu_item controller to ContainerView
controller.View.Frame = _containerView.Bounds;
controller.WillMoveToParentViewController(_window.RootViewController);
_containerView.AddSubview(controller.View);
_window.RootViewController.AddChildViewController(controller);
controller.DidMoveToParentViewController(_window.RootViewController);
}
}
}
I'm following the tab example provided in the playground at https://github.com/MvvmCross/MvvmCross/tree/develop/Projects/Playground, my base tab view I'm calling looks like this
[MvxRootPresentation(WrapInNavigationController = true)]
public partial class ItemDetailBaseView : MvxTabBarViewController<ItemDetailBaseViewModel>
{
private bool _isPresentedFirstTime = true;
public ItemDetailBaseView(IntPtr handle) : base(handle)
{
Console.WriteLine("Loaded"); //<----Never called
}
public override void ViewDidLoad()
{
base.ViewDidLoad(); //<----Never called
// Perform any additional setup after loading the view, typically from a nib.
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
// Release any cached data, images, etc that aren't in use.
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated); //<----Never called
if (ViewModel != null && _isPresentedFirstTime)
{
_isPresentedFirstTime = false;
ViewModel.ShowInitialViewModelsCommand.ExecuteAsync(null);
}
}
While my tab views look like this
public class ItemDetailTabViewModel : MvxViewModel
{
private readonly IMvxNavigationService _navigationService;
public ItemDetailTabViewModel(IMvxNavigationService navigationService)
{
_navigationService = navigationService;
}
public override void ViewAppeared()
{
base.ViewAppeared();
}
public override async Task Initialize()
{
await Task.Delay(3000);
}
}
Nothing fancy so far, I navigate to it with
_navigationService.Navigate<ItemDetailBaseViewModel>(new MvxBundle(new Dictionary<string, string> { { "TabbedPage", "Push" } }));
I get "Navigate requested" but nothing else happens, no view change, not as much as a flicker. As I commented above, nothing in ItemDetailBaseView is called. According to the sample, ViewWillAppear should be called after navigation request, and then the command should populate, but I'm not getting anything. I've even tried catching the request in the Presenter, and making the controller the root view, to no success and I'm out of ideas.
Thank you

Resources