Is there a simple way to auto register [Exports] in a Prism app? WPF .NET 4.8 - prism

I used to be on a project that used Prism and when we needed a new service to do something, we'd just create an interface, a concrete class that implemented that interface and exported it, and then it just became available everywhere for [ImportingConstructor]. We didn't need to manually register it or anything. I no longer have access to that project, but I don't think there was any reflection magic that was done manually to accomplish this.
I'm in a new company and we are starting up a project using MEF / Prism and I'm trying to accomplish the same thing, but as of right now, I'm having to manually register items in order to import them. What am I missing?
I'm in .NET 4.8 WPF app
Additional info
we are basing our project from this website
https://prismlibrary.com/index.html
This is our app class
public partial class App
{
protected override Window CreateShell()
{
return Container.Resolve<ShellWindow>();
}
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<IStartupActionService, StartupActionService>();
containerRegistry.RegisterSingleton<IGeneralNavigationService, GeneralNavigationService>();
containerRegistry.RegisterSingleton<IExperimentSetupNavigationService, ExperimentSetupNavigationService>();
containerRegistry.RegisterSingleton<IProtocolSetupNavigationService, ProtocolSetupNavigationService>();
containerRegistry.RegisterSingleton<IOurProjectNavigationService, OurProjectNavigationService>();
containerRegistry.RegisterSingleton<IOurProjectUiService, OurProjectUiService>();
containerRegistry.RegisterManySingleton<WcfClientService>();
containerRegistry.RegisterSingleton<IControlClientService, ControlClientService>();
}
}
Why do I have to register each new service?
I've been reading about MEF, DryIoc, and others and I'm just not getting clear answers. Is there not a way to just have everything with an [Export] become immediately available for import?
Something else I need to do, that I think this whole registering thing is messing me up on is trying to come up with a way to have "dialogs" but tie them to a neutral class to make it more MVVM happy.
Dialog -> a region that pops open when you call a method. This method currently takes in a UserControl, assumed to have already been constructed and its ViewModel datacontext already attached.
What I would like to do and don't know how to start is
use a neutral container class to open one of these dialogs (similar to interaction request Notification
using attributes, attach an attribute to a view that indicates "I support this neutral container class" (assumed only one view per container)
this view supports [ImportingConstuctor] to bring in its ViewModel
the viewmodel itself supports [ImportingConstuctor] to bring in services needed
again, the desire to NOT need to register these items manually as we add them. Would like to add a service interface, the concrete class that [Export]s the interface and have it just available to the viewmodel and other services, and same for the views and viewmodels, export attribute tag them as necessary and have them just available to either/both grab an instance of them or manually create an instance of them and have their [ImportingConstructors] handled for me.

Related

Accessing properties from different class MAUI Android application

Testing the MAUI app dev by creating a simple Android application.
I've defined an collection and UI elements in MainPage.xaml/cs.
public ObservableCollection<Person> persons = new();
Also defined an broadcast Intent receiver.
internal class TestReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
// handle intent
}
}
I want to access persons collection defined in MainPage and add items to it. There is so many pages defined what is what. App.xaml/Mainpage.xaml/MainActivity/AppShell. I'm a bit lost.
Why broadcast receivers?
I suggest a different approach of your problem.
Make a class. Lets call it PersonService. Put the collection there, add method to add/remove persons. Inject it as singleton, and use it across your app.
Tomorrow when you decide not to use some static list, but database (or web-api), all you have to do is edit it at one place.
Another alternative.
Use messaging. CommunityToolkit.MAUI/MVVM have messaging system.
When you decide to go from Android to IOS? It will be much easier.
If you still want to do Android Broadcasts, please go ahead. But google search some of my alternatives. It saves me a lot of work every day, and works stable.

Prism IDisposable Autofac and Lifetime Scope

I am using Prism to navigate between views in my WPF application. One view in particular I've implemented with the IRegionMemberLifetime.KeepAlive => returns false; to create a new instance of the view every time we navigate to the view (we need to do this for display reasons). This view also hosts a custom win32 control that I need to do some cleanup in using IDisposable.Dispose. When I navigate to my view and then away from it, I'd expect Dispose to get called (to run cleanup). I was able to achieve this by implementing a custom region behavior as discussed here, https://github.com/PrismLibrary/Prism/issues/7. All this is working fine except everything gets marked for disposal but the GC doesn't actually get rid of anything. I'm using Autofac as my IOC container and after doing some research I've concluded the reason comes down to Autofac and lifetime scopes of IDisposables, https://nblumhardt.com/2011/01/an-autofac-lifetime-primer/. Basically Autofac holds references to the IDisposable and the GC won't get rid of the old view because of this. For instance I'm registering my view in the Module as _container.RegisterTypeForNavigation(); I'm not able to register this with any sort of lifetime and I'm not sure how I'd resolve this with a lifetime specified? When I call RegionManager.RequestNavigate I don't see any sort of overloads to specify lifetime? Any ideas would be appreciated.
RegisterTypeForNavigation essentially does builder.RegisterType(type).Named<object>(name); which you can do yourself, too, of course and apply any lifetime you desire. There's no magic in registering for navigation, RegisterTypeForNavigation is just a shorthand.
To make Autofac ignore the IDisposables, one can write
builder.RegisterType<SomeView>().Named<object>(typeof(SomeView).Name).ExternallyOwned();
From the docs:
Disabling Disposal
Components are owned by the container by default and will be disposed by it when appropriate. To disable this, register a component as having external ownership:
builder.RegisterType<SomeComponent>().ExternallyOwned();
The container will never call Dispose() on an object registered with external ownership. It is up to you to dispose of components registered in this fashion.
So extending #Haukinger answer. This is what finally worked for me:
//builder.RegisterTypeForNavigation<SomeView>();
builder.RegisterType<SomeView>().Named<object>
(typeof(SomeView).Name).ExternallyOwned();
That ExternallyOwned() signals to autofac that the user is going to handle calling dispose and that autofac shouldn't track the IDisposable.

