application:didFinishLaunchingWithOptions: not executed when subclassing RBAppDelegate - redbeard-ios

When I subclass RBAppDelegate and override application:didFinishLaunchingWithOptions: it's never executed. Some hints with that?
class AppDelegate: RBAppDelegate {
override func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
super.application(application, didFinishLaunchingWithOptions: launchOptions)
// won't be executed...
configureStuff()
return true
}
}

RBAppDelegate itself does not implement didFinishLaunchingWithOptions. It provides a RBObserverCollection property that allows multiple classes to observer events. Within your app you should create another class that implements the RBAppDelegateObserver protocol. Within this call you should implement applicationDidFinishLaunching and then add this to your RBAppDelegate class via [appDelegate.observers addObserver:youclass]
FYI: If you don't need the functionality provided by RBAppDelegate you can continue to use a normal class that implements the UIApplicationDelegate protocol as is usual.

Related

Inject service into ViewModel with MVVM Light toolkit

I'm currently making an application with WPF and MVVM Light toolkit.
I have this view model :
public class MainViewModel : ViewModelBase
{
// Instance of service which is used for sending email.
private IEmailService _emailService;
// Get/set instance of service which is used for sending email.
public IEmailService EmailService
{
get
{
return _emailService;
}
set
{
Set("EmailService", ref _emailService, value);
}
}
public MainViewModel()
{
_emailService = new ServiceLocator.Current.GetInstance<IEmailService>();
}
}
Email service is a service which handles sending/processing emails. When user interacts with an element on the screen, email service is called (this has been registered in ServiceLocator)
I wonder if my implement is correct with MVVM design pattern or not. And are there any better ways to inject service into view model (the current approach takes a lot of time declaring initializing property)
I wonder if my implement is correct with MVVM design pattern or not.
Dependency injection has nothing to do with the MVVM pattern really. MVVM is about separation of concern between user interface controls and their logic. Dependency injection enables you to inject a class with any objects it needs without the class having to create these objects itself.
And are there any better ways to inject service into view model (the current approach takes a lot of time declaring initializing property)
If it makes no sense for the view model class to exist without a reference to the service, you should use constructor dependency injection instead of injecting the dependency through a property. You can read more about this here:
Dependency injection through constructors or property setters?
Using your current implementation it is possible to use the view model class without the service:
MainViewModel vm = new MainViewModel();
vm.EmailService = null;
A better implementation would be something like this:
public class MainViewModel : ViewModelBase
{
// Instance of service which is used for sending email.
private readonly IEmailService _emailService;
public MainViewModel(IEmailService emailService = null)
{
_emailService = emailService ?? ServiceLocator.Current.GetInstance<IEmailService>();
if(_emailService is null)
throw new ArgumentNullException(nameof(emailService));
}
}
This makes sure that the view model class always has a valid reference to an IEmailService. It also makes it possible to inject it with any implementation of the IEmailService interface when you construct the object.

How to pass data to an external assembly User Control through MEF

