Всем привет, начал писать приложение на UWP в MVVM-паттерне и столкнулся с проблемой навигации между страницами приложения.
Приложение имеет следующую стандартную структуру:
1) Форма ввода пароля
2)После пароля проходим в следующую страницу с hamburger-меню в левой части и большой центральной частью для меняющегося содержимого.
Для навигации верхнего уровня (по всему приложению) использую вспомогательный класс NavigationService
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.
public class NavigationService
{
/// <summary>
/// This holds the instance to the Only NavigationService in this app.
/// </summary>
public static NavigationService Instance { get; protected set; }
public static NavigationService NavServiceArea { get; protected set; }
/// <summary>
/// This will hold the reference to the frame that is to be manipulated.
/// </summary>
private Frame frame;
/// <summary>
/// The Stack of pages to enable Stack based Navigation.
/// </summary>
public Stack<Type> PageStack { get; protected set; }
#region CTOR
/// <summary>
/// The default constructor to instantiate this class with reference to a frame
/// </summary>
/// <param name="frame">The referenced frame</param>
public NavigationService( ref Frame frame )
{
//Check is the instance doesnt already exist.
if (Instance != null)
{
//if there is an instance in the app already present then simply throw an error.
throw new Exception("Only one navigation service can exist in a App.");
}
//setting the instance to the static instance field.
Instance = this;
//setting the frame reference.
this.frame = frame;
// frame.DataContext = frame_datacontext;
//intialising the stack.
this.PageStack = new Stack<Type>();
//Hooking up the events for BackRequest both for Big Windows and for Phone.
SystemNavigationManager.GetForCurrentView().BackRequested += NavigationService_BackRequested;
}
#endregion
#region Navigation Methods
public void NavigateTo(Type pageType, object parameter)
{
if (PageStack.Count > 0)
{
if (PageStack.Peek() == pageType)
return;
}
PageStack.Push(pageType);
frame.Navigate(pageType, parameter);
UpdateBackButtonVisibility();
}
public void NavigateBack()
{
if (frame.CanGoBack)
frame.GoBack();
PageStack.Pop();
UpdateBackButtonVisibility();
}
public void NavigateToHome()
{
while (frame.CanGoBack)
frame.GoBack();
}
#endregion
#region BackButtonVisibilty Region
void UpdateBackButtonVisibility()
{
SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility = frame.CanGoBack ?
AppViewBackButtonVisibility.Visible : AppViewBackButtonVisibility.Collapsed;
}
#endregion
#region Event Methods for windows and phone
private void NavigationService_BackRequested( object sender , BackRequestedEventArgs e )
{
this.NavigateBack();
}
#endregion
}
, экземпляр которого создается при запуске приложения
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.
sealed partial class App : Application
{
public static NavigationService NavService { get; protected set;}
/// <summary>
/// Инициализирует одноэлементный объект приложения. Это первая выполняемая строка разрабатываемого
/// кода; поэтому она является логическим эквивалентом main() или WinMain().
/// </summary>
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
}
/// <summary>
/// Вызывается при обычном запуске приложения пользователем. Будут использоваться другие точки входа,
/// например, если приложение запускается для открытия конкретного файла.
/// </summary>
/// <param name="e">Сведения о запросе и обработке запуска.</param>
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
#if DEBUG
if (System.Diagnostics.Debugger.IsAttached)
{
//this.DebugSettings.EnableFrameRateCounter = true;
}
#endif
MainPageUserControl mnpage = Window.Current.Content as MainPageUserControl;
// Do not repeat app initialization when the Window already has content,
// just ensure that the window is active
if (mnpage == null)
{
// Create a Frame to act as the navigation context and navigate to the first page
mnpage = new MainPageUserControl();
if (mnpage.rootFrame == null) mnpage.rootFrame = new Frame();
NavService = new NavigationService(ref mnpage.rootFrame);
mnpage.rootFrame.NavigationFailed += OnNavigationFailed;
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//TODO: Load state from previously suspended application
}
}
// Place the frame in the current Window
Window.Current.Content = mnpage;
// Ensure the current window is active
Window.Current.Activate();
if (mnpage.rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
NavService.NavigateTo(typeof(passwordpage), null);
}
}
/// <summary>
/// Вызывается в случае сбоя навигации на определенную страницу
/// </summary>
/// <param name="sender">Фрейм, для которого произошел сбой навигации</param>
/// <param name="e">Сведения о сбое навигации</param>
void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
{
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
}
/// <summary>
/// Вызывается при приостановке выполнения приложения. Состояние приложения сохраняется
/// без учета информации о том, будет ли оно завершено или возобновлено с неизменным
/// содержимым памяти.
/// </summary>
/// <param name="sender">Источник запроса приостановки.</param>
/// <param name="e">Сведения о запросе приостановки.</param>
private void OnSuspending(object sender, SuspendingEventArgs e)
{
var deferral = e.SuspendingOperation.GetDeferral();
//TODO: Сохранить состояние приложения и остановить все фоновые операции
deferral.Complete();
}
}
листинги вьюшек:
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
<UserControl
x:Class="MyFirstUWPApp.View.MainPageUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyFirstUWPApp.View"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Frame Grid.Row="1"
x:Name="rootFrame"
x:FieldModifier="public">
</Frame>
</UserControl>
основная вьюха с меню
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.
<VM:BasePage
x:Class="MyFirstUWPApp.View.MainAppPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyFirstUWPApp.View"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:VM="using:MyFirstUWPApp.ViewModel"
NavigationCacheMode="Enabled"
mc:Ignorable="d">
<VM:BasePage.DataContext >
<VM:MainAppPageViewModel />
</VM:BasePage.DataContext>
<SplitView DisplayMode="CompactInline"
IsPaneOpen="{Binding IsPaneOpen, UpdateSourceTrigger=PropertyChanged}"
CompactPaneLength="50" OpenPaneLength="200">
<SplitView.Pane>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<Button x:Name="MenuButton1" FontFamily="Segoe MDL2 Assets" Content=""
Width="50" Height="50" Background="Transparent"
Tapped="{x:Bind ViewModel.hide_command}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<Button FontFamily="Times New Roma" Content="S"
Width="50" Height="50" Background="Transparent"
Tapped="{x:Bind ViewModel.show_sprav_menu}"/>
<Button FontFamily="Times New Roma" Content="Справочник"
Width="150" Height="50" Background="Transparent"
Tapped="{x:Bind ViewModel.show_sprav_menu}"/>
</StackPanel>
</StackPanel>
</SplitView.Pane>
<SplitView.Content>
<Frame Grid.Row="1"
x:Name="FrameArea"
x:FieldModifier="public">
</Frame>
</SplitView.Content>
</SplitView>
</VM:BasePage>
Проблема в том, что не могу создать внутри существующего экземпляра NavigationService еще один экземпляр этого класса, только чтобы он менял содержимое фрейма
FrameArea то есть фрейма-потомка внутри фрейма-родителя rootFrame( так как при создании NavigationService принимает в себя Usercontrol с фреймом и к этоту фрейму уже идет привязка). Преобразования типов не помогают:
1.
BasePage p = (MainAppPage)pageType;
.
Подскажите плиз как можно пофиксить.