add fragment to activity so ViewModels of both are handled by MvvmCross - mvvmcross

I have fragment:
[MvxFragmentPresentation(AddToBackStack = true)]
public class MyFragmentView : MvxFragment<MyFragmentViewModel>
{
...
}
This fragament is used as content in "classic NavigationDrawer UI pattern", it works ok.
Is opened by:
NavigationService.Navigate<MyFragmentViewModel>();
Additionally I want to nest above fragment in standalone Activity started with like:
NavigationService.Navigate<MyActivityViewModel>();
This activity will have additional EditTexts, TextViews etc.
Later I will develop returning result from MyActivity to caller.
How to nest Fragment in Activity so both (MyFragment and MyActivity) will have ViewModels managed by MvvmCross?
Thank you in advance!

You need to specify the activity which will host your fragment, as you can see in the docs you can set the ActivityHostViewModelType which is the ViewModel that is related to the Activity that will host your fragment like this:
[MvxFragmentPresentation(AddToBackStack = true, ActivityHostViewModelType = typeof(MyActivityThatHostsTheFragmentsViewModel))]
public class MyFragmentView : MvxFragment<MyFragmentViewViewModel>
{
...
}
You can also add the id of the layout container for your fragment is needed:
[MvxFragmentPresentation(AddToBackStack = true, ActivityHostViewModelType = typeof(MyActivityThatHostsTheFragmentsViewModel), FragmentContentId = Resource.Id.Content)]
public class MyFragmentView : MvxFragment<MyFragmentViewViewModel>
{
...
}
You can find examples on the playground of MvvmCross.
Update:
If you need to have the same fragment on different containers then you need to have multiple attributes, e.g. here (as you can also see you can specify different things on the attributes like if one have a fragment content id and the other doesn't)
[MvxFragmentPresentation(AddToBackStack = true, ActivityHostViewModelType = typeof(MyActivityThatHostsTheFragmentsViewModel))]
[MvxFragmentPresentation(ActivityHostViewModelType = typeof(OtherActivityThatHostsTheFragmentsViewModel), FragmentContentId = Resource.Id.Content)]
public class MyFragmentView : MvxFragment<MyFragmentViewViewModel>
{
...
}
HIH

Related

Castle Windsor: Register by convention, open generics

I have an interface like so:
public interface IGenericRepository<T>
I have a base class like so:
public abstract class GenericRepository<T> : IGenericRepository<T> where T : class
I have a class like so:
public class AGenericRepository<T> : GenericRepository<T> where T : class
Without convention, I successfully registered like so:
container.Register(
Component.For(typeof(GenericRepository<>)).ImplementedBy(typeof(AGenericRepository<>))
);
I can successfully resolve an object like so:
var robot = container.Resolve<GenericRepository<Android>>();
However, when trying to register by convention like so:
container.Register(Classes.FromThisAssembly()
.BasedOn(typeof(GenericRepository<>))
.WithService.Base());
I cannot resolve as I did above. What gives?
Writing an answer since this may be too long (and codeful) for a comment.
Given the following code:
public interface IGenericRepository<T> {}
public abstract class GenericRepository<T> : IGenericRepository<T> where T : class {}
public class AGenericRepository<T> : GenericRepository<T> where T : class {}
public class AInstance: AGenericRepository<string>{}
this registration works fine for me:
var container = new WindsorContainer();
container.Register(Classes.FromThisAssembly().BasedOn(typeof (GenericRepository<>)).WithServiceBase());
var result = container.Resolve<GenericRepository<string>>();
I have a feeling that we are lacking some information regarding what classes are registered.
EDIT: in the proposed code apparently the abstract base class acts as a stop gap to determine what the base service is. If you use the following registration the resolution works:
var container = new WindsorContainer();
container.Register(Classes.FromThisAssembly().BasedOn(typeof (GenericRepository<>)).WithServiceAllInterfaces());
var result = container.Resolve<IGenericRepository<string>>();
However the resolution against the GenericRepository doesn't seem to work because it is not registered as a resolution component in castle. If you want to self register components you can describe it directly:
var container = new WindsorContainer();
container.Register(Classes.FromThisAssembly().BasedOn(typeof (GenericRepository<>)).WithServices(typeof(GenericRepository<>)));
var result = container.Resolve<GenericRepository<string>>();
// result is AGenericRepository<string>
DefaultInterfaces() only registers interfaces with a matching name.
Matching names, means that the implementing class contains in its name
the name of the interface (without the I on the front).
http://docs.castleproject.org/Windsor.Registering-components-by-conventions.ashx

Grails JSON marshallers in domain class

I know in grails i can define diferent JSON marshallers and asign names to them for different uses, which is very nice. However i end with a lot of code in the Bootstrap section and i end with two places where i need to tweak when domain classes changes.
Ithink thi is not good enough and i wonder if it might be possible to define JSON marshallers in the domain class itself.
Do you think would it be a good practice? ... can you provide suggestions on the best approach to achieve this?
Thanks,
I wrote a plugin for this purpose specifically. It allows you to use annotations in domain classes, like this:
import grails.plugins.jsonapis.JsonApi
class User {
static hasMany = [
pets: Pet
]
#JsonApi
String screenName
#JsonApi('userSettings')
String email
#JsonApi(['userSettings', 'detailedInformation', 'social'])
String twitterUsername
#JsonApi(['detailedInformation', 'userSettings'])
Set pets
String neverGetsSerialized
#JsonApi('detailedInformation')
Integer getNumberOfTicklyAnimals() {
pets.count { it.likesTickling }
}
}
In your controller, you would then call JSON.use('detailedInformation') to activate a specific marshaller.
In Bootstrap.groovy write this code:
JSON.registerObjectMarshaller(YourClass) { YourClass yourClass->
Map result = [:]
result['yourClass.property'] = yourClass.property
def domain = new DefaultGrailsDomainClass(YourClass)
domain.persistentProperties.each { GrailsDomainClassProperty property, String propertyName = property.name ->
result[propertyName] = yourClass[(propertyName)]
}
return result
}
Code below add one property, you can name it how u want
result['yourClass.property'] = yourClass.property
This code add all properties by it's name to map:
domain.persistentProperties.each { GrailsDomainClassProperty property, String propertyName = property.name ->
result[propertyName] = yourClass[(propertyName)]
}

Refer to a Spark view component in code

I'm building a mobile AIR app using Flash Builder 4.5. The initial view in my views package is TestHomeView.mxml. I want to refer to it in one of my .as classes elsewhere in the app, and I'm not sure how to do that.
Theoretically I should be able to add an "id" attribute to TestHomeView.mxml, but FB gives me an error: "id is not allowed on the root tag of a component". The root tag is s:view.
The reason I need to do this is that within another class I make various calculations and then need to pass an array of values to a component in my view class. So in SomeOtherActionScriptClass.as I first assemble the array, myArray, and then in that class I want to do this:
myViewComponent.viewArray = myArray;
If I'm going to do that, I also need to import the view class into the .as class, which strikes me as weird. So is there a simple way to do what I want, or do I have to dispatch a custom event which contains the array, and listen for it in the view class?
EDIT - Based on the below MVC suggestion I did the following in model:
[Bindable]
public class Model
{
private static var myModel:Model;//doesn't let me name it 'model' because
//I have a package named 'model'
public var myArray:Array; //its value set later in model code
public function Model()
{
if ( Model.myModel != null ){
throw new Error( "Only one Model instance should be instantiated" );
}
}
// singleton: always returns the one existing static instance to itself
public static function getInstance() : Model {
if ( myModel == null ){
myModel = new Model();
}
return myModel;
}
Then in the view code I have:
[Bindable] //do I actually need this?
private var myModel:Model = Model.getInstance();
var viewArray = new Array();
viewArray = myModel.myArray;
But it is coming back null. It isn't null when I put a breakpoint in the Model class, but when I try to access it from the view class, it's null. The model itself isn't null, but that variable is.
What am I doing wrong?
Thanks.
First, if you are trying to make a singleton in AS3 you should first create a class, within the same class file as Model, that is used to ensure you can only create the class once.
Add this class at the bottom of the Model class file (outside of the Model class):
internal class SingletonEnforcer{}
Then create the Model constructor like this:
public function Model(enforcer:SingletonEnforcer){ Init(); } // if init code is needed
public static function get Instance():Model
{
if (!myModel){
myModel = new Model(new SingletonEnforcer());
}
return myModel;
}
Now you don't have to throw an exception for creating a second instance because it isn't possible.
I'm not sure about your first question of referencing your app's main mxml, but if you were asking how to call the app that is running (like WindowedApplication in AIR) then you would call it like this:
// my WindowedApplication file = MyApp.mxml
MyApp(this.parentApplication)
That will return the app's instance.
Once you've set up the Singleton like I have it above you should be able to access your array like:
Model.Instance.myArray;
I hope this helps!
Follow the MVC pattern.
Create Model class (make it Bindable) with a property viewArray. Bind to this property from your View. And in any other class just change viewArray property of the model. The binding event will be fired and this property will also be changed in your View. To make your Model "visible" from any point, you can make it a Singleton.

Castle: using an existing (not single) instance for a lower-level dependency

I have a model roughly like this:
public interface IUnitOfWork { }
public class UnitOfWork : IUnitOfWork { }
public interface IService { }
public class Service : IService
{
public IUnitOfWork UnitOfWork { get; set; }
}
public class ViewModel
{
public IService Service { get; set; }
}
And a configuration that could be like this:
container.Register(Component.For<IService>().ImplementedBy<Service>()
.LifeStyle.Transient
Component.For<IUnitOfWork>().ImplementedBy<UnitOfWork>()
.LifeStyle.Transient,
Component.For<ViewModel>().LifeStyle.Transient);
I need to resolve, at different points, two instances of ViewModel (I'm using a typed factory for this, but let's leave that aside for simplicity and assume I'm using the raw container)
The catch is that I need to resolve two instances of ViewModel at different points (from another ViewModel that knows about both), and they need to share the same IUnitOfWork.
So, something like this:
var vm1 = container.Resolve<ViewModel>();
//...later
var vm2 = container.Resolve<ViewModel>();
Now, it's very easy to share the Service. I'd just have to do something like:
var vm2 = container.Resolve<ViewModel>(new { vm1.Service });
But of course the actual model is more complicated (different ViewModels, with more Services each), so that's not an option.
I can pass the UnitOfWork to Resolve, but it doesn't get used by default (which makes sense). Is there any way to use that parameter (probably by registering a delegate somewhere) when resolving the second ViewModel?
I'd like to be able to do the following:
var vm2 = container.Resolve<ViewModel>(new { UnitOfWork });
And get a ViewModel whose Service has that specific UnitOfWork.
If you need to share a component and you cannot set as singleton(rich client) or perwebrequest, you need to use Contextual lifestyle.
check this thread see my last comment to downoload contrib w/ Contextual Lifestyle
For you case I assume those 2 ViewModel will be used by 1 View... so View + UoW require Contextual Lifestyle
check also this one too see comments at the end
The solution was to use ContextualLifestyle coupled with a custom factory that kept a reference to the ContainerContext, in order to use the same one when resolving another ViewModel.

actionscript 3 MVC work flow

What's the best practice for passing data between the main class and the view class and vice versa?
main.as
var model : Model = new Model();
var view : View = new View();
var controller : controller = new Controller();
public function callFromView() : void {}
view.as
// how to reference the main.as
private function callToMain() : void
{
// please help
}
I generally handle communication by changing properties in the model via the controller. On change of values in the model, i will dispatch events representing those changes. Anyone (Main in this case) that has a reference to the model can subscribe to those events. This results in a more circuitous implementation, but to a very loosely coupled result.
Create a variable inside your View class called:
var main:Main;
Then a function to receive an object of type Main that sets the variable you created above, like this:
public function setMain(mainIN:Main):void
{
main = mainIN;
}
Now you have a local copy of all the data contained in your main document class in your View class. You can access properties of main by doing this (inside your view class' functions):
main.model.x = mouseX; //just an example. For this, your model variable inside Main would need to be public.
To do data passing the other way, you simply create public properties or functions inside your View class, and then because you've created the instance of View inside your Main class, it will be able to access it as normal with code like:
view.someViewFunction();
In this way each class has access to each other's properties and functions. I hope this helps!