This project is read-only.

Navigation & Windows

Nov 25, 2010 at 8:34 AM
Hi Rishi, i have a windowed gui (mdi) and i want to intercept nroute's navigation system to open uris and their related views in windows. could you please give me a detailed example? where do i add the interception handler? which base should i use for an interception handler? are there any problems with the views and viewmodels? anything else i should pay attention to? many thanks!!
Nov 26, 2010 at 12:37 PM
Edited Nov 27, 2010 at 1:03 PM

Hi, I'm not clear by what you mean by an "interception handler"? Is it like you want to intercept to observe or cancel a navigation request, then you can use Navigating or Navigated events off any built-in Navigation Containers. Or are you looking for creating navigation proxies through which navigation requests get handled? An example of your use-case could help..

Cheers,
Rishi

Nov 27, 2010 at 2:08 PM

Hi Rishi, sorry for the misunderstanding:

Every time a user navigates to a specified uri which is mapped to a displayable content (xaml) a window should be created and the navigation content should be displayed inside this newly created window because i have an mdi interface.

My plan is to embed an invisible StatefulBrowsingContainer which handles the navigation. i'm not interested in displaying the content in the navigation container. I want to override the StatefulBrowsingContainer to create a window

with the navigation content after a successful navigation response.

My questions are:

Is there a better way to handle this scenario? I'm always interested in best practise things...

Which functions should i override to create my desktop window after navigation succeeded? In sl i used  the following two functions: 

void OnFragmentNavigation(FragmentNavigationEventArgs e)  & override void OnNavigatedTo(NavigationEventArgs e)

Are there similar functions in nroute?

Many thanks,

Helmut

Dec 4, 2010 at 6:37 AM

Sorry, I got caught up at work during the week. Well, I think the best approach would be to create a kind of "proxy handler" that would take in a navigation request and open a new window forwarding the same request to the container within. To create a proxy all you need to do is implement INavigationHandler interface - BTW, for v/next I'm trying to see I can bake this approach in the nRoute itself, so like we can have a proxy implementation decorated by [MapNavigationContainer] attribute.

Two other possible ways are: using ViewServices (see http://www.orktane.com/Blog/post/2009/10/23/Web-Xcel-Demo-View-Services-in-nRoute.aspx) or use ControllerActions (see the About window part http://www.orktane.com/Blog/post/2010/07/12/Creating-a-Netflix-App-using-nRoute-again-Now-in-WPF.aspx). 

Let me know if either of the options works for you.
Rishi

Dec 6, 2010 at 10:30 AM

Hi,

thanks for you hints. i took the approach with the "proxy handler"....

what i did was the following:

   [MapViewService(typeof(INavigationManager), InitializationMode = InitializationMode.WhenAvailable,
        Lifetime = ViewServiceLifetime.DiscoveredInstance)]
    public class NavigationContainerEx : NavigationContainer, INavigationManager
    {
        private readonly Queue<NavigationRequest> pendingRequests = new Queue<NavigationRequest>();

        public bool HasPendingRequests
        {
            get
            {
                return this.pendingRequests.Count > 0;
            }
        }

        public void AddPendingRequest(NavigationRequest request)
        {
            this.pendingRequests.Enqueue(request);
        }

        public void ProcessPendingRequests()
        {
            while (this.pendingRequests.Count != 0)
            {
                this.Navigate(this.pendingRequests.Dequeue());
            }
        }

        protected override void OnProcessRequest(NavigationRequest request, Action<bool> requestCallback)
        {
            Contract.Requires(request != null);
            Contract.Requires(requestCallback != null);

            if (ViewServiceLocator.GetViewService<IDesktopManager>() != null)
            {
                base.OnProcessRequest(request, requestCallback);
            }
            else
            {
                // queue navigation requests until the desktopmanager is fully loaded and ready to handle them!
                this.AddPendingRequest(request);
                requestCallback(false);
            }
        }

        protected override void OnProcessResponse(NavigationResponse response)
        {
            Contract.Requires(response != null);

            base.OnProcessResponse(response);

            if ((this.Content != null) && (response.Status == ResponseStatus.Success))
            {
                var desktopManager = ViewServiceLocator.GetViewService<IDesktopManager>();
                Contract.Assert(desktopManager != null);

                var desktop = desktopManager.ActiveDesktop;

                if (desktop == null)
                {
                    desktop = desktopManager.Desktops.Any()
                                  ? desktopManager.Desktops.First()
                                  : desktopManager.CreateDesktop();

                    desktopManager.ActiveDesktop = desktop;
                }

                var content = this.Content;
                this.Content = null;

                var window = desktop.CreateWindow(null, null, content, null);
                window.Uri = new Uri(response.Request.RequestUrl, UriKind.Relative);
                window.UriParameters = response.ResponseParameters;

                object dataContext = null;
                var frameworkElement = content as FrameworkElement;

                if (frameworkElement != null)
                {
                    dataContext = frameworkElement.DataContext;
                }

                var windowLifeCycle = dataContext as IWindowLifeCycle;

                if (windowLifeCycle != null)
                {
                    EventHandler<CancelEventArgs> windowClosing;
                    window.Closing += windowClosing = (s, e) => { windowLifeCycle.Closing(e); };

                    var windowClosed = default(EventHandler);
                    window.Closed += windowClosed = (s, e) =>
                        {
                            window.Closed -= windowClosed;
                            window.Closing -= windowClosing;

                            windowLifeCycle.Closed();
                        };

                    windowLifeCycle.Initialize();
                }

                window.Activate();
            }
        }
    }

Cheers,
Helmut
Dec 8, 2010 at 9:07 AM

Your implementation looks quite comprehensive. Normally a much simpler modal type of approach suffices my needs - for example:

 

public partial class ModalWindowContainer : UserControl, INavigationHandler
{
	public ModalWindowContainer()
	{
		InitializeComponent();
this.closeButton.Click += CloseButton_Click;
}
#region INavigationHandler

	public void ProcessRequest(NavigationRequest request, Action<bool> requestCallback)
	{
		((INavigationHandler)this.navigationContainer).ProcessRequest(request, (b) => 
		{
			if (b) this.Show();			// if request is accepted then show this UI
			requestCallback(b);
		});
	}

	public void ProcessResponse(NavigationResponse response)
	{
		((INavigationHandler)this.navigationContainer).ProcessResponse(response);
	}

#endregion

#region Handlers

	private void CloseButton_Click(object sender, RoutedEventArgs e)
	{
		this.Hide();
	}

#endregion

#region Helpers

	private void Show()
	{
		// _showStoryboard.Begin(); <-- I normally use some kind of animation
		this.Visibility = Visibility.Visible;
	}

	private void Hide()
	{
		// _hideStoryboard.Begin(); <-- I normally use some kind of animation
		this.Visibility = Visibility.Collapsed;
	}

#endregion

}

 

The xaml for the control above would have a navigation container named "navigationContainer", and a close button to hide the control. Also, one can adorn it with some transition effects - the like of which are used in the ModalWindow control.

 

With this control, one needs to declare the control most likely in the shell container: 

<local:ModalWindowContainer Canvas.ZIndex="10">
	<i:Interaction.Behaviors>
		<n:NavigationHandlerBehavior HandlerName="ModalHandler"/>
	</i:Interaction.Behaviors>
</local:ModalWindowContainer>

And to use just navigate into the "ModallHandler" named container. So, this is one other approach - your's is quite valid too.
Rishi 

 

Dec 8, 2010 at 2:43 PM

Hi Rishi,

thanks for your informative example on how to handle modal dialogs.

cheers,

helmut