I am a beginner in MEF. According to my requirement I have to show the multiple plugin UI according to the selection of plugin. For that I have to pass plugin related data to the external plugin UserControl.
[InheritedExport(typeof(IConnect))]
public interface IConnect{}
Below code is using to initializing the external UI from the main application,
[ImportMany(typeof(IConnect))]
public IEnumerable<Lazy<IConnect>> Plugins;
....
var catalog = new DirectoryCatalog(#"C:\TestDll\");
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
var childControl = SelectedPlugin as UserControl;
//Here I have to pass the required data to the usercontrol. How to do this?
Dockpanel.Children.Add(childControl );
Could you please suggest a way to pass data to the external user control
Our entire team here at work has been using MEF for years now, and I'm reasonably familiar with how it works.
To get everything bootstrapped off the ground, the first thing to do is ensure that a common MEF container is shared between your main application and the user control in your external assembly.
If you don't have a common MEF container, then your MEF imported classes will never be able to communicate with the host application, as they will be living in separate MEF universes.
Once you have a common container, anywhere you want to bootstrap a class out of the container, you can use something like this:
var test = MefContainer.GetExportedValue<ITest>();
test.Run();
Q. How do I add MEF to my project?
A. Using NuGet, search for "microsoft composition", and add MEF 2.
Q. So how do we create this shared MEF container?
A. As follows:
Follow through a tutorial such as From Zero to Proficient with MEF.
Create a class library that is shared between your imported control, and the host application.
In this class library, create a singleton class called MefContainer. This means that anybody that wants to grab something out of the MEF container can reference this singleton to obtain the MEF container. The MEF container contains classes from all of the auto-discovered assemblies in the directories that we want to scan.
Q. How do I communicate with the user control?
A. Add this class to your shared class library:
public interface ITest
{
string SharedValue { get; set; }
}
[Export(typeof(ITest))]
public class Test : ITest
{
[ImportingConstructor]
public Test()
{
}
public string SharedValue { get; set; }
}
Now, both the host app and the user control can grab an instance of the same class out of the MEF container:
var test = MefContainer.GetExportedValue<ITest>();
var result = test.SharedValue;
By default, classes that are obtained from the MEF container are singleton's, unless we explicitly say that we want non-shared classes.
Q. How about adding Reactive Extensions (RX)?
It's ok to have a class with shared values. But it's nicer if one component can fire events off, and any other component can listen to this event.
To do this, add RX to your project using NuGet (search for "reactive extensions", add "Reactive Extensions - Main Library").
Add a Subject to your shared class:
private Subject<string> MyEvent { get; set; }
Now, if you have a MEF reference to this shared class, you can send an event out:
var t = MefContainer.GetExportedValue<ITest>();
t.MyEvent.OnNext("hello");
And, any other class can subscribe to these events:
var t = MefContainer.GetExportedValue<ITest>();
t.MyEvent.Subscribe(
o =>
{
Console.Write(o);
});
If code is already running in the MEF composition container, then there is no need to use MefContainer to get at the container. You can simply MEF import the shared communication class using the constructor:
public interface IClassRunningInContainer
{
}
[Export(typeof(IClassRunningInContainer))]
public class ClassRunningInContainer : IClassRunningInContainer
{
[ImportingConstructor]
public ClassRunningInContainer(ITest t)
{
t.OnNext("Hello, world!");
}
}
Final Notes
Don't make the mistake of using MEF as a general dependency injection (DI) solution. You will run into roadblocks further down the road, as MEF is does not have the level of built in diagnostics to find out if things have gone wrong, compared to a dedicated dependency injection solution, such as Unity.
The ideal pattern is to use MEF for importing whole assemblies, then use Unity as your day to day DI container.

Nancy/TinyIoC multiple concrete classes for single interface

We have two auth methods for different modules – UserAuthModule and ServiceAuthModule. We’ve created 2 base classes that modules derive from. We’ve interfaced the AuthProviders into IAuthProvider. Then we have a dependency in the constructors that should get the correct AuthProvider injected. However, we can’t find a way to tell Nancy/TinyIoC which concrete class to use. Here is the pseudo-code:
abstract class UserAuthModule : NancyModule
{
public UserAuthModule(IAuthProvider authProvider) // should get the UserAuthProvider concrete class
}
abstract class ServiceAuthModule : NancyModule
{
public ServiceAuthModule(IAuthProvider authProvider) // should get the ServiceAuthProvider concrete class
}
Here's an example of one of the concrete module's class declaration:
public class AccountModule : UserAuthModule
We then get stuck: how do we register 2 concrete classes for the IAuthProvider interface? We could name them, but can’t figure out how Nancy knows which class to inject when it does the constructor injection.
Inside our bootstrapper we have:
Container.Register<IAuthProvider, UserAuthProvider>(“UserAuth”);
Container.Register<IAuthProvider, ServiceAuthProvider>(“ServiceAuth”);
We could resolve the type from the container, but there's not container access within the Nancy module.
Is creating a unique interface for each based off of IAuthProvider out of the question?
interface IUserAuthProvider : IAuthProvider { }
interface IServiceAuthProvider : IAuthProvider { }
And then register:
Container.Register<IUserAuthProvider, UserAuthProvider>();
Container.Register<IServiceAuthProvider, ServiceAuthProvider>();
And then modify the constructors:
public UserAuthModule(IUserAuthProvider authProvider)
public ServiceAuthModule(IServiceAuthProvider authProvider)

Silverlight Prism MEF: why use ServiceLocator to get View instance?

In Prism's IModule Initialize() method, the RegisterViewWithRegion() method is called to map views and regions.
What is the difference between those two lines of code? Why use a ServiceLocator?
_regionManager.RegisterViewWithRegion("Region1", () => _serviceLocator.GetInstance<View1>());
_regionManager.RegisterViewWithRegion("Region1", typeof(View1));
Here is the whole ModuleInit.cs class for context:
namespace MyModule
{
[ModuleExport("MyModule.ModuleInit", typeof(MyModule.ModuleInit))]
public class ModuleInit : IModule
{
private readonly IRegionManager _regionManager;
public IServiceLocator _serviceLocator;
[ImportingConstructor]
public ModuleInit(IRegionManager regionManager, IServiceLocator serviceLocator)
{
_regionManager = regionManager;
_serviceLocator = serviceLocator;
}
#region IModule Members
public void Initialize()
{
_regionManager.RegisterViewWithRegion("Region1", () => _serviceLocator.GetInstance<View1>());
}
#endregion
}
}
[Edit]
The RegisterViewWithRegion Method MSDN site describes what the two different versions do:
RegisterViewWithRegion(IRegionManager, String, Func<Object>)
Associate a view with a region, using a delegate to resolve a
concreate instance of the view. When the region get's displayed, this
delelgate will be called and the result will be added to the views
collection of the region.
RegisterViewWithRegion(IRegionManager, String, Type)
Associate a view with a region, by registering a type. When the region
get's displayed this type will be resolved using the ServiceLocator
into a concrete instance. The instance will be added to the Views
collection of the region
So it seems to me that the only difference would be to use a ServiceLocator to resolve the type into an instance either immediately, or later when the region gets displayed?
[Edit2]
Found the answer elsewhere on Stackoverflow
That's because the main App is not supposed to know about modules.
When a module is loaded, it registers with the ServiceLocator and it has access to the RegionManager.
It can then, without the main app knowing anything about the newly loaded module, inject a view from the module into the main app (a new tab for example).
The ServiceLocator will ask MEF for dependencies, so you can always call _serviceLocator.GetInstance<View1>() parameterless, and MEF will go resolve whatever needs to be imported, no matter what you change in View1's constructor signature.

Passing Dictionary to ObjectForScripting with WPF WebBrowser

I am using a WebBrowser component in WPF to host some JavaScript + HTML and I want to be able to pass a customisable object in as the ObjectForScripting property. My end goal is that the javascript running in the WebBrowser can call something like:
window.external['lookup'].getValue(someId);
I can achieve something close to this by implementing a class with ComVisible set to true that has a lookup property on it:
[ComVisible(true)]
public class ScriptingContext
{
public LookupService lookup { get; set; } //where LookupService is also ComVisible
}
However, I want to be flexible about the members on the ObjectForScripting that I'm passing in so I can't specify what each property will be beforehand.
Ideally I would like to just specify a name-object pair to pass in, but afaict this doesn't work.
What I have tried (and failed with) so far:
using a Dictionary<string,object> as my context
using an extension of Dictionary<string,object> that is marked as ComVisible
using an ExpandoObject
using a List<KeyValuePair<string,object>>
using an extension of List<KeyValuePair<string,object>> that is marked as ComVisible
Is there some way to pass a customisable ObjectForScripting into the WPF WebBrowser that I am missing?
I'm not sure what you mean by customisable, but there's plenty of ways to accomplish what you're going for, such as building a wrapper for your dictionary and having that be your ObjectForScripting:
[ComVisible(true)]
public class ScriptingContext
{
private Dictionary<string, object> objectsForScripting;
public object GetValue(string s)
{
return objectsForScripting[s];
}
}
With the corresponding javascript window.external.GetValue("lookup").getValue(someId).
Note that you can also pass ComVisible objects to javascript through the InvokeScript method and interact with them that way, using something like webBrowser.InvokeScript("RegisterProperty", "lookup", lookupObject) and manage the objects you're exposing on the javascript side.

Resources