How to manage views programmatically in an iPad storyboard application using Monotouch - xamarin.ios

I have created an iPad storyboard application using the newest version of Monotouch. My first screen is a login screen that I only want to show if the user has not saved his credentials. If credentials are available I want to instead navigate to the UITabBarController that is the second scene. I can't seem to find any documentation on how to do this. I tried creating an instance of the UITabBarController and pushing to it but it does not work.
homeScreen = new HomeTabBarNavigator(this.Handle);
this.NavigationController.PushViewController(homeScreen,true);
HomeTabBarNavigator is a UITabBarController that is already linked to other scenes. I get the following error:
[ERROR] FATAL UNHANDLED EXCEPTION: System.NullReferenceException: Object reference not set to an instance of an object
I assume I am getting this error because I have not defined any views to the ViewControllers property of my HomeTabBarNavigator. I was hoping that those views were already defined but that does not seem to be the case. Any ideas.

The best solution I could find is to call PerformSegue on the controller. Here is some example code:
this.PerformSegue("LoginSegue",this);
The controller that is loaded is the LoginController, and LoginSegue is a Segue that points to the HomeTabBarNavigator. While it is not perfect, the applications loaded the tabbar properly.
I used this stackoverlflow iOS question as the basis for my solution.

Related

Blazor Component (in library) and JSInterop

I've created a Blazor Component within a full Blazor project and all works well.
However, when I move this component to it's own Razor Class Library project, I am now getting an error that I cannot use JSInterop until a connection with the server is made. I am running my code in the OnAfterRenderAsync() method.
I had to alter the code a little when I made the change.
In a full Blazor project, JSInterop is provided for you with DI in the Startup class. But this is not the case with a calss library.
So instead of "#inject JSInterop js" in the page, I had to set it up like this -
private IJSRuntime js { get; set; }
protected override void OnInitialized()
{
js = ScopedServices.GetRequiredService<IJSRuntime>();
}
From the sketchy details available on the web, I'm assuming this gets the service from the Parent project.
Using debugging, I can see that js is NOT null. It does seem to have been set to a valid object.
Can anyone point me in the right direction?
The server pre-renders, so your code will run before there is a client connection to the server. When rendering in OnAfterRenderAsync you should only use IJSRuntime when the firstRender parameter is true, or any point after that, but never before.
Found the solution to my problem and it has rendered my initial question irrelevant.
When I copied my component to it's own class library project, it would not compile. It gave me an error on the line #inject JSInterop js.
This led me to believe that it didn't know how to inject this as it is not set during the Startup of the project, as it is in a Blazor app.
So I cobbled together the code to get a reference via ScopedServices.GetRequiredService().
This did create an object but did not have _clientProxy set which contains the connection to the server.
So digging round I managed to find a complete component library example project at BlazorHelp Website
This did have the JSInterop injected in the Blazor file. So I reverted my code back to the original code that worked in the full project and tried to compile. It gave me the same error. So I deleted the #inject JSInterop js line and typed it in again.
IT RECOGNIZED IT!!!
It still failed to compile, not recognizing a custom type (Pivot) and asking whether I had included a reference to it.
[CascadingParameter] public Pivot OwnerPivot { get; set; }
I deleted the word Pivot and retyped it and, voila, it compiled.
So it looks like there some sort of error in VS2019 or the razor compiler, where deleting code in the source file and re-entering caused it to recognize and compile.

Xamarin iOS HockeyApp best practice setup?

I'm attempting to get HockeyApp to work in my iOS Xamarin Forms app. I installed the iOS HockeyApp component (v4.1.0), and the getting started information for shows the following:
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
var manager = BITHockeyManager.SharedHockeyManager;
manager.Configure("Your_App_Id");
manager.StartManager();
}
When I try this, BITHockeyManager.SharedHockeyManager is null.
I've tried to wrap these lines in HockeyApp.Setup.EnableCustomCrashReporting() and Setup.EnableCustomCrashReporting() as is referenced in this post, but Setup doesn't exist in the namespaces I have.
What am I missing to properly enable HockeyApp in iOS?
Whoo hoo! Figured it out finally! I had the linker options set to link 'All assemblies' because of a suggestion from the New type registrar in Xamarin.iOS 7.2.1, errors MT5210 and MT5211 thread. I was seeing the 'Native linking failed...' error and switching to 'All assemblies' initially fixed it.
Switching to 'Link SDK assemblies only' fixed both problems

Hosting and initialising multiple MVVMCross ViewModels for the MvxTabViewController

