In mvvmcross v3 ViewModel
public class TimerViewModel : MvxViewModel
{
System.Timers.Timer timer;
public TimerViewModel()
{
timer = new System.Timers.Timer(500f);
timer.Elapsed += HandleTimerElapsed;
timer.Start();
}
void HandleTimerElapsed (object sender, ElapsedEventArgs e)
{
Debug.Log( "Time Elapsed" );
}
}
As MvxViewModel doesn't implement IDisposable, where should I put the following code ?
timer.Stop();
timer.Elapsed += HandleTimerElapsed;
I find that mvvmcross code have some MvxWeakEventSubscription, is it used to solve my problem ?
There's no easy universal way to know when to dispose the ViewModel - especially once you start mixing and matching ViewModel presentation styles to include navigations, tabs, splitviews, flyouts, fragments, lists, etc. and as you include more and more platforms
As a result of this, a couple of ways I have shut things like timers down in the past are:
1. Sometimes I have used a specialised interface on the ViewModel and I ensure this is called appropriately on each client.
For example, I have done some starting/stopping of 'page' level Views using:
OnPause/OnResume in Android
OnNavigatedTo/OnNavigatingFrom in Windows
ViewDidAppear/ViewWillDisappear in iOS
I have thought about adding this as a generalised pattern to do this (it is logged in https://github.com/slodge/MvvmCross/issues/74) - but so far I've not added this to v3 as I think it would lead to too much misunderstanding among users - it's better to let them to do this in the very few situations where it's needed.
Update: I have blogged about this and published a sample - see http://slodge.blogspot.co.uk/2013/11/n42-is-my-viewmodel-visible-can-i-kill.html
2. Sometimes I've just used Event Aggregation through the MvvmCross Messenger - and I've used it's inherent WeakReference-based messaging to make sure the ViewModel can be garbage collected when the view has finished with it.
An example of this is in the InternetMinute sample - which has a single 'Tick generation service' which ViewModels can connect to via messaging for updates - see:
the service - https://github.com/slodge/MvvmCross-Tutorials/tree/master/InternetMinute/InternetMinute.Core/Services/Tick
a ViewModel that consumes the service - via https://github.com/slodge/MvvmCross-Tutorials/blob/master/InternetMinute/InternetMinute.Core/ViewModels/HomeViewModel.cs
You might consider this slightly inefficient - as the Tick messages will be generated even if the ViewModel isn't present - but it's only a small inefficiency.
3. I've considered using more final events - things like OnNavigatingFrom(BACK) and 'onDestroy' and some 'final' detection on the UINavigationController delegates ... but I've not had a reason to do this 'for real' on any project yet.
Related
I want to create a controller based JavaFX GUI consisting of multiple controllers.
The task I can't accomplish is to pass parameters from one Scene to another AND back.
Or in other words:
The MainController loads SubController's fxml, passes an object to SubController, switches the scene. There shall not be two open windows.
After it's work is done, the SubController shall then switch the scene back to the MainController and pass some object back.
This is where I fail.
This question is very similar to this one but still unanswered. Passing Parameters JavaFX FXML
It was also mentioned in the comments:
"This work when you pass parameter from first controller to second but how to pass parameter from second to first controller,i mean after first.fxml was loaded.
– Xlint Xms Sep 18 '17 at 23:15"
I used the first approach in the top answer of that thread.
Does anyone have a clue how to achieve this without external libs?
There are numerous ways to do this.
Here is one solution, which passes a Consumer to another controller. The other controller can invoke the consumer to accept the result once it has completed its work. The sample is based on the example code from an answer to the question that you linked.
public Stage showCustomerDialog(Customer customer) {
FXMLLoader loader = new FXMLLoader(
getClass().getResource(
"customerDialog.fxml"
)
);
Stage stage = new Stage(StageStyle.DECORATED);
stage.setScene(
new Scene(
(Pane) loader.load()
)
);
Consumer<CustomerInteractionResult> onComplete = result -> {
// update main screen based upon result.
};
CustomerDialogController controller =
loader.<CustomerDialogController>getController();
controller.initData(customer, onComplete);
stage.show();
return stage;
}
...
class CustomerDialogController() {
#FXML private Label customerName;
private Consumer<CustomerInteractionResult> onComplete
void initialize() {}
void initData(Customer customer, Consumer<CustomerInteractionResult> onComplete) {
customerName.setText(customer.getName());
this.onComplete = onComplete;
}
#FXML
void onSomeInteractionLikeCloseDialog(ActionEvent event) {
onComplete.accept(new CustomerInteractionResult(someDataGatheredByDialog));
}
}
Another way to do this is to add a result property to the controller of the dialog screen and interested invokers could listen to or retrieve the result property. A result property is how the in-built JavaFX dialogs work, so you would be essentially imitating some of that functionality.
If you have a lot of this passing back and forth stuff going on, a shared dependency injection model based on something like Gluon Ignite, might assist you.
I've used AfterBurner.fx for dependency injection, which is very slick and powerful as long as you follow the conventions. It's not necessarily an external lib if you just copy the 3 classes into your structure. Although you do need the javax Inject jar, so I guess it is an eternal reference.
Alternately, if you have a central "screen" from which most of your application branches out you could use property binding probably within a singleton pattern. There are some good articles on using singleton in JavaFX, like this one. I did that for a small application that works really great, but defining all of those bindings can get out of hand if there are a lot of properties.
To pass data back, the best approach is probably to fire custom Events, which the parent controller subscribes to with Node::addEventHandler. See How to emit and handle custom events? for context.
In complex cases when the two controllers have no reference to each other, a Event Bus as #jewelsea mentioned is the superior option.
For overall architecture, this Reddit comment provides some good detail: https://www.reddit.com/r/java/comments/7c4vhv/are_there_any_canonical_javafx_design_patterns/dpnsedh/
I have a TitleWindow component. It allows me to save some data provided through 3 TextInput.
That data "fills" a DropDownList which is in another TitleWindow component, not inside the original one.
How can I call the remoteObject method that fills (or refresh) my DropDownList?
Any ideas will be appreciated!
You can simply use a Singleton as a model if you'd like, this will allow you to share data, but beware keep data only that needs to be shared in here or it will just become a global nightmare.
Using a singleton means you'll have a class that you can only ever have one instance of. If you put properties in that class any time you reference it it will be the same memory throughout the application execution.
http://blog.pixelbreaker.com/actionscript-3-0/as30-better-singletons
Marking the singleton class or individual properties as Bindable will make it so you can watch for the changes and call a function.
http://livedocs.adobe.com/flex/3/html/help.html?content=databinding_8.html
Putting this together you have something like this:
[Singleton.as]
package
{
[Bindable]
public class Singleton
{
public var myListData:Array;
public static var instance:Singleton;
public static function getInstance():Singleton
{
if( instance == null ) instance = new Singleton( new SingletonEnforcer() );
return instance;
}
public function Singleton( pvt:SingletonEnforcer )
{
// init class
}
}
}
internal class SingletonEnforcer{}
Somewhere else you want to get a handle on this
[MyTitleWindow.as]
var instance:Singleton = Singleton.getInstance();
instance.myListData = [1,2,3];
[MyTitleWindowWithAList]
var instance:Singleton = Singleton.getInstance();
BindingUtils.bindSetter(funcUpdateList, instance, "myListData");
private function funcUpdateList(data:Object)
{
myList.dataProvider = data as Array;
}
Another option is to create an event that carries your data payload, dispatch that event from the first title window, and capture it, the problem with this is you have to register the listeners on the PopUpManager or SystemManager I believe because the TitleWindow's aren't direct children of the Application I believe.
Singletons are a bad idea and you should not get in the habit of using them. Instead, just dispatch an event from the View and catch it from something else that has access to your Service object.
Note that your Service should not be part and parcel of any View--the responsibility of a View is displaying data and capturing requests from the user to change the data, not communicating with a server.
For examples of an application written with this pattern in mind, check out
[Refactoring with Mate] (http://www.developria.com/2010/05/refactoring-with-mate.html) - The example has View source enabled
The same application done with RobotLegs - again, View Source is enabled.
Note that these are written against some popular frameworks, but they are written in such a way that you can easily replace that framework code with something else, even your own code.
For reference, here is the naiive implementation, where the service layer is being called directly in the Views. You couldn't call a different service without changing the Views, though the use of the static service means you could use it from elsewhere.
That static usage survived into the later examples, though today I would never write something depending on a globally accessible object. In part this is because I discovered Test Driven Development, and it is impossible to replace the "real" static object with an object that lets you isolate what you are testing. However, the fact that most of the code in the 2 "better" examples is insulated from that static object means that it is trivial to replace it with one that is provided some other way.
The lesson here is if you're going to use static, global objects, lock them away behind as much abstraction as you can. But avoid them if you're at all interested in best practice. Note that a Singleton is a static global object of the worst kind.
This question is a follow-up / "second attempt" to a previous question of mine.
I am building a cross-platform mobile application using MvvmCross framework,
and I would like to use the Messenger plugin to receive event notifications published from somewhere else in my code.
I have tried to add the subscription in the ctor as follows:
public class MyViewModel : BaseViewModel, IMyViewModel
{
private MvxSubscriptionToken _showMsgToken;
public MyViewModel ()
{
_showMsgToken = MvxMessenger.Subscribe<ShowMsg>(message => onShowNavigation(), MvxReference.Weak);
}
private void onShowNavigation()
{
//Do Stuff
}
}
Now when I navigate to this ViewModel everything works and notifications are received.
However, when I navigate away and back to this ViewModel, I can see that the Subscription is adding another entry to the MvxMessenger subscriptions property, resulting onShowAdsNavigation() firing twice for each new event.
So, How can I subscribe to events in the ViewModel?
Or maybe I need to find a way to Unsubscribe from events?
If you need to actively unsubscribe from messages, then you can do this by capturing lifetime events within your views and then using these to drive your viewmodel. This is your code - you can do what you like.
For some options on this, see ViewModel LifeCycle, when does it get disposed?
I generally don't bother with active management of subscriptions. Instead I rely on the fact that the View will be removed from the UI, and so it and its ViewModel will be removed from memory at some time afterwards. When this happens I know that the subscription management will then happen automatically - when the View and ViewModel get Garbage Collected, then the subscriptions will also shortly afterwards get cleaned up. I know that the weak referencing used within the Messenger will mean that the subscriptions will clean themselves up.
To prove this, try https://github.com/slodge/MessengerHacking - it has a button to force GC to occur.
If this isn't "good enough* for your app, then see "If you need to actively..." above.
I've seen a lot of questions here related to the OnNavigatedTo method, but none of them seem to answer the basic question of, "At what point should I load data?" The documentation on MSDN doesn't explicitly answer this question, as far as I can tell.
If I need to load a list of data from the local database, which method is the most appropriate to use? Should I use the OnNavigatedTo method, or the Loaded event?
What I've been using so far is this pattern, which seems to work well:
protected override void OnNavigatedTo(NavigationEventArgs e) {
base.OnNavigatedTo(e);
if (NavigationMode.New == e.NavigationMode) {
var data = LoadData();
this.DataContext = data;
}
}
What this means is that for a new instance of a page, load the data synchronously. This also means that the page will not be rendered until the data has finished loading and the profiler complains that I'm using too much UI thread time.
An alternate approach is this pattern:
protected override async void OnNavigatedTo(NavigationEventArgs e) {
base.OnNavigatedTo(e);
if (NavigationMode.New == e.NavigationMode) {
var data = await LoadData();
this.DataContext = data;
}
}
But with this pattern, it seems to me that navigation, and therefore page rendering may occur before I've loaded the data and set the DataContext, meaning unnecessary re-paints and what-not.
I usualy bind to a ViewModel directly in XAML. Then in OnNavigatedTo I trigger the view model to fetch its data async.
This allows me to show basic values from start (page title etc.). Then when I start fetching the data I can also activate a progressbar directly in the ViewModel and then remove it once the data is fetched.
I recommend you load your data asynchronously. OnNavigatedTo is one place where you can start the loading. If you're talking about a page that the user is almost certainly going to navigate to, then you may be able to start loading earlier.
I have a series of blog posts that look at how async has some friction with traditional OOP. There are a couple of posts that look at data binding in particular, e.g., asynchronous construction (the section on asynchronous initialization) and asynchronous properties (the section on data binding).
Just a few hours ago I announced the first stable release for my AsyncEx library, which includes the NotifyTaskCompletion types that you can use to kick off an asynchronous loading operation and have your view respond automatically (via data binding) when it completes.
But back to the core problem: you do have to show something while the data is loading. I recommend you do not consider this "unnecessary", but rather accept it as an opportunity to provide a better user experience. Think about what you want your app to look like on a slower phone or if there is an error loading the data. Any time there's I/O, design the "Loading..." and "Error" states as well as the "Loaded" state.
I have a large application that needs to ensure that various items are loaded (at different times, not just at startup) before calling other routines that depend on said loaded items. What i find problematic is how my architecture ends up looking to support this: it is either littered with callbacks (and nested callbacks!), or pre populated with dozens of neat little
private function SaveUser_complete(params:ReturnType):void
{
continueOnWithTheRoutineIWasIn();
}
and so forth. Right now the codebase is only perhaps 2500 lines, but it is going to grow to probably around 10k. I just can't see any other way around this, but it seems so wrong (and laborious). Also, i've looked into pureMVC, Cairngorm, and these methods seem equally tedious,except with another layer of abstraction. Any suggestions?
Well asynchronous operations always have this affect on code bases, unfortunately there's not really a lot you can do. If your loading operations form some sort of 'Service' then it would be best to make a IService interface, along with the appropriate MVC Style architecture and use data tokens. Briefly:
//In your command or whatever
var service:IService = model.getService();
var asyncToken:Token = service.someAsyncOperation(commandParams);
//some messaging is used here, 'sendMessage' would be 'sendNotification' in PureMVC
var autoCallBack:Function = function(event:TokenEvent):void
{
sendMessage(workOutMessageNameHere(commandParams), event.token.getResult());
//tidy up listeners and dispose token here
}
asyncToken.addEventListener(TokenEvent.RESULT, autoCallBack, false, 0, true);
Where I have written the words 'workOutMessageNameHere()' I assume is the part you want to automate, you could either have some sort of huge switch, or a map of commandParams (urls or whatever) to message names, either way best get this info from a model (in the same command):
private function workOutMessageNameHere(commandParams):String
{
var model:CallbackModel = frameworkMethodOfRetrivingModels();
return model.getMessageNameForAsyncCommand(commandParams);
}
This should hopefully just leave you with calling the command 'callService' or however you are triggering it, you can configure the callbackMap / switch in code or possibly via parsed XML.
Hope this gets you started, and as I've just realized, is relevant?
EDIT:
Hi, just had another read through of the problem you are trying to solve, and I think you are describing a series of finite states, i.e. a state machine.
It seems as if roughly your sequences are FunctionState -> LoadingState -> ResultState. This might be a better general approach to managing loads of little async 'chains'.
Agreeing with enzuguri. You'll need lots of callbacks no matter what, but if you can define a single interface for all of them and shove the code into controller classes or a service manager and have it all in one place, it won't become overwhelming.
I know what you are going through. Unfortunately I have never seen a good solution. Basically asynchronous code just kind of ends up this way.
One solution algorithm:
static var resourcesNeededAreLoaded:Boolean = false;
static var shouldDoItOnLoad:Boolean = false;
function doSomething()
{
if(resourcesNeededAreLoaded)
{
actuallyDoIt();
}
else
{
shouldDoItOnLoad = true;
loadNeededResource();
}
}
function loadNeededResource()
{
startLoadOfResource(callBackWhenResourceLoaded);
}
function callBackWhenResourceLoaded()
{
resourcesNeededAreLoaded = true;
if(shouldDoItOnLoad)
{
doSomething();
}
}
This kind of pattern allows you to do lazy loading, but you can also force a load when necessary. This general pattern can be abstracted and it tends to work alright. Note: an important part is calling doSomething() from the load callback and not actuallyDoIt() for reasons which will be obvious if you don't want your code to become out-of-sync.
How you abstract the above pattern depends on your specific use case. You could have a single class that manages all resource loading and acquisition and uses a map to manage what is loaded and what isn't and allows the caller to set a callback if the resource isn't available. e.g.
public class ResourceManager
{
private var isResourceLoaded:Object = {};
private var callbackOnLoad:Object = {};
private var resources:Object = {};
public function getResource(resourceId:String, callBack:Function):void
{
if(isResourceLoaded[resourceId])
{
callback(resources[resourceId]);
}
else
{
callbackOnLoad[resourceId] = callBack;
loadResource(resourceId);
}
}
// ... snip the rest since you can work it out ...
}
I would probably use events and not callbacks but that is up to you. Sometimes a central class managing all resources isn't possible in which case you might want to pass a loading proxy to an object that is capable of managing the algorithm.
public class NeedsToLoad
{
public var asyncLoader:AsyncLoaderClass;
public function doSomething():void
{
asyncLoader.execute(resourceId, actuallyDoIt);
}
public function actuallyDoIt ():void { }
}
public class AsyncLoaderClass
{
/* vars like original algorithm */
public function execute(resourceId:String, callback:Function):void
{
if(isResourceLoaded)
{
callback();
}
else
{
loadResource(resourceId);
}
}
/* implements the rest of the original algorithm */
}
Again, it isn't hard to change the above from working with callbacks to events (which I would prefer in practise but it is harder to write short example code for that).
It is important to see how the above two abstract approaches merely encapsulate the original algorithm. That way you can tailor an approach that suites your needs.
The main determinants in your final abstraction will depend on:
Who knows the state of resources ... the calling context or the service abstraction?
Do you need a central place to acquire resources from ... and the hassle of making this central place available all throughout your program (ugh ... Singletons)
How complicated really is the loading necessities of your program? (e.g. it is possible to write this abstraction in such a way that a function will not be executed until a list of resources are available).
In one of my project, I build custom loader which was basically wrapper class. I was sending it Array of elements to load and wait for either complete or failed event(further I modified it and added priority also). So I didn't have to add so many handlers for all resources.
You just need to monitor which all resources has been downloaded and when all resources complete, dispatch a custom event-resourceDownloaded or else resourcesFailed.
You can also put a flag with every resource saying it is necessary or compulsory or not, If not compulsory, don't throw failed event on failing of that resource and continue monitoring other resources!
Now with priority, you can have bunch of file which you want to display first, display and continue loading other resources in background.
You can do this same and believe me you'll enjoy using it!!
You can check the Masapi framework to see if it fulfills your needs.
You can also investigate the source code to learn how they approached the problem.
http://code.google.com/p/masapi/
It's well written and maintained. I used it successfully in a desktop RSS client I developed with Air.
It worked very well assuming you pay attention to the overhead while loading too many resources in parallel.