ReactiveUI.Routing Pattern

873 views
Skip to first unread message

Wayne

unread,
May 30, 2013, 7:48:26 AM5/30/13
to reacti...@googlegroups.com
Hello

I'm looking for some guidance on how to nicely pass parameters from page to page in a Windows Store App. Let's say I have a search page with lots of options, and would like the search results to be on a different page. How to I send the search parameters collected from the search page to the search results page?

Navigation is easy:
Search.Subscribe(_ => screen.Router.Navigate.Execute(RxApp.GetService<ISearchResultsViewModel>()));

Ideally, I'd like to be able to do:
Search.Subscribe(_ => screen.Router.Navigate.Execute(RxApp.GetService<ISearchResultsViewModel>(), InstanceOfClassWithSearchParameters));
The SearchResultsViewModel would then have to accept an InstanceOfClassWithSearchParameters somehow. The AdventureWorksShopper LOB App which is based on Prism has a base ViewModel class which has an overrideable OnNavigatedTo method which accepts an "object navigationParameter" that effectively allows this. The ReactiveUI WhenNavigatedTo takes no parameter.

Here's what I have right now:
            Search.Subscribe(
                _ =>
                {
                    var searchResults = RxApp.GetService<ISearchResultsViewModel>();
                    searchResults.SearchParameters = InstanceOfClassWithSearchParameters;
                    screen.Router.Navigate.Execute(searchResults);
                });
The SearchResultsViewModel then subscribes to this.WhenAny(SearchParameters) in its constructor.

Another option is
            Search.Subscribe(
                _ =>
                {
                    RxApp.GetService<IApp>().CurrentSearchParameters = InstanceOfClassWithSearchParameters;
                    screen.Router.Navigate.Execute(RxApp.GetService<ISearchResultsViewModel>(), InstanceOfClassWithSearchParameters);
                });
And then in my SearchResultsViewModel fetch the CurrentSearchParameters from IApp on WhenNavigatedTo. I could imagine that wouldn't work if I want to send SearchParameters from the Search Charm and the SearchResults page is already open.

What pattern are people using? Or have I completely missed something that ReactiveUI offers? Right now I'm trying to only use ReactiveUI features rather than bringing in MVVM Light or Caliburn Micro.


A second question, if I may. How different will ReactiveUI 5.x be from ReactiveUI 4.6? Right now I see ReactiveUI 5.0 alpha, but not for WinRT. What is the timeline for a 5.0 release?

Cheers
Wayne

Wayne

unread,
May 30, 2013, 10:33:13 AM5/30/13
to reacti...@googlegroups.com
Sorry, a CopyPaste problem, the last code snippet should read:

Another option is
            Search.Subscribe(
                _ =>
                {
                    RxApp.GetService<IApp>().CurrentSearchParameters = InstanceOfClassWithSearchParameters;
                    screen.Router.Navigate.Execute(RxApp.GetService<ISearchResultsViewModel>());

Paul Betts

unread,
May 30, 2013, 1:01:13 PM5/30/13
to reacti...@googlegroups.com
Hi Wayne,

How about just:

Search.Subscribe(_ =>
screen.Router.Navigate.Execute(new SearchResultsViewModel(ViewModel.SearchResults)));

In this case, your search results aren't really a "service", so looking it up
via service location doesn't make much sense. ViewModels themselves aren't
usually the thing you should be mocking - the thing you want to mock are
Models and interfaces that represent the actual work being done (i.e.
ILoginApi, ISearchApi, etc.)

> A second question, if I may. How different will ReactiveUI 5.x be from
> ReactiveUI 4.6? Right now I see ReactiveUI 5.0 alpha, but not for WinRT.
> What is the timeline for a 5.0 release?

ReactiveUI 5.x supports WinRT, but the old reactiveui-winrt package name is
deprecated. This package came from the days when NuGet didn't really grok
Windows Store apps. In RxUI 5.0 you should just use the ReactiveUI package.

As to how different, while the concepts fundamentally haven't changed much,
there has been a ton of breaking changes that generally result in a smaller,
cleaner ReactiveUI, at the expense of existing apps will probably have to do a
lot of fixups.

Here's what's new / changed:
https://github.com/reactiveui/ReactiveUI/pull/219#issuecomment-18094531

--
Paul Betts <pa...@paulbetts.org>
> --
> You received this message because you are subscribed to the Google Groups "ReactiveUI mailing list" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to reactivexaml...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.

Wayne

unread,
May 30, 2013, 2:11:33 PM5/30/13
to reacti...@googlegroups.com
Hi Paul, 

Thanks for reply. Always reliably quick ;-)


In this case, your search results aren't really a "service", so looking it up
via service location doesn't make much sense. ViewModels themselves aren't
usually the thing you should be mocking - the thing you want to mock are
Models and interfaces that represent the actual work being done (i.e.
ILoginApi, ISearchApi, etc.)

Okay, yes you're right I've no need to mock my SearchResultsViewModel. Of course I want to _test_ it, but I've no need to _mock_ it. Creating an instance in this way means that dependency injection doesn't come into play, so I have to pass in my screen instance and so on explicitly, but that's not a problem.

I've been looking at other ReactiveUI examples out there, and maybe following patterns without understanding them. So if there's no use in mocking a ViewModel, then why bother creating an interface for it? Why is the goal of, for example, your IPlayViewModel?
 
ReactiveUI 5.x supports WinRT, but the old reactiveui-winrt package name is
deprecated. This package came from the days when NuGet didn't really grok
Windows Store apps. In RxUI 5.0 you should just use the ReactiveUI package.

Okay, thanks. However I tried to install 5.0 using "Install-Package ReactiveUI -pre", and got the following error message:
Install-Package : Could not install package 'NLog 2.0.1.2'. You are trying to install this package into a project that targets '.NETCore,Version=v4.5', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author.

As to how different, while the concepts fundamentally haven't changed much,
there has been a ton of breaking changes that generally result in a smaller,
cleaner ReactiveUI, at the expense of existing apps will probably have to do a
lot of fixups.

So over the past year I've spent very small amounts of time on very random occasions trying to learn about Rx and ReactiveUI. I never really had an opportunity to use it for productive code. Now I've set up my own company, and ReactiveUI will be the basis for all of our development for UI Apps. I'm excited by the planned support for Xamarin on iOS and Android (I've yet to play with MonoTouch/Xamarin yet, but the idea of being able to code for all platforms in C# is very cool). Given that my current Windows Store Apps won't be productive for a couple of months yet, would it be worthwhile to switch to 5.0-aplha now to save having to refactor and having to learn how the new ReactiveUI works?

Thanks for all your work on ReactiveUI. It's very awesome. Maybe a bit overwhelming for the average or below average developer to work with, but that's mostly the fault of the Rx concepts, not ReactiveUI. I personally like way it works my brain, and enables such elegant code to be written.

Cheers
Wayne 

Paul Betts

unread,
May 30, 2013, 2:39:43 PM5/30/13
to ReactiveUI mailing list
> I've been looking at other ReactiveUI examples out there, and maybe following
> patterns without understanding them. So if there's no use in mocking a
> ViewModel, then why bother creating an interface for it? Why is the goal of,
> for example, your IPlayViewModel?

Not all of my ideas are good ones :)  In this case, it was theoretically
useful for Blendability. In RxUI 5.x, these kinds of interfaces will be super
useful for scaffolding (i.e. all you have to do is write that Interface and
you can generate the ViewModel and View for it by running a command)

Really, Play was an exercise in trying to write 100% tested code using mocks.
But, the more I used it, the more I realized that mocking ViewModels isn't
usually very interesting, compared to being able to mock IPlayApi for example.

