Table of contents
Frame
, or ContentControl
, and the views are simply displayed inside these controls. However, there are many scenarios where the purpose of navigation is another kind of control, such as TabControl
, or ListBox
. In such cases, navigation may require activating or highlighting an existing view, or adding a new view.RegionName
property, as shown below.
<ContentControl prism:RegionManager.RegionName="MainRegion" ... />
Region
object, representing the region itself, and a RegionAdapter
object (region adapter), whose task is to control the location and activation of views in a given control element. The Prism Library provides a RegionAdapter
implementation for most Silverlight and WPF controls. You can create your own RegionAdapter
to support additional controls, or to implement special behavior. The RegionManager
class (region manager) provides access to the Region
application objects.
ContentControl
, which can display only one view at a time. In other cases, it can be a control that allows you to display multiple views at once, such as TabControl
, or ListBox
.
TabControl
, the view that is displayed on the highlighted tab is active, in ContentControl
, the one that is currently displayed on the screen.
The note.
Determining which presentation is active is especially important in the navigation process. Often, it may be necessary for an active view to take part in navigation, for example, to save data before the user leaves it, or to request cancellation, or to confirm the operation.
Add
method in the Region
class. The following code shows how you can get a reference to a Region
object through the RegionManager
class, and programmatically add a view to it. In the example, the view is created using the DI container.
IRegionManager regionManager = ...; IRegion mainRegion = regionManager.Regions["MainRegion"]; InboxView view = this.container.Resolve<InboxView>(); mainRegion.Add(view);
RegisterViewWithRegion
method in the RegionManager
class. This method allows you to specify a callback method that will be called when displaying a region with the specified name. The following example shows how you can create a view (using a dependency injection container) when displaying a region named “MainRegion” .
IRegionManager regionManager = ...; regionManager.RegisterViewWithRegion("MainRegion", () => container.Resolve<InboxView>());
RequestNavigate
method defined in the INavigateAsync
interface.
The note.
Despite the name, theINavigateAsync
interfaceINavigateAsync
not imply asynchronous navigation performed in a separate thread. On the contrary,INavigateAsync
implies pseudo-asynchronous navigation. TheRequestNavigate
method may end synchronously after the end of navigation, or it may end before the end of navigation, for example, when the user needs to confirm the navigation. By allowing you to set a callback method during navigation, Prism enables support for such scenarios without the difficulty of handling background threads.
INavigateAsync
interface implements the Region
class, allowing you to initiate navigation in that region.
IRegion mainRegion = ...; mainRegion.RequestNavigate(new Uri("InboxView", UriKind.Relative));
RequestNavigate
method on the RegionManager
object, specifying the name of the region on which you are navigating. This method finds a link to the corresponding region and calls the RequestNavigate
method on it. This is shown in the example below.
IRegionManager regionManager = ...; regionManager.RequestNavigate("MainRegion", new Uri("InboxView", UriKind.Relative));
container.RegisterType<object, InboxView>("InboxView"); regionManager.Regions[Constants.MainRegion].RequestNavigate(new Uri("InboxView", UriKind.Relative));
The note.
When creating a view by a navigation service, it requests an object of typeObject
from a container, with the name provided in the navigation URI. Different containers use different registration mechanisms to support this. For example, in Unity, you need to register the views by associating theObject
type with this view, and providing the registration name that matches the name in the navigation URI. In MEF, you only need to specify the name of the contract in theExportAttribute
attribute.
container.RegisterType<InboxView>("InboxView");
container.RegisterType<object,InboxView>("InboxView");
The note.
The name used for registration and navigation does not have to be associated with the name of the view type, any string will do. For example, instead of a string, you can explicitly use the full name of the type:typeof(InboxView).FullName
;
[Export("InboxView")] public partial class InboxView : UserControl { ... }
The note.
The preceding description illustrates view-first navigation when a URI refers to the name of the view with which it was exported or registered in a container. With view-first navigation, the dependent view model is created as a view dependency. An alternative approach is to use the view model – first navigation when the navigation URI refers to the name of the view model with which it was registered in the container. This approach can be useful when views are defined as data patterns, or when you want the navigation pattern to be defined independently of the views.
RequestNavigate
method also allows you to specify a callback method that will be called when the navigation is completed.
private void SelectedEmployeeChanged(object sender, EventArgs e) { ... regionManager.RequestNavigate(RegionNames.TabRegion, "EmployeeDetails", NavigationCompleted); } private void NavigationCompleted(NavigationResult result) { ... }
NavigationResult
class has properties through which you can get information about the navigation operation. The Result
property indicates whether navigation has completed. If the navigation ended with an error, then the Error
property will contain a reference to any exceptions thrown during the navigation. Through the Context
property, you can access the navigation URI and any parameters it contains, as well as a link to the service that coordinates navigation operations.
INavigationAware
. You can implement this interface in a view, or (more often) in a view model. By implementing it, your view, or view model, can be directly involved in the navigation process.
The note.
In the following description, it is assumed that navigation occurs between views. But it should be noted that theINavigationAware
interface during navigation will be called regardless of whether it is implemented in the view, or in the view model. During navigation, Prism checks whether theINavigationAware
viewINavigationAware
, if so, the necessary methods are called on it. Also, Prism makes a check on the implementation of this interface on the object in which the ViewDataContext
property is set, and, if successful, calls the necessary methods.
INavigationAware
interface:
public interface INavigationAware { bool IsNavigationTarget(NavigationContext navigationContext); void OnNavigatedTo(NavigationContext navigationContext); void OnNavigatedFrom(NavigationContext navigationContext); }
IsNavigationTarget
method allows an existing representation in the region, or a representation model, to show whether it can process a navigation request. This can be useful in cases where you want to reuse an already existing view for navigation processing, or you want to navigate to an already existing view. For example, a view that displays customer information can be updated by selecting different customers. For more information, see the “Navigating to Existing Views” section later in this article.
OnNavigatedFrom
and OnNavigatedTo
are called during a navigation operation. If the current active view in a region (or its view model) implements this interface, the OnNavigatedFrom
method OnNavigatedFrom
called before navigation begins. The OnNavigatedFrom
method allows the previous view to save its state, or prepare for deactivation or deletion from the user interface. For example, a view can save changes made by a user to a database, or send them to a web service.
OnNavigatedTo
method OnNavigatedTo
called after the navigation is completed. The OnNavigatedTo
method allows the view that was just displayed to be initialized, possibly using parameters passed along with the navigation URI. For more information, see the next section, “Passing Parameters During Navigation.”
IRegionMemberLifetime
interface that allows you to control the lifetime of views in regions, asking whether you should immediately remove deactivated views from a region, or simply mark them as deactivated.
public class EmployeeDetailsViewModel : IRegionMemberLifetime { public bool KeepAlive { get { return true; } } }
IRegionMemberLifetime
interface defines the only KeepAlive
property that is read-only. If it is set to false
, the view will be removed from the region when it is deactivated. Since the region then stops storing the link to the view, it will be accessible to the garbage collector (unless, of course, other parts of your application reference it). You can implement this interface in both the view and the view model. Although the IRegionMemberLifetime
interface IRegionMemberLifetime
intended, for the most part, to control the lifetime of views in regions during activation and deactivation, the KeepAlive
property is also used during navigation after creating and activating a view in the target region.
The note.
, ,ItemsControl
,TabControl
, , . , , .
NavigationContext
provides access to the navigation URI and to all parameters that were passed along with it. You can get access to NavigationContext
in the way IsNavigationTarget
, OnNavigatedFrom
and OnNavigatedTo
.
UriQuery
. You can use it if necessary to add navigation parameters to the URI before starting navigation and to access these parameters during navigation. UriQuery
creates a list with name-value pairs for each parameter.
UriQuery
and attach them to the navigation URI.
Employee employee = Employees.CurrentItem as Employee; if (employee != null) { UriQuery query = new UriQuery(); query.Add("ID", employee.Id); _regionManager.RequestNavigate(RegionNames.TabRegion, new Uri("EmployeeDetailsView" + query.ToString(), UriKind.Relative)); }
Parameters
object property NavigationContext
. This property returns an instance of a class UriQuery
that has an indexing property to simplify access to individual parameters.
public void OnNavigatedTo(NavigationContext navigationContext) { string id = navigationContext.Parameters["ID"]; }
EditCustomer
, and the user already uses this view to edit the client with ID 123. If the user decides to edit the client record with ID 456, he can simply navigate to submissionEditCustomer
and enter a new ID. After that, the view EditCustomer
will request information about the new client and update its UI accordingly.
EditCustomer
in TabControl
, for example, clients with ID 123 and ID 456. When you navigate to EditCustomer
and enter ID 456, the corresponding view will be activated (that is, the corresponding tab will be highlighted). If the user navigates to the view EditCustomer
and enters ID 789, then a new instance will be created and displayed in the UI.
INavigationAware.IsNavigationTarget
. This method is called during navigation on views in the region that have the same type as the target view. In the previous example, the target representation was of type EditCustomer
, so the method IsNavigationTarget
will be called on all existing representations of typeEditCustomer
located in the region. Prism determines the target presentation type using a navigation URI, assuming that it is the short name of the target representation type.
The note.
In order for Prism to determine the type of the target view, the name of the view in the navigation URI must match the short name of its type. For example, if a view has a classMyApp.Views.EmployeeDetailsView
, then the name of the view specified in the navigation URI should be EmployeeDetailsView . This is the standard behavior of Prism. You can change it by creating your content loader class. You can do this by implementing an interfaceIRegionNavigationContentLoader
, or by inheriting your class fromRegionNavigationContentLoader
.
IsNavigationTarget
can use a parameter NavigationContext
to determine if the view can process the navigation request. NavigationContext
gives access to the navigation URI and navigation parameters. In the previous example, the implementation of this method in the view model EditCustomer
compared the current client ID with the ID specified in the navigation query, returning true
if it matches.
public bool IsNavigationTarget(NavigationContext navigationContext) { string id = navigationContext.Parameters["ID"]; return _currentCustomer.Id.Equals(id); }
IsNavigationTarget
always returns true
, regardless of the navigation parameters, this view will always be reused. Such an approach can guarantee that in a certain region there will be only one representation of a certain type.
IConfirmNavigationRequest
.
IConfirmNavigationRequest
inherits from the interface INavigationAware
and adds a methodConfirmNavigationRequest
. By implementing this interface in your view, or view model, you allow them to participate in the navigation process, allowing you to interact with the user so that he can cancel or confirm the navigation. You may also need to use the Interaction Request object , which was discussed in Part 6, MVVM Advanced Scenarios , to display a confirmation popup window.
The note.
The methodConfirmNavigationRequest
is called on the active view (or view model), similar to the methodOnNavigatedFrom
described earlier.
ConfirmNavigationRequest
takes two parameters, a reference to the current navigation context described above, and a delegate that must be called to continue navigation. For this reason, this delegate is often called the continuation callback . You can save a reference to the delegate-continuation, to call it after the end of user interaction. If an application interacts with the user through Interaction Request objects , you can use this delegate as the callback method of the interaction request. The following diagram illustrates the complete process.
InteractionRequest
:
RequestNavigate
.IConfirmNavigation
, ConfirmNavigationRequest
.ComposeEmailView
, and ComposeEmailViewModel
. The view model class implements the interface IConfirmNavigation
. If the user navigates, for example, by pressing the Calendar button , at the time of creating the message, a method will be invoked ConfirmNavigationRequest
so that the view model can request confirmation from the user. To support this, the view model sets the interaction request object, as shown in the example below.
public class ComposeEmailViewModel : NotificationObject, IConfirmNavigationRequest { private readonly InteractionRequest<Confirmation> confirmExitInteractionRequest; public ComposeEmailViewModel(IEmailService emailService) { this.confirmExitInteractionRequest = new InteractionRequest<Confirmation>(); } public IInteractionRequest ConfirmExitInteractionRequest { get { return this.confirmExitInteractionRequest; } } }
ComposeEmailVew
trigger InteractionRequestTrigger
attached to ConfirmExitInteractionRequest
the view model property . When an interaction is requested, a simple popup window is shown to the user.
<UserControl.Resources> <DataTemplate x:Name="ConfirmExitDialogTemplate"> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding}"/> </DataTemplate> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White"> <ei:Interaction.Triggers> <prism:InteractionRequestTrigger SourceObject="{Binding ConfirmExitInteractionRequest}"> <prism:PopupChildWindowAction ContentTemplate="{StaticResource ConfirmExitDialogTemplate}"/> </prism:InteractionRequestTrigger> </ei:Interaction.Triggers> ...
ConfirmNavigationRequest
class method ComposeEmailVewMode
is invoked when a user attempts to navigate while writing a message. The implementation of this method triggers the interaction request defined earlier, so that the user can confirm or change the navigation operation.
void IConfirmNavigationRequest.ConfirmNavigationRequest( NavigationContext navigationContext, Action<bool> continuationCallback) { this.confirmExitInteractionRequest.Raise( new Confirmation {Content = "...", Title = "..."}, c => {continuationCallback(c.Confirmed);}); }
Confirmed
, which forces it to confirm or cancel the navigation.
.
,Rise
,ConfirmNavigationRequest
, UI . OK , Cancel , , , , - . UI. .
true
, to cancel the navigation, you must pass false
.
void IConfirmNavigationRequest.ConfirmNavigationRequest( NavigationContext navigationContext, Action<bool> continuationCallback) { continuationCallback(true); }
NavigationContext
provides access to the region’s navigation service, which is responsible for coordinating the sequence of operations during navigation in the region. It provides access to the region in which you are navigating, and to the navigation log associated with that region. The navigation service implements the interface IRegionNavigationService
shown below.
public interface IRegionNavigationService : INavigateAsync { IRegion Region { get; set; } IRegionNavigationJournal Journal { get; } event EventHandler<RegionNavigationEventArgs> Navigating; event EventHandler<RegionNavigationEventArgs> Navigated; event EventHandler<RegionNavigationFailedEventArgs> NavigationFailed; }
INavigateAsync
, you can initiate navigation in the parent region by calling the method RequestNavigate
. The event Navigating
is triggered when a navigation operation is initiated. The event Navigated
is triggered when navigation is completed in the region. NavigationFailed
called when an error occurs during navigation.
Journal
gives access to the navigation log associated with the region. The navigation log implements the interface IRegionNavigationJournal
shown below.
public interface IRegionNavigationJournal { bool CanGoBack { get; } bool CanGoForward { get; } IRegionNavigationJournalEntry CurrentEntry { get; } INavigateAsync NavigationTarget { get; set; } void Clear(); void GoBack(); void GoForward(); void RecordNavigation(IRegionNavigationJournalEntry entry); }
OnNavigatedTo
. By default, Prism provides a simple stack log that allows you to navigate back and forth within a region.
GoBack
that uses the navigation log of the parent region. Consequently, the view can display the Back button , which allows the user to move to the previous view in the region. Similarly, you can implement a command GoForward
to create a wizard-style workflow (wizard style workflow ).
public class EmployeeDetailsViewModel : INavigationAware { ... private IRegionNavigationService navigationService; public void OnNavigatedTo(NavigationContext navigationContext) { navigationService = navigationContext.NavigationService; } public DelegateCommand<object> GoBackCommand { get; private set; } private void GoBack(object commandArg) { if (navigationService.Journal.CanGoBack) { navigationService.Journal.GoBack(); } } private bool CanGoBack(object commandArg) { return navigationService.Journal.CanGoBack; } }
The note.
The navigation log can be used only in navigation operations in the region, which are coordinated by the navigation service of the region. If you use a detection or deployment technique to implement navigation in a region, the navigation log will not be updated during navigation and cannot be used to navigate backward or forward in a region.
Frame
. Frame
may, if necessary, display an address bar that allows the user to navigate backward or forward between the views displayed in Frame
. The usual approach is to use the Silverlight navigation framework to implement high-level navigation in the application shell and use the Prism navigation for all other parts of the application. In this case, your application will support deep links and will be integrated with the browser’s browser and its address bar, and will also enjoy all the benefits of navigation in the Prism regions.
Frame
that has similar functionality in terms of logging and navigation UI. You can use the WPF navigation framework with Prism navigation, although implementing navigation using only Prism regions may be a simpler and more flexible solution.
Source: https://habr.com/ru/post/182052/