How to implement "onActivityResult" but for fragments, using the new Navigation from Androidx - android-architecture-components

I just searched the docs about using and implement the new Navigation Component, and I dont see or find a method to send data to previous fragment.

There is a feature request for this feature, you can star it:
https://issuetracker.google.com/issues/79672220.
But for now you can implement this using LiveData and ViewModel, First fragment will observe some LiveData object inside your ViewModel, second fragment will change this object value, and when you will go back to first fragment it will be notified that the value is changed.

Related

How to add to an ObservableCollection from a different view?

(I'm using Prism Dryloc) My application consists of two views. The first contains a single list view displaying strings and the second - an entry and a button.
The listview is bound to an observable collection in the first page's View Model. How can I add to the observable collection from a different view?
Great question! You're essentially trying to pass data between views, and there's several ways of passing data between Views in Xamarin.Forms.
The two ways that seem relevant for your case:
Either making the ObservableCollection a public static object (so there's only one global instance of it). Not recommended.
The better way is to use the messaging center so that the second page publishes an event when the button is pressed, that the first page is subscribed to. And it passes that information that gets added to the list.
If these don't work, elaborate your use case and I'll suggest some more

How does an MVC System View element know when to update?

For example in AngularJS if you bind an ng-model to an ng-repeater, and your controller calls a service that updates the model, then the repeater is updated to reflect the change.
My question is, how does the view element (in this example, the ng-repeater) know to be updated?
For example, is there a timer that fires every couple milliseconds and updates the UI (unlikely)? Does the controller or view implement some type of internal event listener for all bindings and when the model updates, it fires a re-layout of the associated view elements?
When we write an expression ({{dyanvar}}), behind the scenes Angular sets up a watcher on the scope model, which in turn updates the view whenever the model changes. This watcher is like any other watcher we set up in AngularJS:
$scope.$watch('dyanvar', function(newValue, oldValue) {
//update the view with newValue
});
The second argument passed to $watch() is known as a listener function, and It is called whenever the value of dyanvar changes.
Your answer is in this article :
https://cfdeepak.wordpress.com/2014/09/29/how-two-way-data-binding-works-in-angular-js/

Moving an ItemView from one CollectionView in another without deleting it, best practice?

I'm building a dashboard builder and view interface with Marionette. I have some views from legacy code that are pretty heavyweight(large reports) and the html is thus pre-constructed on the server.
I have a Marionette CollectionView for each row in the dashboard which contains an ItemView for each widget that was dragged onto the row during dashboard building.
When the user moves a widget from one row to another I want to avoid deleting the view and having to reconstruct it (because it would be a lot of unnecessary dom manipulation) but instead want to just detach the element from one(row) CollectionView and add it to another. What's the best practice for accomplishing this with CollectionViews in Marionette?
It seems by default moving a item across CollectionViews would destroy the view/model from one and re-instantiate/re-render it in the other.
The concern I have is that the tablereport in the DOM that would be moving from one collection to another is not original Marionette/Backbone template generated View, it would be just a predefined DOM element we set as the view's el.
The tablereport DOM element has lots of children elements with events associated with it via legacy code not the Backbone view events array nor via Backbone's listenTo calls. So destroying the DOM tablereport element is what we need to avoid to preserve those events, we just want to relocate it in the DOM.
Whats the best way to handle this functionality efficiently in Marionette.
A couple options spring to mind, but the fact that your event-binding code is not easily callable means you'll probably want to use the jQuery detach() method to keep all your events bound when you remove an element.
One option is to cache your view elements as you build them:
- write a view factory which you delegate to in the buildItemView method of your CompositeView.
- have your factory cache the elements for the views it creates against the model.cid of the model that is passed in as the first parameter to the buildItemView method.
- when your factory method is called, retrieve the element from the cache if it exists, call detach() on it, and set it as the ItemView's element.
- override the render method on the view to stop it from rebuilding the html
- move the model from one CollectionView's collection and put it into the other CollectionView's collection, and Marionette will then build your view as described above and insert the element (with events still bound) into the DOM.
Instead of doing the above, you could, assuming you know which ItemView has been dropped:
- remove the ItemView from the first CollectionView's children container (this is a Backbone.Babysitter instance, I believe, and there is documentation for it)
- detach the ItemView's element
- insert the ItemView's element into its new place in the DOM
- insert the ItemView into the second CollectionView's children container
- remove the model from the first CollectionView's collection
- add the model into the second CollectionView's collection silently, which prevents the CollectionView from triggering its normal behaviour of building a new view, rendering it and inserting it.
The first way is probably more elegant as you are still letting Marionette do its thing, but just altering the building, rendering and inserting of the ItemViews. The second way is less complex, but means you have to manually keep everything in sync yourself - essentially doing what Marionette would normally do behind the scenes and stopping it from 'interfering', so to speak.

PRISM: Passing object/events from parent to child View/VM with PopupRegions

We are working with an application that uses prism and MVVM for healthcare tracking operations.
Within this application, we have registered views in primary regions, and scenarios in which clicking on a cell in a grid (in this case a xamdatagrid - Infragistics) will launch another region via the prism region popup behaviors constructs.
So, when we click on the cell, a cellactivation operation in the code behind for that view is called which then calls a method in the view model to .RequestNavigate to the view that is registered for the 'secondary' popup region (thus launching what appears to be a dialog over the existing application).
I am attempting to pass an object from the parent view (the values of the record in the grid) to the child view that is launched in the popup, and have found that none of the expected operations is working.
I have a mediator object that we are using to pass information back from children to parents, but this does not work the other direction because the publish/notify operations for the mediator require the child view to 'already' be instantiated before the parent publishes to pass that information.
I'm finding that the event aggregator structures built into the Prism.Events classes don't appear to be working either (I'm assuming because of the same publish/subscribe issues). I can publish an event through the event aggregator from the parent view and subscribe in the child view, but I have to launch the child view 'twice' in order to get the event tied to the event aggregator operation to actually fire.
I understand this is rather vague (minus the code), but I'm looking more for a start point, or anyone that's run into the same kinds of issues. The bullet point scenario is as follows:
Parent view already instantiated in existing region.
Clicking on cell in parent view instantiates (navigates to) child view in popup region.
Same click operation needs to pass an object from the parent view to the child view so that the child view can filter its own data based on that object.
Operations are constructed using Prism/MVVM.
Any help, suggestions, pointers, ideas would be awesome.
We had the same scenario and ended up with creating a UiService that are injected to our ViewModels. Our ViewModel base class has a SetModel method which the UiService calls when navigating, for sending parameters to the destination view.
By example:
Clicking a button in the existing View.
Source ViewModel calls UiService ShowView(data).
UiService calls RequestNavigate for the requested view.
UiService calls SetModel on the destination ViewModel (by accessing the DataContext of the requested view) to pass in the data from the source ViewModel.
Depending what you want to pass it can be pretty simple with INavigationAware
Sounds like you want to pass something like query string - parameters, etc. Code to open window will be like this:
var query = new UriQuery
{
{ "MailItemKey", this.SelectedMailItem.MailItemKey.ToString(CultureInfo.InvariantCulture) }
};
RegionManager.RequestNavigate(RegionNames.Popup, typeof(MailItemView).Name + query.ToString());
And inside MailItemViewModel which is our popup's VM code is like this:
public override void OnNavigatedTo(NavigationContext navigationContext)
{
var mailItemKey = int.Parse(navigationContext.Parameters["MailItemKey"]);
}
If you want to pass custom objects - it will be more complex. I would look for MVVM in the box samples - there is some code on how it's done. I had to re-work it whole lot and code is not really copy-pasteable.
Sounds like a perfect use of a RegionContext.
Parent view contains a region that can have multiple "child" views activated in it. They need to share some context or data. Set a region context and bind or pass whatever info all the "child" views in the Region will need.
See the Prism samples around RegionContext.

Breaking event cycles in GUIs

When writing GUIs, I've frequently come over the following problem: Assume you have a model and a controller. The controller has a widget W that is used to show a property X of the model.
Because the model might be changed from outside the controller (there might be other controllers using the same model, undo operations etc), the controller listens to changes on the model. The controller also listens to events on the widget W and updates the property X accordingly.
Now, the following happens:
the value in W is changed
an event is generated, the handler in the controller is invoked
the controller sets the new value for X in the model
the model emits events because it has been changed
the controller receives a change event from the model
the controller gets the value of X and sets it in the widget
goto 1.
There are several possible solutions for that:
Modify the controller to set a flag when the model is updated, and not react to any events from the model if this flag is set.
Disconnect the controller temporarily (or tell the model not to send any events for some time)
Freeze any updates from the widget
In the past, I usually went for option 1., because it's the simplest thing. It has the drawback of cluttering your classes with flags, but the other methods have their drawbacks, too.
Just for the record, I've had this problem with several GUI toolkits, including GTK+, Qt and SWT, so I think it's pretty toolkit-agnostic.
Any best practices? Or is the architecture I use simply wrong?
#Shy: That's a solution for some cases, but you still get a round of superfluous events if X is changed from outside the controller (for instance, when using the command pattern for undo/redo), because then the value has changed, W is updated and fires an event. In order to prevent another (useless) update to the model, the event generated by the widget has to be swallowed.
In other cases, the model might be more complex and a simple check on what exactly has changed might not be feasible, e.g. a complex tree view.
The standard QT way of dealing with this and also the one suggested in their very useful tutorial is to make the change to the value in the controller only if the new value is different from the current value.
This is way signals have the semantics of valueChanged()
see this tutorial
Usually you should respond to input events in the widget and not to change events. This prevents this type of loop from occuring.
User changes input in the widget
Widget emits change event (scroll done / enter clicked / mouse leave, etc.)
Controller responds, translates to change in the model
Model emits event
Controller responds, changes value in widget
Value change event emitted, but not listened to by controller
Flags to indicate updaing work. You can wrap them in methods like BeginUpdate and EndUpdate.

Resources