Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

viewmodel based navigation as first class citzen for all platforms #65

Open
ghuntley opened this issue Jan 21, 2016 · 13 comments
Open

viewmodel based navigation as first class citzen for all platforms #65

ghuntley opened this issue Jan 21, 2016 · 13 comments
Assignees

Comments

@ghuntley
Copy link
Member

Our routing is something that should be overhauled in the future. It is far too prescriptive and platform-specific. ReactiveUI should really provide a general routing mechanism that cares not about how you manifest it in the view. All that logic should be written ​_once_​ (instead of per platform like we have now) and shared with simple shims to integrate at the UI level.

This is a great opportunity to look around and see how others are doing it. @rid00z has mentioned over beers he has suggestions from implementing this type of logic as part of his framework FreshMvvm.

Additionally MvvmCross has the notion of handling this behavior via Presenters

@jcmm33's team has done a significant amount of work on-top of ReactiveUI and have implemented their own presenter solution. Maybe this is a chance to use this implementation as the golden standard and off-load the burden from his team of having to maintain their own.

Suggested leads for this topic are @jcmm33, @rid00z, @codemillmatt and of course @kentcb / @flagbug

@jcmm33
Copy link

jcmm33 commented Jan 28, 2016

Our approach in this area is something that has evolved over quite a while, but it is something that we are now quite happy with in principle, with the occasional tweak as to how we do things.

We started out by pretty much taking the MvvmCross approach namely providing a ViewModelType along with parameter values for the view model and presentation information.

It should however be noted at this point that we operate a convention whereby ViewModel constructors (for presented/navigated ones anyway) don't vary dependant upon the parameters/values required for that view model to work. e.g. if it were a view model showing a users details, then a specific users details wouldn't be provided in the constructor but instead the service/controller/manager capable of looking up a users details would. The actual specific user details would be provided through either view model initialisation (a topic on its own) or say through other method calls/properties on the view model.

e.g.

public class UserDetailsViewModel:RxViewModel
{
    public UserDetailsViewModel(IUserController userController)
    {
    }

    public void Present(Guid userId)
    {
    }
}

It should also be noted that by taking this approach serialization of view models for suspend/resume scenarios becomes very easy to do.

The MvvmCross details on navigation can be seen here in more detail https://github.com/MvvmCross/MvvmCross/wiki/ViewModel--to-ViewModel-navigation

As with MvvmCross we allow for custom presenters to be used instead of the standard ones.

Moving on from this, we started, as a pattern providing simplistic static methods on the appropriate viewmodels to create the presentation request instead of having view models littered with untyped parameters being provided e.g.