How to get Current Page/View or topmost Page/View in Xamarin.Forms

I want to show AlertDialog(DisplayAlert) in a Xamarin.Forms project when an unhandled error occurs.
How can I get the current page instance?
You need to keep a reference of your main page as you mentioned. There are a few ways to do this.
You can have a static reference to it in your App.cs file, which is actually already there as it inherits from Application which has:
App.Current.MainPage
If you use an MVVM helper like MVVMLight you pass the page to the service so it keeps a reference of it.
ACR UserDialogs is a dialog package that can also help as it extends and adds different types of dialogs
To get around this and have a lot more flexibility add 'ACR User Dialogs' package to each of your platform's projects.
Then you can use that from anywhere :
await UserDialogs.Instance.AlertAsync ("Your question has been successfully sent", "Thankyou");

Xamarin XLabs IOC and camera

I'm looking at https://github.com/XLabs/Xamarin-Forms-Labs/blob/master/Samples/XLabs.Sample/ViewModel/CameraViewModel.cs to try and get the camera available to my app.
I have this setup the same, but when I run my app the iOS app that calls my PCL is giving the error:
IResolver has not been set. Please set it by calling Resolver.SetResolver(resolver) method.
I don't know what this means or what exact code I need. I don't use IOC at all and I don't much care about it but I just want this camera to be available to my PCL. How can I get this camera available to my PCL when I'm not using MVC here.
If you wish to use the ViewModel then modify the constructor to take in IMediaPicker:
https://github.com/XLabs/Xamarin-Forms-Labs/blob/master/Samples/XLabs.Sample/ViewModel/CameraViewModel.cs#L62
public CameraViewModel(IMediaPicker mediaPicker)
{
this._mediaPicker = mediaPicker;
}
Remove the Setup function:
https://github.com/XLabs/Xamarin-Forms-Labs/blob/master/Samples/XLabs.Sample/ViewModel/CameraViewModel.cs#L156-L167
How you get the IMediaPicker implementation to PCL is up to you. IoC is the preferred (and easy) way but you can use other patterns as well. One would be to define a static Func<IMediaPicker> property on the ViewModel and set it in the platform specific projects.
IoC container is the easiest and quickest way to get it done and it would as simple as adding these lines at the application startup (e.g. AppDelegate's FinishedLaunching method):
var container = new SimpleContainer();
container.Register<IMediaPicker, MediaPicker>();
Resolver.SetResolver(container.GetResolver());

Using Prism, how do I register my user control inside the unity boot strapper?

I am using Prism (Composite Application Framework) to build an application. I have my shell created and it has three regions( Main, menu, switchboard). I would like to load my switchboard region in the shell with a switchboard user control but in this case, I don't want to load it through a module.
So, how do I register my view (switchboard user control) with my shell's switchboard region inside of the boot strapper. Maybe it is only possible to create a module specifically for the switchboard user control but it seems like a waste of time. I've been trying to attempt this but ultimately can't seem to get access to the RegionManager through my derived UnityBootStrapper class.
Thank You.
Wihtout knowing your entire scenario, it might not be necessary to add the Switchboard UserControl to a region. This is because, if your scenario requires you to add it in the Shell project, you might not need the extensibility and UI Composition capabilities provided by regions.
Assuming the SwitchBoard using control is in a ContentControl you could simply place it there from inside the Shell designer, without the need to define a region. On the other hand, if the SwitchBoard user control is placed inside a Selector or ItemsControl you could define the region, and add it as one of its children. You will still be able to add new views to those regions, and the SwitchBoard control will always be in the Shell.
That said, assuming the RegionManager has been registered in the container, you can do something like this to access the RM in the bootstrapper:
(pesudo code):
public class MyBootstrapper : UnityBootstrapper
{
MyMethod()
{
IRegionManager manager = this.Container.Resolve<IRegionManager>();
}
}
I hope this helps.
Thanks,
Damian

Resources