Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't navigate from inside a callback method with Prism

I have a small application using WPF and Prism. I have my shell and two modules. I can successfully navigate between them in the "normal fashion" (e.g from a button click) so I know they are wired up for navigation correctly. However, if I perform some asynchronous operation that fires an event on completion, I can't navigate from inside that event handler. The last thing I tried was using Event Aggregation to publish an event back to the UI thread, but it's still not navigating. The Subscriber to the event gets the event successfully and fires RequestNavigate(...) but the UI doesn't update.

Now, some code: The viewmodel for my first module LoginModule:

public class LoginViewModel : ViewModelBase, ILoginViewModel, INavigationAware
{
    ...

    [ImportingConstructor]
    public LoginViewModel(IRegionManager regionManager, IUnityContainer container, IEventAggregator eventAggregator)
    {
        _regionManager = regionManager;
        _container = container;
        _eventAggregator = eventAggregator;
    }

    private DelegateCommand _Login;
    public DelegateCommand Login
    {
        get
        {
            if (_Login == null)
                _Login = new DelegateCommand(() => LoginHandler());
            return _Login;
        }
    }
    private void LoginHandler()
    {
        _client = new JabberClient();
        _client.Server = "gmail.com";
        _client.User = Username;
        _client.Password = Password;

        ...

        _client.OnAuthenticate += client_OnAuthenticate;
        _client.Connect();
    }

    private void client_OnAuthenticate(object sender)
    {
        Console.WriteLine("Authenticated!");
        _eventAggregator.GetEvent<UserAuthenticatedEvent>().Publish("");
    }

    public bool IsNavigationTarget(NavigationContext navigationContext)
    {
        return true;
    }
    ...
}

The ViewModel for my second module RosterModule:

public class RosterViewModel : IRosterViewModel, INavigationAware
{
    private readonly IEventAggregator _eventAggregator;
    private readonly IRegionManager _regionManager;

    [ImportingConstructor]
    public RosterViewModel(IRegionManager regionManager, IEventAggregator eventAggregator)
    {
        _regionManager = regionManager;
        _eventAggregator = eventAggregator;

        _eventAggregator.GetEvent<UserAuthenticatedEvent>().Subscribe(o =>
        {
            Console.WriteLine("Requesting navigation...");
            _regionManager.RequestNavigate(RegionNames.ContentRegion, new Uri(WellKnownViewNames.RosterView, UriKind.Relative));
        });
    }

    public bool IsNavigationTarget(NavigationContext navigationContext)
    {
        return true;
    }

    public void OnNavigatedFrom(NavigationContext navigationContext)
    {

    }

    public void OnNavigatedTo(NavigationContext navigationContext)
    {
        Console.WriteLine("I'm here at the RosterViewModel");
    }
}

Any tips on what I might be doing wrong?

like image 313
LonghornTaco Avatar asked Oct 16 '13 15:10

LonghornTaco


1 Answers

From OP,

Ok, so just a few minutes after posting, I reread an article I ran into yesterday and saw something I missed...

http://neverindoubtnet.blogspot.com/2009/05/event-aggregator-in-prism-explorer.html

They explain that one of the overloads of the Subscribe method includes a ThreadOption.

So:

_eventAggregator.GetEvent<UserAuthenticatedEvent>()
    .Subscribe(
    o =>
    {
        Console.WriteLine("Requesting navigation...");
        _regionManager.RequestNavigate(
            RegionNames.ContentRegion,
            new Uri(WellKnownViewNames.RosterView, UriKind.Relative));
    });

Became:

_eventAggregator.GetEvent<UserAuthenticatedEvent>()
    .Subscribe(
    o =>
    {
        Console.WriteLine("Requesting navigation...");
        _regionManager.RequestNavigate(
            RegionNames.ContentRegion,
            new Uri(WellKnownViewNames.RosterView, UriKind.Relative));
    }, 
    ThreadOption.UIThread);

And now it works!

Hopefully, this helps someone else down the road.

Enjoy!

like image 164
rae1 Avatar answered Nov 02 '22 12:11

rae1