How do you cancel navigation in MvvmCross 6.x? - xamarin

I'm converting an MVVMCross 4.x app to MvvmCross 6.x.
Previously if I wanted to intercept the showing of a view model and cancel it then I would subclass the MvxViewPresenter and override the Task<bool> Show(MvxViewModelRequest request) method. I'm struggling to find the equivalant in MvvmCross 6.0
I've tried hooking in to the Mvx.IoCProvider.Resolve<IMvxNavigationService>().BeforeNavigate event but this gets called after the Prepare() and Initialize() view model methods.
How do I intercept the call before the ViewModel.Initialize() method is called and cancel the navigation?

Related

onTurnError is not called from TeamsActivityHandler.onInvokeActivity

i'm implementing a bot for microsoft teams using com.microsoft.bot:bot-integration-core version 4.14
i'm subclassing TeamsActivityHandler and overriding methods like onMessageActivity and onAdaptiveCardInvoke
i also use BotFrameworkAdapter to add some middleware and onTurnError handler.
when i have an action, triggered from a button click for example, and this action raises an exception, then onTurnError is not called, since an error is handled in TeamsActivityHandler (https://github.com/microsoft/botbuilder-java/blob/main/libraries/bot-builder/src/main/java/com/microsoft/bot/builder/teams/TeamsActivityHandler.java#L181)
in case on an error in onMessageActivity, the onTurnError is called fine.
if i subclass from a parent of TeamsActivityHandler, which is ActivityHandler then i assume error handling will work fine.
so my question is:
how is onTurnError is supposed to be used in case of subclassing TeamsActivityHandler ?

How to hide TimePicker and DatePicker on lifecycle events in Xamarin Forms

I'm running into an issue on android where our TimePicker and DatePicker stay visible when we navigate OnPause(). We need to redirect our users back to the login screen when they background the application, but if the TimePicker or DatePicker is active when they do this it stays on the screen. It appears above the login screen and pressing cancel or ok crashes the app.
We are hooking into the native android lifecycle events (not just using Xamarins built in hooks) and we redirect OnResume(). I've tested this in a barebones app though and it still happens OnPause().
Here is our TimePicker causing us the issue:
<TimePicker x:Name="VitalTimePicker" HorizontalOptions="Fill" VerticalOptions="Fill" IsVisible="false" PropertyChanged="OnTimePickerPropertyChanged"/>
And here is an example of changing screens on a lifecycle event:
protected override void OnSleep()
{
App.Current.MainPage = new NavigationPage(new NotesPage());
}
Any ideas? I was thinking of clearing the Pickers but I can't seem to find how to do that
Edit
Just to add a little more context
The Application class (app.xaml.cs) has lifecycle hooks that we use to catch when our users background the app. In here we call MainPage = new NavigationPage(new LoginPage()); which takes the app back to the login page.
I've added
protected override void OnDisappearing()
{
VitalTimePicker.Unfocus();
VitalDatePicker.Unfocus();
}
to the view i'm working from and it seems to be called when we background the application, but for some reason the TimePicker is staying on the screen when our login page pops up again.
You can programmatically close DatePickers and TimePickers using the method Unfocus(). I'd recommend closing them before you call the next page, as I don't know if they will be able to be referenced and closed after the other screen has been initialized.
Create a method that calls VitalTimePicker.Unfocus() and the same for any other picker you have, and call this method before changing to login screen and you should be good to go.

keyDown(with:) Not Called on Custom ViewController or View, Only WindowController

I have moved most of the core functionality of my non-document based macOS app to a custom, embedded framework.
The app code has a standard main storyboard with an initial window, and the window has a "window content" relationship/segue into a storyboard reference pointing to a storyboard inside the embedded framework. Therein lies a custom NSViewController subclass and a custom NSView subclass.
I want to group all the input event handling code inside the framework, which means implementing mouseDown(with:) on the custom NSView subclass, and --lo and behold-- it gets called when I click inside the app window. So far, so good.
Next, I implemented keyDown(with:) to similarly handle keyboard input. However, at runtime, it does not get called and instead, I hear the annoying beep (NSBeep).
I tried implementing keyDown(with:) on the view controller instead, but it's all the same.
Finally, I tried implementing the key handler on my NSWindowController subclass instead, and that does work.
So I could get around this by forwarding the event like so:
class WindowController: NSWindowController {
override func keyDown(with event: NSEvent) {
contentViewController?.view.keyDown(with: event)
}
}
, but it is very inelegant. I would prefer to not pollute the app code with input logic.
This doesn't seem to have anything to do with embedding frameworks, however. I put together a minimal project from the 'Cocoa App' template and confirmed that indeed keyDown(with:) only gets called if implemented on the window controller code, but not on the view or view controller side.
How can I get keyDown(with:) to be called on the view or view controller (not the window or window controller) in a storyboard-based app? (so I can move it from the main app to my embedded framework).
Edit: The question has been marked as duplicate. I tried the solutions pointed in answers to the other question (namely, override acceptsFirstResponder to return true). This solves the problem in my minimal demo project, but when I tried it on my full app, it still does not work (I did see that question and did try to override acceptsFirstResponder in my app before posting this question).
I will now try to modify my minimal poeject to see if I can reporduce the issue in the main app.
Edit 2: I have refactored the minimal project to:
Send the view controller to a separate storyboard,
Send the view controller's storyboard and represented classes (custom view, custom view controller) to a separate, embedded framework.
Now the basic setup mirrors that of my app in all that seems to matter, but still can not reproduce the issue in the minimal project. I will investiate further...
Edit 3: I haven't been able to reproduce the issue on the minimal project.
On my app's custom view, I implemented:
public override var acceptsFirstResponder: Bool {
return true
}
public override func performKeyEquivalent(with event: NSEvent) -> Bool {
let retVal = super.performKeyEquivalent(with: event)
return retVal
}
On startup, acceptsFirstResponder is called twice.
When hitting any key, performKeyEquivalent(with:) is called twice, too. Inspectig the intermediate variable retVal above reveals that the super class's implementation always returns false. After returning from this method, NSBeep() is called and keyDown(with:) isn't.
If instead of super.performKeyEquivalent(with:) I force-return true, I can avert the call to NSBeep() (but keyDown(with:) is still not called...)
Edit 4 (Final):
Out of desperation, I cleared the "Custom Class" field of the window controller's Identity Inspector in my app's main storyboard (to the default NSWindowController).
Suddenly, my custom view's keyDown(with:) starts getting called.
I reinstated the custom class to confirm.
It still works.
I clean the build folder and try again.
It still works.
Now I can no longer reproduce the issue even on my main app. I really don't know what to say...

Xamarin.Forms How to switch pages using MVVMLight

I'm currently working on a Xamarin.forms project using .NET Standard as code sharing strategy. I try to use the MVVM pattern by using the MvvmLightLibsStd10 library. I already successfully setup the MVVM structure by using this tutorial:
https://www.linkedin.com/pulse/build-xamarinforms-net-standard-mvvm-light-app-rafael-carvalho
I can't use Navigation.PushAsync(new Page()); because it only works in code behind and not in the ViewModel.
I already tried to Pass Navigation trough the VM constructor, like describe over here:
Xamarin.form Page Navigation in mvvm
But when I try this method, an error occurred at "LoadApplication(new DemoMVVM2.App());" in MainPage.
How can I switch pages using MVVM Xamarin.Forms with MVVMLight (based on the code from my first url)?
but I have no Idea how I can switch Pages via the ViewModel and keeping the header with back button.
Generally when working with MVVMLight you'll be using a NavigationService.
This class can be constructor injected in your VM, thanks to the build in IOC in MVVMLight.
With it you can do Navigate and GoBack in your VM, triggering a real navigation on the current stack.
Only thing that you maybe missed, is the fact that you need to write one yourself for Xamarin forms.
But Laurent Bugnion ( the owner of MVVMLight ) supplied an example available here:
https://github.com/lbugnion/sample-2016-vslive-crossplatform/blob/master/Flowers/Flowers.Forms/Flowers.Forms/Helpers/NavigationService.cs
You can pass a callback to your ViewModel(VM) and on Command or whatever action call your navigation code which is in your page (View). this way you can keep your navigation code in your page and your binding logic in your ViewModel.
interface NavHandler{
void navigateToSomeView();
}
public class MyPage : ContentPage,NavHandler{
public MyPage(){
BindingContext = new MyViewModel(this);
}
void navigateToSomeView(){
Navigation.PushAsync(new Page2());
}
}
public class MyViewModel{
NavHandler handler;
public MyViewModel(NavHandler handler){
this.handler = handler
}
//Your action
this.btnClicked = new Command(async()=>{
handler.navigateToSomeView()
}
}

External Object for Android with callback Event

I'm building an External Object for Android.
I have an asynchronous method and I guess I must to use an Event into the External Object to receive it's callback in Genexus.
But, can anyone show me how to trigger this event in GX from the android java class?
This method:
mCoordinator.runAction("yourEvent", null);
And the mCoordinator you can get it at the constructor:
public YourUC(Context context, Coordinator coordinator, LayoutItemDefinition definition){
}

Resources