Xamarin Forms IEventAggregator in iOS class crash the application - xamarin.forms

I'm using Xamarin.Forms and Prism 6.3.0
I have a class in the iOS project where I want to use the IEventAggregator. When I'm passing the IEventAggregator as a parameter to the constructor of the class, the application crashes.
A clarification, I'm trying to publish from the iOS class, not to subscribe to an event published by Xamarin.Forms.
How can I use the IEventAggregator inside a class in iOS project of Xamarin.Forms?

I don't know if there is a more elegant solution, but there is one that is working. You'll have to add the dependency to your container manually with the correct injection parameters.
In your platform specific project (iOS in this case, but it holds for Android, too) change the following line
this.LoadApplication(new App());
to
var app = new App();
this.LoadApplication();
Given your App is a PrismApplication you can now access the IUnityContainer and register your type manually
var app = new App();
app.Container.RegisterType(typeof(IServiceService),
typeof(MyServiceService),
string.Empty,
new ContainerControlledLifetimeManager(),
new InjectionConstructor(new ResolvedParameter(typeof(IEventAggregator))));
this.LoadApplication(app);
Now Unity should be able to resolve MyServiceService correctly and your app should not crash anymore. Maybe you have to remove
[assembly: Xamarin.Forms.Dependency(typeof(MyServiceService)]
but I have not tried if it crashed if it's not removed.

The answer to the question is here
In short, in the class in the iOS project add the using statement using Microsoft.Practices.Unity; and in the constractor of the class add
var ea = ((App)Xamarin.Forms.Application.Current).Container.Resolve<IEventAggregator>();
in order to get the EventAggregator.
Then you can use it to publish a message i.e.
ea.GetEvent<SomeEvent>().Publish(somePayload);

Related

Can't get Prism 8 with DryIoc RegisterServices and Platform-Specific support to work

Trying to use Prism 8, ContainerLocator, IHttpClientFactory and Platform-Specific Service registration with DryIoc Extensions (not Magician) in a Xamarin Forms application
I have these nuget packages installed
Prism.DryIoc.Extensions
Prism.Forms
My main Xamarin Application inherits from PrismApplicationBase.
In platform code (eg Android) I have IPlatformInitializer implented by MainActivity and for platform-specific services I use:
LoadApplication(new App(this));
as documented here:
https://prismlibrary.com/docs/dependency-injection/platform-specific-services.html
This line causes the IContainerExtension to be resolved in the shared code
protected override IContainerExtension CreateContainerExtension()
...but I can't find a way to successfully return a valid IContainerExtension implementation.
I've attempted:
https://prismlibrary.com/docs/dependency-injection/container-locator.html
var createContainerExtension = () => new DryIocContainerExtension();
ContainerLocator.SetContainerExtension(createContainerExtension);
But the code given here can't even compile - the DryIocContainerExtension class created is defined INTERNAL and isn't available to my application code.
If I use...
PrismContainerExtension.Init();
or
return ContainerLocator.Current;
...as worked previously (eg Prism 7.2) I get a runtime error as described here:
https://githubmemory.com/repo/dansiegel/Prism.Container.Extensions/issues/180
ValueFactory attempted to access the Value property of this instance.
Please can someone advise what I'm doing wrong, or do I have to get my company to pay for Magician to resolve my issue?

Xamarin.Forms for iOS using SceneDelegate.cs

In iOS 13, UIScene is used. Codes in AppDelegate.cs must be moved into SceneDelegate.cs to support multiple windows of the same app in Split View.
For Xamarin.Forms, AppDelegate.cs uses LoadApplication (new App()) to launch an instance of App.cs in the Xamarin.Forms. LoadApplication is found in Xamarin.Forms.Platform.iOS.FormsApplicationDelegate.
What is the equivalent in SceneDelegate.cs to launch an instance of App.cs in the Xamarin.Forms?
From the app lifecycle of xamrin forms :
iOS – Main method > AppDelegate > App > ContentPage .
Android – MainActivity > App > ContentPage
We will see that Main method invoke App class before , if need a instance of App from iOS , generally will try as follow :
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App(app)); // pass app to Forms
return base.FinishedLaunching(app, options);
}
However ,Forms can not using UIKit (error screenshot).
In xamarin forms , there is DependencyService to load navtive method . Therefore, suggest that using DependecyService to call app from iOS native AppDelegate.cs .
About using SceneDelegate.cs in Xamarin Forms , there is no SceneDelegate.cs file in iOS solution now . I will check that whether be possible in Xamarin Forms .
==================================Update==============================
If want to deal with a universal link in AppDelegate.cs , you need to do something in continueUserActivity method as follow :
public override bool ContinueUserActivity(UIApplication application, NSUserActivity userActivity, UIApplicationRestorationHandler completionHandler)
{
//return base.ContinueUserActivity(application, userActivity, completionHandler);
if(userActivity.ActivityType == NSUserActivityType.BrowsingWeb)
{
NSUrl url = userActivity.WebPageUrl;
// other code
}
return true;
}
==================================Update===============================
Finally , found that it is possible to add SceneDelegate to a Xamarin Forms project. A new Xamarin Forms project does not come with the necessary SceneDelegate.cs or .storyboard files, so these need to be added. After adding these files, the info.plist needs to be updated with the UIApplicationSceneManifest key, which will contain more needed keys.
The additions to info.plist are shown here: https://learn.microsoft.com/en-us/xamarin/ios/platform/ios13/multi-window-ipad#project-configuration (just UIApplicationSceneManifest and everything under)
The two things to note are that:
The sample has issues with navigation working properly when having multiple windows of the app running.
This is not an official sample, as Xamarin.Forms does not currently offer official support for using mutiple Scenes with an iOS application.
The unofficial Xamarin.Forms sample is here:https://www.dropbox.com/s/sdxq5me7vcdmuf9/XamFormsiOSMultiWindow.rar?dl=0
It seems this issue has been resolved in MAUI. Just inherit from MauiUISceneDelegate for your SceneDelegate class and the framework will take car of the rest:
[Register("SceneDelegate")]
public class SceneDelegate : MauiUISceneDelegate
{
}
And then in your info.plist file:
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>__MAUI_DEFAULT_SCENE_CONFIGURATION__</string>
<key>UISceneDelegateClassName</key>
<string>SceneDelegate</string>
</dict>
</array>
</dict>
</dict>
I wish there was an equally clean solution for Xamarin.Forms as we have not migrated our app to MAUI yet.
Hope this helps!
*Update:
Junior Jiang's solution did work for me, but I had to make a few changes to get it to work:
Uncomment the following lines in SceneDelegate.cs:
//var ad = new AppDelegate();
//ad.GetUI();
...
//Window.RootViewController = ad.Window.RootViewController;
Then add the following line after the uncommented code in SceneDelegate.cs
Window.MakeKeyAndVisible();
I made a few additional changes that are not specifically required, but probably a bit better in terms of resource usage, such as rather resolving appDeleggate as follows:
var appDelegate = (AppDelegate)UIApplication.SharedApplication.Delegate;
And instead returning the created Xamarin.Forms app in GetUI method (in AppDelegate) to be used in SceneDelegate, instead of creating another one in SceneDelegate.
One limitation that I did notice is that I could no longer see iOS alert messages, so I used a custom syncfusion popup instead.