> However I tried to install 5.0 using "Install-Package ReactiveUI -pre", and
> got the following error message

hwhoops. In the meantime, try:

Install-Package ReactiveUI-Mobile ReactiveUI-Events -pre 

ReactiveUI the package, is just a metapackage (i.e. a package that has no
content of its own, it only pulls in other packages) for people to get all the pieces
in one go.

> Given that my current Windows Store Apps won't be productive for a couple of
> months yet, would it be worthwhile to switch to 5.0-aplha now to save having
> to refactor and having to learn how the new ReactiveUI works?

If you're willing to be Brave™, it's definitely usable for production code -
right now it's being used in my VS Extension SaveAllTheTime
(http://xpaulbettsx.github.io/SaveAllTheTime) and it's worked pretty well.

> ReactiveUI will be the basis for all of our development for UI Apps.
> Thanks for all your work on ReactiveUI. It's very awesome. Maybe a bit
> overwhelming for the average or below average developer to work with, but
> that's mostly the fault of the Rx concepts, not ReactiveUI. I personally
> like way it works my brain, and enables such elegant code to be written.

Wow, thanks!

-- 
Paul Betts <pa...@paulbetts.org>


Wayne

unread,
May 31, 2013, 5:28:32 AM5/31/13
to reacti...@googlegroups.com
Hi Paul

I've been thinking about this a bit more, and rather struggling. I'm not sure I like 'new'ing this SearchResultsViewModel.I don't mind 'new'ing ViewModels which are simple derived representations of my models, but not the ViewModels behind my pages.

To summarise the situation:
- the SearchViewModel is the ViewModel for the SearchPage, which simply collects the parameters for the search
- the SearchResultsViewModel is the ViewModel for the SearchResultsPage. This executes the Search over the ISearchApi. It can be navigated to from either the SearchPage or the Search charm.

The SearchResultsViewModel obviously needs the ISearchApi. I generally like to inject this into the constructor this via IOC rather than fetching it from the IOC container. In my experience, passing around the IOC container, or using a CommonServiceLocator causes a loss of visibility of what a class' dependencies are - the IOC container becomes a "bag of holding", and you can't see what's the in the bag.

So, if I were to 'new' the SearchResultsViewModel, then I have to explicitly pass in the ISearchApi into the constructor. But then my SearchViewModel would then have to the ISearchApi injected simply to be able to pass it on. From my perspective, the SearchViewModel shouldn't have to know about all the SearchResultViewModel's dependencies.

What I've found to be unique about ReactiveUI's routing, is that the Navigate.Execute() takes a class instance. A quick look at how other frameworks are doing routing shows that the Navigate() methods often take a Type. I think the following is what I need:
From SearchViewModel:
    screen.Router.Navigate.Execute(ISearchResultsViewModel, searchParameters); // Execute method signature is Execute(Type, object parameters)

Then in my SearchResultsViewModel:
    this.WhenNavigatedTo().Subscribe(x => {}); // x is my searchParameters
In this case, WhenNavigatedTo would be something like:
    IObservable<object> WhenNavigatedTo<TViewModel>(this TViewModel viewModel) where TViewModel : class, IRoutableViewModel

I'm not sure if my ideas are completely down the wrong path, that's why I'm posting here to get your (and hopefully the opinion of others out there!). If my ideas are not wrong, I have two options:to implement something like I need myself (I'd be injecting my own router to my ViewModels), or I could bring in another MVVM framework to help with this (which I'm trying to avoid).

Thanks for reading, and I appreciate any input on my ideas.

Cheers
Wayne

Wayne

unread,
May 31, 2013, 7:21:10 AM5/31/13
to reacti...@googlegroups.com
Sorry, a mistake in the last message. It should read:
    screen.Router.Navigate.Execute(typeof(ISearchResultsViewModel), searchParameters); // Execute method signature is Execute(Type, object parameters)

-Wayne
Reply all
Reply to author
Forward
0 new messages