Prism(八) 导航

源码地址 - WineMonk/PrismStudy: Prism框架学习 (github.com)

导航基础

视图

ViewA/B.xaml

1
2
3
4
5
6
7
8
9
10
<UserControl x:Class="ModuleA.Views.ViewA"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True">
<StackPanel>
<TextBlock Text="{Binding Title}" FontSize="48" HorizontalAlignment="Center" VerticalAlignment="Center" />
<TextBlock Text="{Binding PageViews}" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</StackPanel>
</UserControl>

ViewA/BViewModel.cs

1
2
3
4
5
6
7
public class ViewAViewModel : BindableBase
{
public ViewAViewModel()
{

}
}

注册导航视图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class ModuleAModule : IModule
{
public void OnInitialized(IContainerProvider containerProvider)
{

}

public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<ViewA>();
containerRegistry.RegisterForNavigation<ViewB>();
}
}

public partial class App : PrismApplication
{
protected override Window CreateShell()
{
return Container.Resolve<MainWindow>();
}

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{

}

protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
{
moduleCatalog.AddModule<ModuleA.ModuleAModule>();
}
}

导航视图

MainWindow.xaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<Window x:Class="BasicRegionNavigation.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
Title="{Binding Title}" Height="350" Width="525">
<DockPanel LastChildFill="True">
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Margin="5" >
<Button Command="{Binding NavigateCommand}" CommandParameter="ViewA" Margin="5">Navigate to View A</Button>
<Button Command="{Binding NavigateCommand}" CommandParameter="ViewB" Margin="5">Navigate to View B</Button>
</StackPanel>
<ContentControl prism:RegionManager.RegionName="ContentRegion" Margin="5" />
</DockPanel>
</Window>

MainWindowViewModel.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class MainWindowViewModel : BindableBase
{
private readonly IRegionManager _regionManager;

private string _title = "Prism Unity Application";
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}

public DelegateCommand<string> NavigateCommand { get; private set; }

public MainWindowViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;

NavigateCommand = new DelegateCommand<string>(Navigate);
}

private void Navigate(string navigatePath)
{
if (navigatePath != null)
_regionManager.RequestNavigate("ContentRegion", navigatePath);
}
}

导航视图请求回调

MainWindowViewModel.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class MainWindowViewModel : BindableBase
{
private readonly IRegionManager _regionManager;

private string _title = "Prism Unity Application";
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}

public DelegateCommand<string> NavigateCommand { get; private set; }

public MainWindowViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;

NavigateCommand = new DelegateCommand<string>(Navigate);
}

private void Navigate(string navigatePath)
{
if (navigatePath != null)
// _regionManager.RequestNavigate("ContentRegion", navigatePath);
_regionManager.RequestNavigate("ContentRegion", navigatePath, NavigationComplete);
}

/// <summary>
/// 导航请求回调方法
/// </summary>
/// <param name="result">导航结果</param>
private void NavigationComplete(NavigationResult result)
{
System.Windows.MessageBox.Show(String.Format("Navigation to {0} complete. ", result.Context.Uri));
}
}

视图察觉参与导航

ViewA/B.xaml

1
2
3
4
5
6
7
8
9
10
<UserControl x:Class="ModuleA.Views.ViewA"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True">
<StackPanel>
<TextBlock Text="{Binding Title}" FontSize="48" HorizontalAlignment="Center" VerticalAlignment="Center" />
<TextBlock Text="{Binding PageViews}" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</StackPanel>
</UserControl>

ViewA/BViewModel.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class ViewAViewModel : BindableBase, INavigationAware
{
private string _title = "ViewA";
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}

private int _pageViews;
public int PageViews
{
get { return _pageViews; }
set { SetProperty(ref _pageViews, value); }
}

public ViewAViewModel()
{

}

/// <summary>
/// 当实现者被导航到时调用。
/// </summary>
/// <param name="navigationContext">导航上下文</param>
public void OnNavigatedTo(NavigationContext navigationContext)
{
PageViews++;
}

/// <summary>
/// 调用以确定此实例是否可以处理导航请求。
/// </summary>
/// <param name="navigationContext">导航上下文</param>
/// <returns>如果这个实例接受导航请求,返回True;否则,False(将会导航至此视图的新实例)</returns>
public bool IsNavigationTarget(NavigationContext navigationContext)
{
return true;
}

/// <summary>
/// 当实现者被导航离开时调用。
/// </summary>
/// <param name="navigationContext">导航上下文</param>
public void OnNavigatedFrom(NavigationContext navigationContext)
{

}
}

通过参数导航

Model

Person.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
public class Person : INotifyPropertyChanged
{
#region Properties

private string _firstName;
public string FirstName
{
get { return _firstName; }
set
{
_firstName = value;
OnPropertyChanged();
}
}

private string _lastName;
public string LastName
{
get { return _lastName; }
set
{
_lastName = value;
OnPropertyChanged();
}
}

private int _age;
public int Age
{
get { return _age; }
set
{
_age = value;
OnPropertyChanged();
}
}

private DateTime? _lastUpdated;
public DateTime? LastUpdated
{
get { return _lastUpdated; }
set
{
_lastUpdated = value;
OnPropertyChanged();
}
}

#endregion //Properties

#region INotifyPropertyChanged

public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName]string propertyname = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}