What's the proper way of setting up MvvmCross 6.0 Xamarin.Forms UWP application code?

I have my UWP Application inherited from Base class, which inherits from MvxApplication<Setup, CoreApp>:
public sealed partial class App : WindowsApplication
{
public App()
{
InitializeComponent();
}
}
public class WindowsApplication : MvxApplication<Setup, CoreApp>
{
}
public class Setup : MvxWindowsSetup<CoreApp>
{
public override IEnumerable<Assembly> GetViewAssemblies()
{
// need to do this as otherwise I receive the message that corresponding view to view model is not found
var assemblies = base.GetViewAssemblies().ToList();
assemblies.Add(typeof(Forms.App).Assembly);
return assemblies;
}
}
However, when launching it, receiving the following error message:
The type MvxContentPagePresentationAttribute is not configured in the
presenter dictionary
As I understand, all that is not proper way to launch Xamarin.Forms MvvmCross application, as UWP App and Setup should be inherited from something like MvxFormsApplication and MvxFormsWindowsSetup<CoreApp, Forms.App> respectively (to have Xamarin.Forms app properly initialized).
But:
MvxFormsApplication is not generic and doesn't provide ability of passing Forms-generic setup.
even if I inherit the App from MvxFormsApplication and use this.RegisterSetupType<MvxFormsWindowsSetupInheritor>();, Visual Studio compiler never allows me to compile the project because of some weird error message (something like The name “WindowsApplication” does not exist in the namespace “…”) (this might be some issue of Visual Studio, but I have VS 15.7 version, which expects the code to work (again, MvvmCross declares they support UWP and XF)).
So, from my understanding, if there is Xamarin.Forms app, there must be also some way of passing actually Xamarin.Forms App class to the UWP App class initialization.
MvvmCross, again, stands for UWP and Xamarin.Forms support, but I can't see any clear example of the way to setup such type of application.
MvvmCross documentation as always is quite "modest". There are some instructions about setting up MvvmCross UWP app as well as setting up MvvmCross XF iOS/Android, but the only word about MvvmCross XF UWP is:
You are now free to place your custom renderers in a different
assembly. All you have to do to make it work is to add your assembly
to the Setup.ViewAssemblies collection.
(in official website docs)
(which is still sounds weird, as iOS and Android versions don't need that additional code, which makes me think that such (current) documentation isn't quite actualized)
and
UWP, WPF
Extend App from MvxApplication. ( App : MvxApplication { } )
from MvvmCross.Forms package readme.txt file, when all other platforms, again, expect inheritance for the app classes from MvxForms*-based ones.
MvvmCross guys, any thoughts on that?
When I set up a new Xamarin.Forms project, I always follow the Playground sample in the MvvmCross GitHub as this example evolves along with the API and is always up-to-date, as it is part of the MvvmCross solution, so any commits need to preserve its functionality. So if you want to see how everything should look in a minimal UWP + Xamarin.Forms project see the Playground.Forms.UI and Playground.Forms.Uwp projects in the linked folder.