public class UserDetailsViewModel:RxViewModel
{
...
public static ViewModelPresentRequest CreateViewRequest(Guid userId)
{
...
}

The underlying presenter is still the same, its just how the parameters are constructed for the presenter.

One final change (we have been doing as of late) is injecting a fully typed presenter into the view models instead. So, instead of constructing a view model request we simply go things like:

ShowAll = ReactiveCommand.CreateAsyncObservable(_ => presenter.ShowSearchResultsFor( _searchInstance, _travelLimit));

Once again, all this presenter does is invoke the appropriate methods to create the view model request and pass it on, but it does provide a clean separation and allows for easy mocking up of presentation services.

Our intention has always been to make all of our work available on github once we are fully happy with it. This is still the case.

It should be noted that this is a highly opinionated framework/library in its approach and the 3rd party libraries used. Our approach has always been to improve delivery and code reliability, not provide some abstract framework which can be mixed and matched at will, so libraries like Autofac and AutoMapper are used heavily and our solution currently depends on these frameworks (especially Autofac) to function.

@ericsink
Copy link

ericsink commented Feb 4, 2016

Warning, possibly dumb question from clueless newbie:

Does @thedillonb have some presenter stuff in CodeHub that is worth mentioning here?

Despite encountering advice from @paulcbetts about using "view first" on iOS/Android, I am investigating ways of using viewmodel based navigation with ReactiveUI for a Xamarin app.

One possibility is to use MvvmCross for the navigation stuff while using ReactiveUI for binding and commands and FRP goodness.

But studying the CodeHub code is, er, interesting.

His BaseViewModel class has a method called NavigateTo()

https://github.com/thedillonb/CodeHub/blob/master/CodeHub.Core/ViewModels/BaseViewModel.cs#L21

In the iOS code, I see stuff like this:

https://github.com/thedillonb/CodeHub/blob/master/CodeHub.iOS/ViewControllers/BaseViewController.cs#L49

These things make me curious. But maybe that's because I've only been looking at ReactiveUI for a few days.

@thedillonb
Copy link

@ericsink, I tried to model CodeHub's VM first paradigm around delegation to the current view. If you've ever looked at other solutions, like MVVMCross, you'll notice that it uses VM first delegation to a common "presenter" which I took as inspiration but found it incredibly limiting since you end up with a big switch statement in a "presenter" class. I believe the more robust way is to simply delegate to the current view on how it wants to present it's child views - thats what you see at https://github.com/thedillonb/CodeHub/blob/master/CodeHub.iOS/ViewControllers/BaseViewController.cs#L49. Delegation to the current view means there's no big switch block and it ends up being extremely simple to test and utilize in other platforms.

That being said, it's just my simple, off-the-top-of-my-head solution which may not work for everyone, but happened to work pretty well in CodeHub.

@glennawatson glennawatson transferred this issue from reactiveui/ReactiveUI May 21, 2019
@open-collective-bot
Copy link

open-collective-bot bot commented May 21, 2019

Hey @ghuntley 👋,

Thank you for opening an issue. We will get back to you as soon as we can. Also, check out our Open Collective and consider backing us.

https://opencollective.com/reactiveui

PS.: We offer priority support for all backers. Don't forget to add priority label when you start backing us 😄

An advanced, composable, functional reactive model-view-viewmodel framework for all .NET platforms!

@weitzhandler
Copy link

Hi all,
As a swear by Prism dev, I find that RxUI doesn't provide enough in terms of navigation and routing. I actually liked the way it worked in Prism with DI INavigationAware and INavigationService, but IScreen and IRoutingViewModel sounds good too.
Can we abstract them out into a separate non-Xamarin.Forms dependent package, to allow for extension and implementation in other platforms?

@glennawatson
Copy link
Contributor

Yeah that's the plan, the work is on-going to separate it out at the moment.

@worldbeater
Copy link
Contributor

worldbeater commented Jun 13, 2019

I actually liked the way it worked in Prism with DI INavigationAware and INavigationService, but IScreen and IRoutingViewModel sounds good too.
Can we abstract them out into a separate non-Xamarin.Forms dependent package, to allow for extension and implementation in other platforms?

Probably missing the context, by what do you mean by that @weitzhandler? Currently, IScreen, RoutingState and IRoutableViewModel interfaces are located in the ReactiveUI core package, and are compatible not only with Xamarin.Forms, but also with UWP, WPF, Avalonia, etc. (RoutedViewHosts implementations exist for almost every platform except Android and iOS)

@weitzhandler
Copy link

@worldbeater I see now, I didn't know that. Will make more research on that. Thanks.

@weitzhandler
Copy link

So what Sextant does is just providing the XF NavigationPage and VM registration?

@glennawatson
Copy link
Contributor

It's a work in progress rewrite of the navigation stack inside RxUI, but the old navigation stack works as well until it's finished. Given it's very work in progress it's likely to change dramatically.

@weitzhandler
Copy link

weitzhandler commented Jun 14, 2019

I'm gonna start off with IScreen and IRoutableViewModel. As new things will come in I'll move on.
BTW, I'm using Splat.DryIoc Can't afford to give up on DI sorry.

@glennawatson
Copy link
Contributor

We added the DI containers to allow people to have a choice :) -- so both the traditional and sextant approach will interop with the registered splat DI container

@weitzhandler
Copy link

Awesome then!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants