I am trying to use MvvmCross v3 in one of my applications which consists of activities, content providers and broadcast receivers. However, I am not quite succeeding.
The application consists of a Core PCL which contains logic, models and viewmodels and a Droid application which contains all MonoDroid-specific stuff.
In Core I have an App:MvxApplication class and in Droid I have a Setup:MvxSetup class which creates an App-instance and initialises stuff.
I can use the IOC parts with content providers, broadcast receivers and non-Mvx-activities without problems. When I now want to add an MvxActivity it falls apart.
When the Mvx Activity launches I get an exception "Cirrious.CrossCore.Exceptions.MvxException: MvxTrace already initialized".
Obviously I am initialising things in the wrong order / wrong place. But, I need a pointer in the right direction.
My App Class
public class App
: MvxApplication
{
public override void Initialize()
{
base.Initialize();
InitialisePlugins();
InitaliseServices();
InitialiseStartNavigation();
}
private void InitaliseServices()
{
CreatableTypes().EndingWith("Service").AsInterfaces().RegisterAsLazySingleton();
}
private void InitialiseStartNavigation()
{
}
private void InitialisePlugins()
{
// initialise any plugins where are required at app startup
// e.g. Cirrious.MvvmCross.Plugins.Visibility.PluginLoader.Instance.EnsureLoaded();
}
}
And my setup class
public class Setup
: MvxAndroidSetup
{
public Setup(Context applicationContext)
: base(applicationContext)
{
}
protected override IMvxApplication CreateApp()
{
return new App();
}
protected override IMvxNavigationSerializer CreateNavigationSerializer()
{
return new MvxJsonNavigationSerializer();
}
public override void LoadPlugins(Cirrious.CrossCore.Plugins.IMvxPluginManager pluginManager)
{
pluginManager.EnsurePluginLoaded<Cirrious.MvvmCross.Plugins.Json.PluginLoader>();
base.LoadPlugins(pluginManager);
}
public void RegisterServices()
{
// I register a bunch of singletons here
}
// The following is called from my content provider's OnCreate()
// Which is the first code that is run
public static void DoSetup(Context applicationContext)
{
var setup = new Setup(applicationContext);
setup.Initialize();
setup.RegisterServices();
}
My Content provider's OnCreate():
public override bool OnCreate()
{
Log.Debug(Tag, "OnCreate");
_context = Context;
Setup.DoSetup(_context);
return true;
}
My MvxActivity:
[Activity(Label = "#string/ApplicationName", MainLauncher = true)]
[IntentFilter(new[] { "Settings" })]
public class SettingsView
: MvxActivity
{
public new SettingsViewModel ViewModel
{
get { return (SettingsViewModel) base.ViewModel; }
set { base.ViewModel = value; }
}
protected override void OnViewModelSet()
{
SetContentView(Resource.Layout.Page_SettingsView);
}
}
Short answer (I'm in an airport on mobile)
all the mvx android views will check the setup singleton has been created - https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross.Droid/Platform/MvxAndroidSetupSingleton.cs (vnext tree - but similar on v3)
so if you are creating a setup, but not setting this singleton, then you will get a second setup created when you first show a view
i suspect you can just get your setup created via the singleton class, but if this isn't flexible enough for your needs, then please log an issue on github
would also love to see some blogging about this - I've not used custom content providers much (at all!)
Related
I'm trying to integrate TinyIoc with MvvmCross. I followed the instructions from
https://github.com/MvvmCross/MvvmCross/wiki/Customising-using-App-and-Setup#changing-the-ioc-container-that-mvvmcross-uses
and created an adapter
public class TinyIoCMvxIoCAdapter : MvxSingleton<IMvxIoCProvider>, IMvxIoCProvider
{
...
}
that implements all the methods and forwards it to the TinyIoC container. That was very straight forwared and I only had to implement some additional code to fire the callbacks when something gets subscribed for
void CallbackWhenRegistered<T>(Action action)
void CallbackWhenRegistered(Type type, Action action)
I changed Setup.cs
protected override IMvxIoCProvider CreateIocProvider()
{
var provider = TinyIoCAdapterSetup.CreateIocProvider();
return provider;
}
with
public class TinyIoCAdapterSetup
{
public static IMvxIoCProvider CreateIocProvider()
{
var container = TinyIoCContainer.Current;
container.AutoRegister(t => t == typeof(IMvxViewModel));
return new TinyIoCMvxIoCAdapter(container);
}
}
That all works great. I can see that register is called on TinyIoc and things are getting resovled as well.
What does not work are the plugins. We are using the Messenger plugin and with the TinyIoC integration, the IMvxMessenger cannot be resolved when a ViewModel is resolved that gets the IMvxMessenger ctor injected. I can see that the MessengerPluginBootstrap is created by Mvx but I couldn't see that a call was made to register IMvxMessenger.
Does anybody know what I'm doing wrong?
Each plugin has a PluginLoader class that the Bootstrapper calls to register the plugin in the IoC container.
It looks something like this:
public class PluginLoader
: IMvxPluginLoader
{
public static readonly PluginLoader Instance = new PluginLoader();
private bool _loaded;
public void EnsureLoaded()
{
if (_loaded)
{
return;
}
Mvx.RegisterSingleton<IMvxMessenger>(new MvxMessengerHub());
_loaded = true;
}
}
Without seeing your IoC adapter, it's difficult to say what the issue is. Try manually registering the plugin to see if the IoC container is working properly.
While trying to coerce Windsor into wrapping an implementation with a random number of decorators, i've stumbled upon the following:
i have 3 decorators and an implementation all using the same interface.
if you run this code, windsor resolves icommandhandler<stringcommand> as implementation, which, as far as i can tell, is expected behaviour, because the typed implementation can not be registered with the open typed decorators.
However, if you uncomment the line container.Register(Component.For<ICommandHandler<stringCommand>>().ImplementedBy<Decorator1<stringCommand>>());, all three decorators will be used to resolve implementation, which is the desired result (sort of : ).
class Program
{
static void Main(string[] args)
{
var container = new WindsorContainer();
container.Register(Component.For(typeof(ICommandHandler<>)).ImplementedBy(typeof(Decorator1<>)));
container.Register(Component.For(typeof(ICommandHandler<>)).ImplementedBy(typeof(Decorator2<>)));
container.Register(Component.For(typeof(ICommandHandler<>)).ImplementedBy(typeof(Decorator3<>)));
//uncomment the line below and watch the magic happen
//container.Register(Component.For<ICommandHandler<stringCommand>>().ImplementedBy<Decorator1<stringCommand>>());
container.Register(Component.For<ICommandHandler<stringCommand>>().ImplementedBy<implementation>());
var stringCommandHandler = container.Resolve<ICommandHandler<stringCommand>>();
var command = new stringCommand();
stringCommandHandler.Handle(command);
Console.WriteLine(command.s);
Console.ReadKey();
}
}
public interface ICommandHandler<T>
{
void Handle(T t);
}
public class stringCommand
{
public string s { get; set; }
}
public abstract class Decorator<T> : ICommandHandler<T>
{
public abstract void Handle(T t);
};
public class Decorator1<T> : Decorator<T>
where T : stringCommand
{
private ICommandHandler<T> _handler;
public Decorator1(ICommandHandler<T> handler)
{
_handler = handler;
}
public override void Handle(T t)
{
t.s += "Decorator1;";
_handler.Handle(t);
}
}
public class Decorator2<T> : Decorator<T>
where T : stringCommand
{
private ICommandHandler<T> _handler;
public Decorator2(ICommandHandler<T> handler)
{
_handler = handler;
}
public override void Handle(T t)
{
t.s += "Decorator2;";
_handler.Handle(t);
}
}
public class Decorator3<T> : Decorator<T>
where T : stringCommand
{
private ICommandHandler<T> _handler;
public Decorator3(ICommandHandler<T> handler)
{
_handler = handler;
}
public override void Handle(T t)
{
t.s += "Decorator3;";
_handler.Handle(t);
}
}
public class implementation : ICommandHandler<stringCommand>
{
public void Handle(stringCommand t)
{
t.s += "implementation;";
}
}
Why exactly is this happening, is this a feature of windsor that i am not aware of? Is there perhaps a different way to achieve the same effect? (without resorting to reflection)
When windsor tries to resolve a component it will first try to resolve the more specific interface. So when you register Component.For it will prefer to resolve this over an open generic type.
If the same interface is registered multiple times, it will use the first one specified.
So if you don't uncommment the line your application will resolve implementation since this is the most specific component.
If you do uncomment the line decorator1 will be resolved and indeed the magic starts. The decorator will now start looking for the first registered component that satisfies it's constructor, in this case that would be decorator1 again (you did notice that your output show decorator1 2 times ?). Which will the resolve the next registered component and so on till it comes to the actual implementation.
So the only thing I can think about is not registering decorator1 as an open generic but as a specific type.
Kind regards,
Marwijn.
I have an MVVM Cross application running on Windows Phone 8 which I recently ported across to using Portable Class Libraries.
The view models are within the portable class library and one of them exposes a property which enables and disables a PerformanceProgressBar from the Silverlight for WP toolkit through data binding.
When the user presses a button a RelayCommand kicks off a background process which sets the property to true which should enable the progress bar and does the background processing.
Before I ported it to a PCL I was able to invoke the change from the UI thread to ensure the progress bar got enabled, but the Dispatcher object isn't available in a PCL. How can I work around this?
Thanks
Dan
All the MvvmCross platforms require that UI-actions get marshalled back on to the UI Thread/Apartment - but each platform does this differently....
To work around this, MvvmCross provides a cross-platform way to do this - using an IMvxViewDispatcherProvider injected object.
For example, on WindowsPhone IMvxViewDispatcherProvider is provided ultimately by MvxMainThreadDispatcher in https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross.WindowsPhone/Views/MvxMainThreadDispatcher.cs
This implements the InvokeOnMainThread using:
private bool InvokeOrBeginInvoke(Action action)
{
if (_uiDispatcher.CheckAccess())
action();
else
_uiDispatcher.BeginInvoke(action);
return true;
}
For code in ViewModels:
your ViewModel inherits from MvxViewModel
the MvxViewModel inherits from an MvxApplicationObject
the MvxApplicationObject inherits from an MvxNotifyPropertyChanged
the MvxNotifyPropertyChanged object inherits from an MvxMainThreadDispatchingObject
MvxMainThreadDispatchingObject is https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross/ViewModels/MvxMainThreadDispatchingObject.cs
public abstract class MvxMainThreadDispatchingObject
: IMvxServiceConsumer<IMvxViewDispatcherProvider>
{
protected IMvxViewDispatcher ViewDispatcher
{
get { return this.GetService().Dispatcher; }
}
protected void InvokeOnMainThread(Action action)
{
if (ViewDispatcher != null)
ViewDispatcher.RequestMainThreadAction(action);
}
}
So... your ViewModel can just call InvokeOnMainThread(() => DoStuff());
One further point to note is that MvvmCross automatically does UI thread conversions for property updates which are signalled in a MvxViewModel (or indeed in any MvxNotifyPropertyChanged object) through the RaisePropertyChanged() methods - see:
protected void RaisePropertyChanged(string whichProperty)
{
// check for subscription before going multithreaded
if (PropertyChanged == null)
return;
InvokeOnMainThread(
() =>
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(whichProperty));
});
}
in https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross/ViewModels/MvxNotifyPropertyChanged.cs
This automatic marshalling of RaisePropertyChanged() calls works well for most situations, but can be a bit inefficient if you Raise a lot of changed properties from a background thread - it can lead to a lot of thread context switching. It's not something you need to be aware of in most of your code - but if you ever do find it is a problem, then it can help to change code like:
MyProperty1 = newValue1;
MyProperty2 = newValue2;
// ...
MyProperty10 = newValue10;
to:
InvokeOnMainThread(() => {
MyProperty1 = newValue1;
MyProperty2 = newValue2;
// ...
MyProperty10 = newValue10;
});
If you ever use ObservableCollection, then please note that MvvmCross does not do any thread marshalling for the INotifyPropertyChanged or INotifyCollectionChanged events fired by these classes - so it's up to you as a developer to marshall these changes.
The reason: ObservableCollection exists in the MS and Mono code bases - so there is no easy way that MvvmCross can change these existing implementations.
If you don't have access to the Dispatcher, you can just pass a delegate of the BeginInvoke method to your class:
public class YourViewModel
{
public YourViewModel(Action<Action> beginInvoke)
{
this.BeginInvoke = beginInvoke;
}
protected Action<Action> BeginInvoke { get; private set; }
private void SomeMethod()
{
this.BeginInvoke(() => DoSomething());
}
}
Then to instanciate it (from a class that has access to the dispatcher):
var dispatcherDelegate = action => Dispatcher.BeginInvoke(action);
var viewModel = new YourViewModel(dispatcherDelegate);
Or you can also create a wrapper around your dispatcher.
First, define a IDispatcher interface in your portable class library:
public interface IDispatcher
{
void BeginInvoke(Action action);
}
Then, in the project who has access to the dispatcher, implement the interface:
public class DispatcherWrapper : IDispatcher
{
public DispatcherWrapper(Dispatcher dispatcher)
{
this.Dispatcher = dispatcher;
}
protected Dispatcher Dispatcher { get; private set; }
public void BeginInvoke(Action action)
{
this.Dispatcher.BeginInvoke(action);
}
}
Then you can just pass this object as a IDispatcher instance to your portable class library.
Another option that could be easier is to store a reference to SynchronizationContext.Current in your class's constructor. Then, later on, you can use _context.Post(() => ...) to invoke on the context -- which is the UI thread in WPF/WinRT/SL.
class MyViewModel
{
private readonly SynchronizationContext _context;
public MyViewModel()
{
_context = SynchronizationContext.Current.
}
private void MyCallbackOnAnotherThread()
{
_context.Post(() => UpdateTheUi());
}
}
We are using the NoTrackingReleasePolicy on the Windsor container due to the memory leaks that occur when we do not Release our components after usage. Now consider the following problem.
Some disposable component:
public class DisposableComponent : IDisposable
{
private bool _disposed;
public bool Disposed
{
get { return _disposed; }
}
public void Dispose()
{
_disposed = true;
GC.SuppressFinalize(this);
}
}
Some class using the disposable component:
public class ClassWithReferenceToDisposableService
{
private DisposableComponent _disposableComponent;
public ClassWithReferenceToDisposableService(DisposableComponent disposableComponent)
{
_disposableComponent = disposableComponent;
}
}
And finaly a test which configures these components as transient and resolve/release them:
[Test]
public void ReleaseComponent_ServiceWithReferenceToTransientDisposable_TransientComponentDisposed()
{
// arrange
var windsorContainer = new WindsorContainer();
windsorContainer.Kernel.ReleasePolicy = new NoTrackingReleasePolicy();
windsorContainer.Register(Component.For<ClassWithReferenceToDisposableService>().LifeStyle.Transient);
windsorContainer.Register(Component.For<DisposableComponent>().LifeStyle.Transient);
ClassWithReferenceToDisposableService service =
windsorContainer.Resolve<ClassWithReferenceToDisposableService>();
// act
windsorContainer.Release(service);
}
Now, if I remove the NoTrackingReleasePolicy, Windsor will dispose the transient service as expected, but I can not do this (period). Now, what I want to achieve is that Windsor disposes the transient components (anywhere in the resolve graph) when I invoke ReleaseCompnent. Is there any way to achieve this without changing the NoTrackingReleasePolicy?
No, you can't have your cake and eat it too.
You can implement your own custom policy that is kind of like NoTrackingReleasePolicy but will track some components...
Consider the following example:
public interface ITask
{
void Execute();
}
public class LoggingTaskRunner : ITask
{
private readonly ITask _taskToDecorate;
private readonly MessageBuffer _messageBuffer;
public LoggingTaskRunner(ITask taskToDecorate, MessageBuffer messageBuffer)
{
_taskToDecorate = taskToDecorate;
_messageBuffer = messageBuffer;
}
public void Execute()
{
_taskToDecorate.Execute();
Log(_messageBuffer);
}
private void Log(MessageBuffer messageBuffer)
{}
}
public class TaskRunner : ITask
{
public TaskRunner(MessageBuffer messageBuffer)
{
}
public void Execute()
{
}
}
public class MessageBuffer
{
}
public class Configuration
{
public void Configure()
{
IWindsorContainer container = null;
container.Register(
Component.For<MessageBuffer>()
.LifeStyle.Transient);
container.Register(
Component.For<ITask>()
.ImplementedBy<LoggingTaskRunner>()
.ServiceOverrides(ServiceOverride.ForKey("taskToDecorate").Eq("task.to.decorate")));
container.Register(
Component.For<ITask>()
.ImplementedBy<TaskRunner>()
.Named("task.to.decorate"));
}
}
How can I make Windsor instantiate the "shared" transient component so that both "Decorator" and "Decorated" gets the same instance?
Edit: since the design is being critiqued I am posting something closer to what is being done in the app. Maybe someone can suggest a better solution (if sharing the transient resource between a logger and the true task is considered a bad design)
Edit2: Castle3 has added support for this (http://docs.castleproject.org/Windsor.Whats-New-In-Windsor-3.ashx) by introducing the "Bound" lifestyle
'Transient' explicitly means 'non-shared', so what you are asking is conceptually the wrong thing to do. The correct solution is to register Shared as a Singleton instead of Transient:
container.Register(Component.For<Shared>());
(Singleton is the default lifetime in Windsor.)
However, I suspect that behind the stated question lies a much more complex problem. I'm guessing that you need Shared to be Transient because you need it with this lifestyle for a lot of other cases, but exactly when it comes to the relationship between Decorator and Decorated you need to share them.
I still think this sounds like a Design Smell, but there are at least two ways you can achieve this result.
The first option involves prematurely resolving Shared and explicitly supply the resolved instance to the configuration of the two IFoo registrations:
container.Register(Component.For<Shared>().LifeStyle.Transient);
var r = container.Resolve<Shared>();
container.Register(Component
.For<IFoo>()
.ImplementedBy<Decorator>()
.DependsOn(new { resource = r }));
container.Register(Component
.For<IFoo>()
.ImplementedBy<Decorated>()
.DependsOn(new { resource = r }));
The second option is to make a specialized, named registration for Shared that is used only by the IFoo registrations:
container.Register(Component.For<Shared>().LifeStyle.Transient);
container.Register(Component.For<Shared>().Named("shared"));
container.Register(Component
.For<IFoo>()
.ImplementedBy<Decorator>()
.ServiceOverrides(new { resource = "shared" }));
container.Register(Component
.For<IFoo>()
.ImplementedBy<Decorated>()
.ServiceOverrides(new { resource = "shared" }));