#endregion //INotifyPropertyChanged

public override string ToString()
{
return String.Format("{0}, {1}", LastName, FirstName);
}
}

View

PersonList.xaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<UserControl
x:Class="ModuleA.Views.PersonList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True">

<UserControl.Resources>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding DataContext.SelectedPerson.FirstName}" />
</Style>
</UserControl.Resources>

<Grid
x:Name="LayoutRoot"
Margin="10"
Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="100" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<ListBox x:Name="_listOfPeople" ItemsSource="{Binding People}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<prism:InvokeCommandAction Command="{Binding PersonSelectedCommand}" CommandParameter="{Binding SelectedItem, ElementName=_listOfPeople}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
<TabControl
Grid.Row="1"
Margin="10"
prism:RegionManager.RegionName="PersonDetailsRegion" />
</Grid>
</UserControl>

PersonDetail.xaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<UserControl x:Class="ModuleA.Views.PersonDetail"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

<!-- First Name -->
<TextBlock Text="First Name:" Margin="5" />
<TextBlock Grid.Column="1" Margin="5" Text="{Binding SelectedPerson.FirstName}" />

<!-- Last Name -->
<TextBlock Grid.Row="1" Text="Last Name:" Margin="5" />
<TextBlock Grid.Row="1" Grid.Column="1" Margin="5" Text="{Binding SelectedPerson.LastName}" />

<!-- Age -->
<TextBlock Grid.Row="2" Text="Age:" Margin="5"/>
<TextBlock Grid.Row="2" Grid.Column="1" Margin="5" Text="{Binding SelectedPerson.Age}"/>
</Grid>
</UserControl>

ViewModel

PersonListViewModel.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
using System;
using ModuleA.Business;
using Prism.Mvvm;
using Prism.Navigation.Regions;

namespace ModuleA.ViewModels
{
public class PersonDetailViewModel : BindableBase, INavigationAware
{
private Person _selectedPerson;
public Person SelectedPerson
{
get { return _selectedPerson; }
set { SetProperty(ref _selectedPerson, value); }
}

public PersonDetailViewModel()
{

}

public void OnNavigatedTo(NavigationContext navigationContext)
{
var person = navigationContext.Parameters["person"] as Person;
if (person != null)
SelectedPerson = person;
}

public bool IsNavigationTarget(NavigationContext navigationContext)
{
var person = navigationContext.Parameters["person"] as Person;
if (person != null)
return SelectedPerson != null && SelectedPerson.LastName == person.LastName;
else
return true;
}

public void OnNavigatedFrom(NavigationContext navigationContext)
{

}
}
}

PersonDetailViewModel.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
using ModuleA.Business;
using Prism.Commands;
using Prism.Mvvm;
using Prism.Navigation.Regions;
using System;
using System.Collections.ObjectModel;

namespace ModuleA.ViewModels
{
public class PersonListViewModel : BindableBase
{
IRegionManager _regionManager;

private ObservableCollection<Person> _people;
public ObservableCollection<Person> People
{
get { return _people; }
set { SetProperty(ref _people, value); }
}

public DelegateCommand<Person> PersonSelectedCommand { get; private set; }

public PersonListViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;

PersonSelectedCommand = new DelegateCommand<Person>(PersonSelected);
CreatePeople();
}

private void PersonSelected(Person person)
{
var parameters = new NavigationParameters();
parameters.Add("person", person);

if (person != null)
__regionManager.RequestNavigate("PersonDetailsRegion", typeof(PersonDetail).Name, parameters);
}

private void CreatePeople()
{
var people = new ObservableCollection<Person>();
for (int i = 0; i < 10; i++)
{
people.Add(new Person()
{
FirstName = String.Format("First {0}", i),
LastName = String.Format("Last {0}", i),
Age = i
});
}

People = people;
}
}
}

导航请求处理

ViewA/BViewModel.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class ViewAViewModel : BindableBase, IConfirmNavigationRequest
{
public ViewAViewModel()
{

}

/// <summary>
/// 确定此实例是否接受导航。
/// </summary>
/// <param name="navigationContext">导航上下文</param>
/// <param name="continuationCallback">指示导航何时可以继续的回调函数。</param>
/// <remarks>
/// 此方法的实现者在此方法完成之前不需要调用回调函数,但它们必须确保回调函数最终被调用。
/// </remarks>
public void ConfirmNavigationRequest(NavigationContext navigationContext, Action<bool> continuationCallback)
{
bool result = true;

if (MessageBox.Show("Do you to navigate?", "Navigate?", MessageBoxButton.YesNo) == MessageBoxResult.No)
result = false;

continuationCallback(result);
}

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

public void OnNavigatedFrom(NavigationContext navigationContext)
{

}

public void OnNavigatedTo(NavigationContext navigationContext)
{

}
}