Xamarin Forms Prism Can't access PCL classes from android project

I'm using Xamarin Forms Prism and I can't use my PCL classes in android project.
common example :
here is the Interface in PCL
namespace BlankApp.Helpers
{
public interface IToast
{
void MakeLongToast(string msg);
}
}
and here is the class in android project
namespace BlankApp2.Droid.DependencyService
{
public class ToastImp : IToast
{
}
}
it can not find IToast Interface reference !
there is a suggest from IDE with this msg : "Reference 'projectname-WebAppMAinModule' and use 'projectname.Helpers.IToast' "
screenshot
which does nothing actually !
I don't have these kind of problems in XamarinForms I face theme while using Prism . Do I forget something in referencing my PCL ?
I'm using
Prism.Forms (7.0.0.396)
Xamarin.Forms (2.5.0.122203)
also there are my project dependencies
here
You should be able to implement PCL interfaces and use its classes, etc. in your platform specific code (Android included).
Use the following steps:
Make sure your Android project is referencing your PCL.
Delete your Android obj & bin folders.
Recompile your PCL
After recompiling your PCL, recompile your Android project
See if it recognizes your interface now.
If the above doesn't work, then as one last option is:
Close the solution
Re-open the solution
Both of these typically work when your project won't recognize a newly created Interface.

MvvmCross - how do I access SQLite in a windows store background task?

I have a store app that uses the mvvmcross sqlite plugin (community edition). This app has a periodic background task that accesses the database to get data to be shown in a live tile. I can't see how I can get access to this database from the background task. I would like to use the mvvmcross sqlite plugin in the background task, but I don't see how to initialize the mvvmcross environment properly.
If you want to initialize the full MvvmCross framework including all of your app, then you'll need to run your Setup class.
In WinRT, this could be as simple as calling:
var setup = new Setup(null /*rootFrame*/);
setup.Initialize();
although it may require you to do a little work to:
Make sure your presenter does not use the null rootFrame
Provide some other means to create a UI thread dispatcher - currently MvxStoreViewDispatcher relies on .Dispatcher access - see https://github.com/MvvmCross/MvvmCross/blob/v3.1/Cirrious/Cirrious.MvvmCross.WindowsStore/Views/MvxStoreViewDispatcher.cs - to do this, you could override InitializeViewDispatcher with something like:
protected override void InitializeViewDispatcher()
{
if (_rootFrame != null)
{
base.InitializeViewDispatcher(); return;
}
var dispatcher = new NonMainThreadDispatcher();
Mvx.RegisterSingleton<IMvxMainThreadDispatcher>(dispatcher);
}
public class NonMainThreadDispatcher : MvxMainThreadDispatcher
{
public bool RequestMainThreadAction(Action action)
{
action();
}
}
If you want to initialize less functionality than the entire framework (e.g. for memory reasons) then you can also consider creating special Setup and App classes just for your background task.
Aside> This is similar to questions like these in Android - Using MvvmCross from content providers and activities and MvvmCross initialization
I was able to solve the problem in a straightforward way. Since the background task only needed the SQLite data service from the PCL core project, I did the following:
Included a reference to the Core project.
Added the nuget packages for MvvmCross and the SQLite community plugin.
Deleted all of the files and folders added when doing the mvvmcross install: Bootstrap/, Todo-Mvvmcross/, Views/, DebugTrace.cs, and Setup.cs.
There is a current limitation in the nuget installer that requires some additional edits to the project file to handle multiple store platforms (x86, ARM, and x64), see 'Cirrius.Mvvmcross.Community.Plugins.SQLite.WindowsStore needs platform-specific dlls for X86 and ARM' on Stack Overflow for details. Make sure you put the Choose statement after the default SQLite.WindowsStore reference and you need to leave the default reference in the project file. You will also need to adjust the HintPath based on the location/names of your references.
Initialized the SQLite data service by explicitly calling the factory and creating a new instance of the data service:
var factory = new MvxStoreSQLiteConnectionFactory();
IMyDataService repository = new MyDataService(factory);
I then have access to the data service with no other overhead associated with mvvmcross.

Resources