I need to create a Tab view in iOS. I tried to do this by simply adding a UITabBar to an MvxViewController but I could not get that to work (See this question if interested)
I am now trying to go use the approach MVVMCross and Apple seem to push me towards, a TabController.
In our Core project we have 4 ViewModels that are displayed from one or more places using a ShowViewModel call and are initialised with a customerNumber.
CustomerViewModel
CustomerOrdersViewModel
CustomerHistoryViewModel
ReturnsViewModel
In Android and Windows Store we have separate Views for each of these ViewModels. I do not want to change our Core implementation to support iOS. I will create a new ViewModel called TabbedCustomerViewModel and that will have 4 properties, one for each of the hosted ViewModels.
Using a custom MvxTouchViewPresenter registered in the iOS project I can listen for requests to Show one of the Customer views and then switch the Request to TabbedCustomerViewModel. I have that working, the new ViewModel gets created and the initialisation paramaters that would have been passed to the original VM are passed to the intercepting VM's Init method.
The problem I am having is knowing how I should be initialising the hosted VMs. I assume I am going to have to ctor, init and Start them manually. Has anyone got any thoughts on how to do this?
The N-25 Tab Tutorial does not have to worry about this as its hosted VMs are not standalone so don't have Init and Start dependencies
I have the initialisation of the VMs working now too. When the View loads it checks if it is within a Tabbed UI by looking at the ParentViewController.
If it is it calls a custom method on the new TabbedCustomerViewModel. I have copied the code that MVVMCross use and added it to the new Method
try
{
mvxViewModel.CallBundleMethods("Init", this.initialisationParameters);
if (reloadedState != null)
{
mvxViewModel.CallBundleMethods("ReloadState", reloadedState);
}
mvxViewModel.Start();
}
catch (Exception exception)
{
throw exception.MvxWrap("Problem initialising viewModel of type {0}", mvxViewModel.GetType().Name);
}
The initialisationParameters and reloadedState are stored by TabbedCustomerViewModel when it is initialised so that it can pass it down to the ViewModels it is hosting

An exception of type 'Microsoft.VisualStudio.TestTools.UITest.Extension.FailedToPerformActionOnHiddenControlException'

Im getting the following error when I run the coded UI application:
An exception of type 'Microsoft.VisualStudio.TestTools.UITest.Extension.FailedToPerformActionOnHiddenControlException' occurred in Microsoft.VisualStudio.TestTools.UITesting.dll but was not handled in user code
This exception arises in the Mouse.Click() function in the below code.
public static void DestinationMaster()
{
Mouse.Hover(PPI.PPIHome.PPI_Main.PPI_Window.MastersPane);
Mouse.Click(PPI.PPIHome.PPI_Main.PPI_Window.DestinationMasterPane.DestinationMasterHyperlink);
}
The application doesnt run after this exception.I am using IE 8 as my browser to run the application.But when I run the application ,IE mode is changed automatically to compatibility mode.Is this related to the exception?
Is there a way to resolve this issue and get my application to running.Thanks in advance.
Does the hover work? Can you hover over the link instead to make sure that works? What happens when you find the control from the UIMap?
What does PPI.PPIHome.PPI_Main.PPI_Window.DestinationMasterPane.DestinationMasterHyperlink.TryGetClickablePoint() return?
Does the UI need to scroll to see the link? If so you could use PPI.PPIHome.PPI_Main.PPI_Window.DestinationMasterPane.DestinationMasterHyperlink.EnsureClickable() to scroll to the control.
Try to use WaitForControlReady() to make sure the page is fully loaded before coded ui acts on it. Sometimes coded ui can move faster than the application under test.
Make sure you have the latest update for VS2012

Delegate pointer issues since upgrading to ARC

I've just upgraded my application to ARC, but I am having issues with how it handles classes with delegates. Because I am targeting iOS 4.0 and above, I am using __unsafe_unretained and #property (unsafe_unretained) to store the delegate pointers.
However, what I am now finding is that the services (that include delegates) I create in my view controllers are now hanging around after I have removed that view controller, which result in trying to communicate back with the view controller (delegate) after it has been deallocated... And therefore getting an error with Zombies enabled.
How can I update my code in either the view controller or the service, so that when the view controller is removed (popped off the nav controller stack) the service with the delegate pointer also gets removed from memory?
It turns out that it's not me that's doing anything wrong...
The offending NSZombie turned out to be due to the MKMapViewDelegate, which keeps sending 'mapView:didUpdateUserLocation:' after the View Controller it belongs to gets deallocated. I know.
I resolved it by intercepting the Back button in my View Controller, and set the delegate to nil before popping it:
- (void)backButtonTapped
{
self.mapView.delegate = nil;
[self.navigationController popViewControllerAnimated:YES];
}
I don't know why MapKit holds onto a delegate after it has been dealloc'd. If anyone knows I'd be grateful to find out more.

Resources