Всем привет, пишу UWP-приложение с постраничной навигацией(MVVM).
Интерфейс навигации
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.
/// <summary>
/// Provides a mechanism to navigate between pages.
/// </summary>
public interface INavigationService
{
/// <summary>
/// Gets the name of the currently displayed page.
/// </summary>
string CurrentPage { get; }
/// <summary>
/// Navigates to the specified page.
/// </summary>
/// <param name="page"></param>
void NavigateTo(string page);
/// <summary>
/// Navigates to the specified page and
/// supply additional page-specific parameters.
/// </summary>
/// <param name="page"></param>
/// <param name="parameter"></param>
void NavigateTo(string page, object parameter);
/// <summary>
/// Navigates to the previous page in the navigation history.
/// </summary>
void GoBack();
}
}
Его реализация
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.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
/// <summary>
/// Provides a mechanism to navigate between pages.
/// </summary>
public sealed class NavigationService : INavigationService
{
private readonly IDictionary<string, Type> pages_
= new Dictionary<string, Type>();
/// <summary>
/// The name of the virtual "root" page at the top of the navigation history.
/// </summary>
public const string RootPage = "(Root)";
/// <summary>
/// A moniker for an "unknown" page when navigation happens without
/// using the <see cref="NavigationService"/>.
/// </summary>
public const string UnknownPage = "(Unknown)";
private static Frame AppFrame
{
get
{
return ((Window.Current.Content as Frame)?.Content as MainPage)?.AppFrame;
}
}
public void Configure(string page, Type type)
{
lock (pages_)
{
if (pages_.ContainsKey(page))
throw new ArgumentException("The specified page is already registered.");
if (pages_.Values.Any(v => v == type))
throw new ArgumentException("The specified view has already been registered under another name.");
pages_.Add(page, type);
}
}
public NavigationService()
{
}
#region INavigationService Implementation
/// <summary>
/// Gets the name of the currently displayed page.
/// </summary>
public string CurrentPage
{
get
{
var frame = AppFrame;
if (frame.BackStackDepth == 0)
return RootPage;
if (frame.Content == null)
return UnknownPage;
var type = frame.Content.GetType();
lock (pages_)
{
if (pages_.Values.All(v => v != type))
return UnknownPage;
var item = pages_.Single(i => i.Value == type);
return item.Key;
}
}
}
/// <summary>
/// Navigates to the specified page.
/// </summary>
/// <param name="page"></param>
public void NavigateTo(string page)
{
NavigateTo(page, null);
}
/// <summary>
/// Navigates to the specified page and
/// supply additional page-specific parameters.
/// </summary>
/// <param name="page"></param>
/// <param name="parameter"></param>
public void NavigateTo(string page, object parameter)
{
lock (pages_)
{
if (!pages_.ContainsKey(page))
throw new ArgumentException("Unable to find a page registered with the specified name.");
//System.Diagnostics.Debug.Assert(AppFrame != null);
AppFrame.Navigate(pages_[page], parameter);
}
}
/// <summary>
/// Navigates to the previous page in the navigation history.
/// </summary>
public void GoBack()
{
//System.Diagnostics.Debug.Assert(AppFrame != null);
if (AppFrame.CanGoBack)
AppFrame.GoBack();
}
#endregion
}
Регистрирую в контейнере зависимости ViewModels
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.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
public class ViewModelLocator
{
private IKernel Kernel { get; }
public ViewModelLocator()
{
Kernel = new StandardKernel();
string UserPath = ApplicationData.Current.LocalFolder.Path;
Kernel.Bind<ApplicationDbContext>()
.ToSelf()
.InTransientScope()
.WithConstructorArgument("DbPath", UserPath);
//Создаем папку для хранения файлов
var WorkedDir = Path.Combine(UserPath, "DataStore");
if (!Directory.Exists(WorkedDir))
Directory.CreateDirectory(WorkedDir);
Get<ApplicationDbContext>().Database.EnsureCreated();
MapperConfiguration configuration = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Container, SelectedContainerDto>();
cfg.CreateMap<SelectedContainerDto, VisualContainer>();
});
IMapper mapper = configuration.CreateMapper();
Kernel.Bind<IMapper>().ToConstant(mapper);
var nav = new NavigationService();
nav.Configure("MainPage", typeof(MainPage));
nav.Configure("ContainerSprav", typeof(ContainerSprav));
nav.Configure("AddContainer", typeof(AddContainer));
nav.Configure("AddFlightType", typeof(FlightTypeSprav));
nav.Configure("CreateDiagram", typeof(CreateDiagram));
nav.Configure("FilledElementSprav", typeof(FilledElementSprav));
nav.Configure("ServingSprav", typeof(ServingSprav));
nav.Configure("ServingClassSprav", typeof(ServingClassSprav));
nav.Configure("MeasureUnitSprav", typeof(MeasureUnitSprav));
nav.Configure("CreateNewItemContainer", typeof(CreateNewItemContainer));
nav.Configure("AddContainerItemToLevel", typeof(AddContainerItemToLevel));
Kernel.Bind<INavigationService>().ToConstant(nav);
Kernel.Bind<MenuVM>().ToConstant(new MenuVM(Get<INavigationService>()));
Kernel.Bind<ApplicationViewModel>().ToConstant(new ApplicationViewModel());
Kernel.Bind<ICbaseFlightInfo>().ToConstant(new OracleDataFetcher());
Kernel.Bind<IFlightsData>()
.To<FlightDataFetcher>()
.InTransientScope();
//Создание диаграммы
Kernel
.Bind<CreateDiagramViewModel>()
.ToSelf()
.InSingletonScope()
.WithConstructorArgument("flightsData",Get<IFlightsData>())
.WithConstructorArgument("mapper", Get<IMapper>())
.WithConstructorArgument("navigationService", Get<INavigationService>());
Kernel.Bind<AddContainerItemToLevelViewModel>()
.ToSelf()
.WithConstructorArgument("containerItems", Get<EFCoreGenericRepository<ContainerItem>>());
}
private T Get<T>() => Kernel.Get<T>();
///Раздаем ViewModel для Pages
public ApplicationViewModel ApplicationViewModel => Get<ApplicationViewModel>();
public MenuVM MenuViewModel => Get<MenuVM>();
public ContainersViewModel ContainersViewModel => Get<ContainersViewModel>();
public AddContainerViewModel AddContainerViewModel => Get<AddContainerViewModel>();
public AddContainerItemToLevelViewModel AddContainerItemToLevelViewModel => Get<AddContainerItemToLevelViewModel>();
}
Регистрирую локатор для всего приложения в App.xaml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
<Application
x:Class="App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:CbaseDiagram"
xmlns:locator="using:Locator.Locator">
<Application.Resources>
<locator:ViewModelLocator x:Key="Locator" />
</Application.Resources>
</Application>
В Page получаю ViewModel из конструктора
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
<Page
x:Class="CbaseDiagram.Views.AddContainer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:CbaseDiagram.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
DataContext="{Binding AddContainerViewModel,Source={StaticResource Locator}}"/>
Если из ViewModel нужно перейти на другую страницу, то делаю инъекцию сервиса навигации в конструктор и вызываю метод навигации
1.
2.
// вызов команды навигации
NavigateToCreationOfNewContainerItem = new RelayCommand(() => navigationService.NavigateTo("CreateNewItemContainer"));
Проблема в том, что если хочу вместе с навигацией передавать параметр,
1.
NavigateToCreationOfNewContainerItem = new RelayCommand(() => navigationService.NavigateTo("CreateNewItemContainer",parameter))
то я не могу его поймать во принимающей ViewModel, страницы на которую переходят.
Пытался у принимающей Page привязать событие OnNavigatedTo, но почему-то падает в ошибку, типа нет такого события.
1.
2.
3.
4.
5.
6.
<Page>
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="OnNavigatingTo">
<core:InvokeCommandAction Command="{Binding OnNavigatedToCommand}" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
$exception {Windows.UI.Xaml.Markup.XamlParseException: Не удалось найти текст, связанный с этим кодом ошибки.
Cannot add instance of type 'Microsoft.Xaml.Interactions.Core.EventTriggerBehavior' to a collection of type 'Microsoft.Xaml.Interactivity.BehaviorCollection'. [Line: 19 Position: 82]
at Windows.UI.Xaml.Application.LoadComponent(Object component, Uri resourceLocator, ComponentResourceLocation componentResourceLocation)
at CbaseDiagram.Views.AddContainerItemToLevel.InitializeComponent()
at CbaseDiagram.Views.AddContainerItemToLevel..ctor()} Windows.UI.Xaml.Markup.XamlParseException
Как можно без прокси поймать передаваемый параметр в принимающей ViewModel?