Publishing ViewNavigationArgs with parameters

Mar 6, 2011 at 11:59 PM

Hi 

I am trying to work out where the best place to pass parameters to a View 

e.g.

EventAggregator.Publish(new ViewNavigationArgs("MyView")); 

Where MyView can take a parameter (akin to the Navigation Framework or web QueryString e.g.

/index.html#MyView?id=1

Perhaps I'm barking up the wrong tree, but it was my understanding that this should/could be done using the same EventAggregator - perhaps by extending the ViewNavigationArgs such as:

EventAggregator.Publish(new ViewNavigationArgs("MyView") { id = 1 }); 

I know Jounce doesn't tie you down to a method of navigation and in some cases we want the freedom of loading individual controls rather than changing the page etc. - actually in the MyView case we want to load in a parameterised child control (as opposed to navigating to a new page). Just not 100% sure where the best place is for this messaging!

Thanks

Gus

Coordinator
Mar 7, 2011 at 1:20 AM

I've never been a fan of the querystring method. Silverlight is an application, not a set of web pages, so I never understand the reasoning behind trying to force one navigation model into the other. I far prefer to look at it as an application and avoid artificial constructs like query stings to pass data.

I'm not sure I completely understand the use case but I can tell you the way I always pass parameters is either using the event aggregator or via direct messaging between view models. For example, if I need to pass an id to a child view, I'll call a method on the view model and pass the id. The view model can pick up the id and store it, so when the view is navigated, the id is available for reference. Does that address your scenario or am I missing the mark?

Thanks,

Jeremy

Mar 7, 2011 at 7:30 AM

I guess the querystring method stems from browser-based functionality (i.e. Back button & bookmarking) and to some extent SEO (admittedly an ID doesn't do much for SEO, but can be mapped)

I'll go with direct messaging; easy enough to implement

You probably didn't understand the use case as it was 1am when I posted this, probably also something to do with me not thinking through the options straight ;-) 

Thanks for the prompt response!

Gus

Mar 7, 2011 at 8:32 AM
Edited Mar 7, 2011 at 8:36 AM

Hi Jeremy,

correct me if I'm wrong but your recommendation feels like you're suggesting the equivalent of ditching parameterized method calls and rather using property setters and parameterless methods in normal OO-programming.

Maybe it would be a good idea to offer an object-typed tag in ViewNavigationArgs that gets passed to a RegionAdapter (see P.S.) and to the targeted ViewModel in its _Activate(...) method as a simple way of achieving parameterized View navigation?

Regards,
DrJ

 

P.S.: Slightly different subject - but this discussion reminds me of my request from a while back to add a parameter to ViewNavigationArgs that can be used to select a transition animation in the RegionAdapter rather than in the individual Views.

Mar 7, 2011 at 9:07 AM

Hi DrJ

I think you're right about the similarities; just had a look back and found your post:

eventAggregator.Publish(new ViewNavigationArgs(journal.CurrentEntry.Step) { Mode = "forward" });

in your discussion is identical in function to my idea:

EventAggregator.Publish(new ViewNavigationArgs("MyView") { id = 1 }); 

Obviously the parameters are acted on differently.

Did you ever use this? 

Our navigation is dynamically built, and the parameter needs to bound; seems like it would be easiest following something like the above? 

I actually started creating a NavigationContext class with string (View) and object (whatever) as public properties which could then be used in lieu of a simple string:

public IActionCommand<NavigationContext> NavigateCommand { get; private set; }

But this feels wrong, think I prefer using the eventAggregator. Not sure if that is explained very well..

Regards,

Gus

Mar 7, 2011 at 2:31 PM
Edited Mar 7, 2011 at 2:37 PM

Hi Gus,

good to see that someone else is making use of Jounce's navigation feature in a non-trivial context.

I am indeed using the parameterized navigation feature described in my earlier posts in a custom modification of Jounce where the ViewNavigationArgs's additional string-typed "Mode" property is routed through the ViewModelRouter infrastructure to a RegionAdapter which then chooses between one of several possible transition animation effects.

This was the least invasive extension that suited my needs and I didn't feel I needed to change ViewNavigationArgs' parameter type to an explicit NavigationContext class for just one additional string parameter. Exchanging the string-typed "Mode" property for an object-typed "Context" property would be the more general solution, of course.

Cheers,
DrJ

 

P.S. ... and looking at the issues list our humble plea has already been listened to. Thanks Jeremy

Mar 7, 2011 at 2:57 PM

I've voted on the issues list; thanks Jeremy! 

DrJ > how/where did you retrieve your "Mode" property from your ViewModel? Can you elaborate on how you routed it through the ViewModelRouter? 

Many thanks
Gus

 

Coordinator
Mar 7, 2011 at 3:15 PM

Yes, I added it. I wouldn't say I've used it in a non-trivial context, I just take a different approach and use viewmodel communication to pass parameters and view navigation to activate views. However, I do see the point in encapsulating it into a single process, so I've added it as a feature to vote. Thanks everyone for taking the time to share the insights and use cases for these!

Mar 8, 2011 at 5:08 PM
jeremylikness wrote:

... I wouldn't say I've used it in a non-trivial context, ...

Sorry, didn't mean to sound rude.

@Gus:

Actually the only changes I had to make in Jounce's infrastructure were in the ViewRouter rather than in the ViewModelRouter. In its HandleEvent method I needed to pass the additional ViewNavigationArgs parameters into the _ActivateView method which in turn had to be extended with an additional parameter.

This in turn allows all of the region adapters to be notified about the additional payload on the view activation request and act accordingly.

If I globally replace the "string Mode" parameter that I currently use with an "object Payload" parameter my modification will turn into a valid implementation of to Jeremy's issue entry. The change is really trivial - I could provide the sources, however, if anyone were interested to see them.

Oct 30, 2012 at 6:53 AM

hello i have not found an example to navigate with parameters

i usually use this for mu vm Menu to navigate to my views

private void showDP(string obj)       

{           

EventAggregator.Publish(new ViewNavigationArgs("vDP"));       

}

 but now i need to pass a parameter to filter the view

i saw this example 

EventAggregator.Publish(view.AsViewNavigationArgs().AddNamedParameter("Guid", Guid.NewGuid()));

 

but i don't know how to add a parameter the way i use the EventAggregator.Publish

could you help me?

thanks in advance!

Nov 5, 2012 at 8:54 AM

duvo, I do this:

private void showDP(string obj) 
{
    EventAggregator.Publish(new ViewNavigationArgs("vDP"));
    Router.ActivateView("vDP", new Dictionary<string, object>()
    {
        { "FilterString", obj }
    });
}

Jul 9, 2013 at 10:32 AM
Hi,

I am trying to publish to a new view (LoginPage.xaml) from MainViewModel. The view loads into the region properly, but the corresponding view-model does not get initialized (breakpoint is not being hit in the LoginViewModel) and any changes I make to the view from the UI is not getting reflected.

MainPage loads successfully and it also interacts with the MainViewModel. But when I try navigate to LoginPage.xaml, the view loads but does not interact with LoginViewModel.

Please help.
Kindly let me know if you need any more info on the same.

Thanks.

MainViewModel.cs:
public void NavigateToLogin(object parameter)
{
    Dictionary<string, object> paramdict = new Dictionary<string, object>();

    EventAggregator.Publish(new ViewNavigationArgs("LoginPage", paramdict)
        .AddNamedParameter("UserName", "RKD"));
}
MainPage.xaml
<UserControl x:Class="JounceSilverlightDemo.MainPage"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:Regions="clr-namespace:Jounce.Regions;assembly=Jounce" 
             xmlns:ViewModels="clr-namespace:JounceSilverlightDemo.ViewModels" mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="400">

    <!--d:DataContext="{d:DesignInstance ViewModels:MainViewModel, IsDesignTimeCreatable=True}"-->
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>

        <StackPanel Orientation="Horizontal">
        <TextBox Text="{Binding BindingTest, Mode=TwoWay}" Width="200" Margin="5" VerticalAlignment="Center" />
        <Button Content="Nav" VerticalAlignment="Center" Margin="5" Command="{Binding NavCommand}" />
        </StackPanel>
        
        <ContentControl Name="contLogin" Grid.Row="1" 
                        VerticalAlignment="Stretch" HorizontalAlignment="Stretch" 
                        HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" 
                        Regions:ExportAsRegion.RegionName="LoginRegion">
        </ContentControl>
    </Grid>
</UserControl>
MainPage.xaml.cs
[ExportAsView(typeof(MainPage), IsShell = true)]
public partial class MainPage
{
    public MainPage()
    {
        InitializeComponent();
    }

    [Export]
    public ViewModelRoute Binding
    {
        get { return ViewModelRoute.Create<MainViewModel, MainPage>(); }
    }
}
LoginPage.xaml.cs
[ExportAsView("LoginPage")]
[ExportViewToRegion("LoginPage", "LoginRegion")]
public partial class Login : UserControl
{
    public ViewModelRoute Binding
    {
        get { return ViewModelRoute.Create("LoginVM", "LoginPage"); }
    }
}
LoginViewModel.cs
[ExportAsViewModel("LoginVM")]
public class LoginViewModel : BaseViewModel, IPartImportsSatisfiedNotification
{
    ...
}
Jul 9, 2013 at 12:01 PM
public void NavigateToLogin(object parameter)
{
    Dictionary<string, object> paramdict = new Dictionary<string, object>();

    EventAggregator.Publish(new ViewNavigationArgs("LoginPage", paramdict)
        .AddNamedParameter("UserName", "RKD"));
    Router.ActivateView("LoginPage", paramdict);
}