diff --git a/ModernKeePass/App.xaml.cs b/ModernKeePass/App.xaml.cs
index ff09eb1..7938eef 100644
--- a/ModernKeePass/App.xaml.cs
+++ b/ModernKeePass/App.xaml.cs
@@ -17,7 +17,7 @@ namespace ModernKeePass
///
/// Provides application-specific behavior to supplement the default Application class.
///
- sealed partial class App : Application
+ sealed partial class App
{
public DatabaseHelper Database { get; set; } = new DatabaseHelper();
public Dictionary PendingDeleteEntities = new Dictionary();
@@ -87,7 +87,7 @@ namespace ModernKeePass
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
- rootFrame.Navigate(typeof(MainPage), lauchActivatedEventArgs.Arguments);
+ rootFrame.Navigate(typeof(Pages.MainPage), lauchActivatedEventArgs.Arguments);
}
else
{
@@ -140,7 +140,7 @@ namespace ModernKeePass
base.OnFileActivated(args);
var rootFrame = new Frame();
Database.DatabaseFile = args.Files[0] as StorageFile;
- rootFrame.Navigate(typeof(MainPage), args);
+ rootFrame.Navigate(typeof(Pages.MainPage), args);
Window.Current.Content = rootFrame;
Window.Current.Activate();
}
diff --git a/ModernKeePass/Interfaces/IHasSelectableObject.cs b/ModernKeePass/Interfaces/IHasSelectableObject.cs
new file mode 100644
index 0000000..038cb05
--- /dev/null
+++ b/ModernKeePass/Interfaces/IHasSelectableObject.cs
@@ -0,0 +1,7 @@
+namespace ModernKeePass.Interfaces
+{
+ public interface IHasSelectableObject
+ {
+ ISelectableModel SelectedItem { get; set; }
+ }
+}
diff --git a/ModernKeePass/Interfaces/ISelectableModel.cs b/ModernKeePass/Interfaces/ISelectableModel.cs
new file mode 100644
index 0000000..b1382cd
--- /dev/null
+++ b/ModernKeePass/Interfaces/ISelectableModel.cs
@@ -0,0 +1,7 @@
+namespace ModernKeePass.Interfaces
+{
+ public interface ISelectableModel
+ {
+ bool IsSelected { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/ModernKeePass/ModernKeePass.csproj b/ModernKeePass/ModernKeePass.csproj
index 256831f..ed3cc0a 100644
--- a/ModernKeePass/ModernKeePass.csproj
+++ b/ModernKeePass/ModernKeePass.csproj
@@ -119,7 +119,10 @@
-
+
+
+
+ OpenDatabaseUserControl.xaml
@@ -140,13 +143,16 @@
MainPage.xaml
-
+ AboutPage.xaml
-
+ NewDatabasePage.xaml
-
+
+ SettingsPage.xaml
+
+ WelcomePage.xaml
@@ -158,13 +164,13 @@
GroupDetailPage.xaml
-
+ OpenDatabasePage.xaml
-
+ RecentDatabasesPage.xaml
-
+ SaveDatabasePage.xaml
@@ -202,7 +208,7 @@
MSBuild:CompileDesigner
-
+ DesignerMSBuild:Compile
@@ -214,23 +220,27 @@
DesignerMSBuild:Compile
-
+ DesignerMSBuild:Compile
-
+ DesignerMSBuild:Compile
-
+ DesignerMSBuild:Compile
-
+ DesignerMSBuild:Compile
-
+
+ Designer
+ MSBuild:Compile
+
+ DesignerMSBuild:Compile
@@ -320,6 +330,9 @@
ModernKeePassLib
+
+
+ 12.0
diff --git a/ModernKeePass/Pages/BasePages/LayoutAwarePageBase.cs b/ModernKeePass/Pages/BasePages/LayoutAwarePageBase.cs
new file mode 100644
index 0000000..be8f8da
--- /dev/null
+++ b/ModernKeePass/Pages/BasePages/LayoutAwarePageBase.cs
@@ -0,0 +1,184 @@
+using System;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Data;
+using ModernKeePass.Common;
+using ModernKeePass.Interfaces;
+
+namespace ModernKeePass.Pages.BasePages
+{
+ public class LayoutAwarePageBase: Page
+ {
+ ///
+ /// NavigationHelper is used on each page to aid in navigation and
+ /// process lifetime management
+ ///
+ public NavigationHelper NavigationHelper { get; }
+
+ public virtual ListView ListView { get; set; }
+ public virtual CollectionViewSource ListViewSource { get; set; }
+ public virtual IHasSelectableObject Model { get; set; }
+
+ public LayoutAwarePageBase()
+ {
+ // Setup the navigation helper
+ NavigationHelper = new NavigationHelper(this);
+ NavigationHelper.LoadState += navigationHelper_LoadState;
+ NavigationHelper.SaveState += navigationHelper_SaveState;
+
+ // Setup the logical page navigation components that allow
+ // the page to only show one pane at a time.
+ NavigationHelper.GoBackCommand = new RelayCommand(() => GoBack(), () => CanGoBack());
+
+ // Start listening for Window size changes
+ // to change from showing two panes to showing a single pane
+ Window.Current.SizeChanged += Window_SizeChanged;
+ InvalidateVisualState();
+ }
+
+ protected void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ // Invalidate the view state when logical page navigation is in effect, as a change
+ // in selection may cause a corresponding change in the current logical page. When
+ // an item is selected this has the effect of changing from displaying the item list
+ // to showing the selected item's details. When the selection is cleared this has the
+ // opposite effect.
+ if (!UsingLogicalPageNavigation()) return;
+ NavigationHelper.GoBackCommand.RaiseCanExecuteChanged();
+ InvalidateVisualState();
+ }
+
+ ///
+ /// Populates the page with content passed during navigation. Any saved state is also
+ /// provided when recreating a page from a prior session.
+ ///
+ ///
+ /// The source of the event; typically
+ ///
+ /// Event data that provides both the navigation parameter passed to
+ /// when this page was initially requested and
+ /// a dictionary of state preserved by this page during an earlier
+ /// session. The state will be null the first time a page is visited.
+ protected void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
+ {
+ // TODO: Assign a bindable group to Me.DefaultViewModel("Group")
+ // TODO: Assign a collection of bindable items to Me.DefaultViewModel("Items")
+
+ if (e.PageState == null)
+ {
+ // When this is a new page, select the first item automatically unless logical page
+ // navigation is being used (see the logical page navigation #region below.)
+ if (!UsingLogicalPageNavigation() && ListViewSource.View != null)
+ {
+ ListViewSource.View.MoveCurrentToFirst();
+ }
+ }
+ else
+ {
+ // Restore the previously saved state associated with this page
+ if (e.PageState.ContainsKey("SelectedItem") && ListViewSource.View != null)
+ {
+ ListViewSource.View.MoveCurrentTo(e.PageState["SelectedItem"]);
+ }
+ }
+ }
+
+ ///
+ /// Preserves state associated with this page in case the application is suspended or the
+ /// page is discarded from the navigation cache. Values must conform to the serialization
+ /// requirements of .
+ ///
+ /// The source of the event; typically
+ /// Event data that provides an empty dictionary to be populated with
+ /// serializable state.
+ protected void navigationHelper_SaveState(object sender, SaveStateEventArgs e)
+ {
+ if (ListViewSource.View != null)
+ {
+ e.PageState["SelectedItem"] = Model?.SelectedItem;
+ }
+ }
+
+ #region Logical page navigation
+
+ // The split page is designed so that when the Window does have enough space to show
+ // both the list and the details, only one pane will be shown at at time.
+ //
+ // This is all implemented with a single physical page that can represent two logical
+ // pages. The code below achieves this goal without making the user aware of the
+ // distinction.
+
+ protected const int MinimumWidthForSupportingTwoPanes = 768;
+
+ ///
+ /// Invoked to determine whether the page should act as one logical page or two.
+ ///
+ /// True if the window should show act as one logical page, false
+ /// otherwise.
+ protected bool UsingLogicalPageNavigation()
+ {
+ return Window.Current.Bounds.Width < MinimumWidthForSupportingTwoPanes;
+ }
+
+ ///
+ /// Invoked with the Window changes size
+ ///
+ /// The current Window
+ /// Event data that describes the new size of the Window
+ protected void Window_SizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
+ {
+ InvalidateVisualState();
+ }
+
+ protected bool CanGoBack()
+ {
+ if (UsingLogicalPageNavigation() && ListView.SelectedItem != null)
+ {
+ return true;
+ }
+ return NavigationHelper.CanGoBack();
+ }
+ protected void GoBack()
+ {
+ if (UsingLogicalPageNavigation() && ListView.SelectedItem != null)
+ {
+ // When logical page navigation is in effect and there's a selected item that
+ // item's details are currently displayed. Clearing the selection will return to
+ // the item list. From the user's point of view this is a logical backward
+ // navigation.
+ ListView.SelectedItem = null;
+ }
+ else
+ {
+ NavigationHelper.GoBack();
+ }
+ }
+
+ protected void InvalidateVisualState()
+ {
+ var visualState = DetermineVisualState();
+ VisualStateManager.GoToState(this, visualState, false);
+ NavigationHelper.GoBackCommand.RaiseCanExecuteChanged();
+ }
+
+ ///
+ /// Invoked to determine the name of the visual state that corresponds to an application
+ /// view state.
+ ///
+ /// The name of the desired visual state. This is the same as the name of the
+ /// view state except when there is a selected item in portrait and snapped views where
+ /// this additional logical page is represented by adding a suffix of _Detail.
+ protected string DetermineVisualState()
+ {
+ if (!UsingLogicalPageNavigation())
+ return "PrimaryView";
+
+ // Update the back button's enabled state when the view state changes
+ var logicalPageBack = UsingLogicalPageNavigation() && ListView?.SelectedItem != null;
+
+ return logicalPageBack ? "SinglePane_Detail" : "SinglePane";
+ }
+
+ #endregion
+ }
+}
diff --git a/ModernKeePass/Pages/EntryDetailPage.xaml b/ModernKeePass/Pages/EntryDetailPage.xaml
index 45f4fd2..48c3567 100644
--- a/ModernKeePass/Pages/EntryDetailPage.xaml
+++ b/ModernKeePass/Pages/EntryDetailPage.xaml
@@ -379,7 +379,9 @@
-
+
+
+
diff --git a/ModernKeePass/Pages/GroupDetailPage.xaml b/ModernKeePass/Pages/GroupDetailPage.xaml
index ba74310..0bb0269 100644
--- a/ModernKeePass/Pages/GroupDetailPage.xaml
+++ b/ModernKeePass/Pages/GroupDetailPage.xaml
@@ -5,10 +5,10 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="using:ModernKeePass.ViewModels"
xmlns:converters="using:ModernKeePass.Converters"
- xmlns:local="using:ModernKeePass.Controls"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
- xmlns:actions="using:ModernKeePass.Actions"
+ xmlns:actions="using:ModernKeePass.Actions"
+ xmlns:templateSelectors="using:ModernKeePass.TemplateSelectors"
x:Name="PageRoot"
x:Class="ModernKeePass.Pages.GroupDetailPage"
mc:Ignorable="d" >
@@ -32,7 +32,9 @@
-
+
+
+
@@ -139,7 +141,7 @@
-
diff --git a/ModernKeePass/Pages/MainPage.xaml b/ModernKeePass/Pages/MainPage.xaml
index ded151f..974a5f2 100644
--- a/ModernKeePass/Pages/MainPage.xaml
+++ b/ModernKeePass/Pages/MainPage.xaml
@@ -1,16 +1,14 @@
-
-
-
-
+ xmlns:controls="using:ModernKeePass.Controls"
+ xmlns:basePages="using:ModernKeePass.Pages.BasePages"
+ x:Class="ModernKeePass.Pages.MainPage"
+ x:Name="PageRoot"
+ mc:Ignorable="d">
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
-
+
+
+
+
+
+
+
+
+
-
-
-
-
+
-
-
+
+
-
-
+
+
-
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/ModernKeePass/Pages/MainPage.xaml.cs b/ModernKeePass/Pages/MainPage.xaml.cs
index e552153..8f0536a 100644
--- a/ModernKeePass/Pages/MainPage.xaml.cs
+++ b/ModernKeePass/Pages/MainPage.xaml.cs
@@ -1,34 +1,56 @@
-using Windows.UI.Xaml.Controls;
+using System;
+using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
-using ModernKeePass.Pages;
using ModernKeePass.ViewModels;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
-namespace ModernKeePass
+namespace ModernKeePass.Pages
{
///
/// An empty page that can be used on its own or navigated to within a Frame.
///
public sealed partial class MainPage
{
- public MainVm Model => (MainVm)DataContext;
-
+ public new MainVm Model => (MainVm)DataContext;
+
public MainPage()
{
InitializeComponent();
+ ListView = MenuListView;
+ ListViewSource = MenuItemsSource;
}
+ private void MenuListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ ListView_SelectionChanged(sender, e);
+ var selectedItem = Model.SelectedItem as MainMenuItemVm;
+ selectedItem?.Destination.Navigate(selectedItem.PageType, selectedItem.Parameter);
+ }
+
+ #region NavigationHelper registration
+
+ /// The methods provided in this section are simply used to allow
+ /// NavigationHelper to respond to the page's navigation methods.
+ ///
+ /// Page specific logic should be placed in event handlers for the
+ ///
+ /// and .
+ /// The navigation parameter is available in the LoadState method
+ /// in addition to page state preserved during an earlier session.
+
protected override void OnNavigatedTo(NavigationEventArgs e)
{
- base.OnNavigatedTo(e);
+ NavigationHelper.OnNavigatedTo(e);
DataContext = new MainVm(Frame, MenuFrame);
if (Model.SelectedItem == null) MenuFrame.Navigate(typeof(WelcomePage));
}
- private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ protected override void OnNavigatedFrom(NavigationEventArgs e)
{
- Model.SelectedItem?.Destination.Navigate(Model.SelectedItem.PageType, Model.SelectedItem.Parameter);
+ NavigationHelper.OnNavigatedFrom(e);
}
+
+ #endregion
}
}
diff --git a/ModernKeePass/Pages/AboutPage.xaml b/ModernKeePass/Pages/MainPageFrames/AboutPage.xaml
similarity index 98%
rename from ModernKeePass/Pages/AboutPage.xaml
rename to ModernKeePass/Pages/MainPageFrames/AboutPage.xaml
index 0cbb0dc..37b4bbe 100644
--- a/ModernKeePass/Pages/AboutPage.xaml
+++ b/ModernKeePass/Pages/MainPageFrames/AboutPage.xaml
@@ -12,7 +12,7 @@
-
+
diff --git a/ModernKeePass/Pages/AboutPage.xaml.cs b/ModernKeePass/Pages/MainPageFrames/AboutPage.xaml.cs
similarity index 100%
rename from ModernKeePass/Pages/AboutPage.xaml.cs
rename to ModernKeePass/Pages/MainPageFrames/AboutPage.xaml.cs
diff --git a/ModernKeePass/Pages/NewDatabasePage.xaml b/ModernKeePass/Pages/MainPageFrames/NewDatabasePage.xaml
similarity index 96%
rename from ModernKeePass/Pages/NewDatabasePage.xaml
rename to ModernKeePass/Pages/MainPageFrames/NewDatabasePage.xaml
index 968302e..a4f8463 100644
--- a/ModernKeePass/Pages/NewDatabasePage.xaml
+++ b/ModernKeePass/Pages/MainPageFrames/NewDatabasePage.xaml
@@ -19,7 +19,9 @@
- New
+
+
+ Create a new password database to the location of your chosing.
diff --git a/ModernKeePass/Pages/NewDatabasePage.xaml.cs b/ModernKeePass/Pages/MainPageFrames/NewDatabasePage.xaml.cs
similarity index 100%
rename from ModernKeePass/Pages/NewDatabasePage.xaml.cs
rename to ModernKeePass/Pages/MainPageFrames/NewDatabasePage.xaml.cs
diff --git a/ModernKeePass/Pages/OpenDatabasePage.xaml b/ModernKeePass/Pages/MainPageFrames/OpenDatabasePage.xaml
similarity index 96%
rename from ModernKeePass/Pages/OpenDatabasePage.xaml
rename to ModernKeePass/Pages/MainPageFrames/OpenDatabasePage.xaml
index 89e8964..9e66e60 100644
--- a/ModernKeePass/Pages/OpenDatabasePage.xaml
+++ b/ModernKeePass/Pages/MainPageFrames/OpenDatabasePage.xaml
@@ -17,7 +17,9 @@
- Open
+
+
+ Open an existing password database from your PC.
diff --git a/ModernKeePass/Pages/OpenDatabasePage.xaml.cs b/ModernKeePass/Pages/MainPageFrames/OpenDatabasePage.xaml.cs
similarity index 100%
rename from ModernKeePass/Pages/OpenDatabasePage.xaml.cs
rename to ModernKeePass/Pages/MainPageFrames/OpenDatabasePage.xaml.cs
diff --git a/ModernKeePass/Pages/RecentDatabasesPage.xaml b/ModernKeePass/Pages/MainPageFrames/RecentDatabasesPage.xaml
similarity index 98%
rename from ModernKeePass/Pages/RecentDatabasesPage.xaml
rename to ModernKeePass/Pages/MainPageFrames/RecentDatabasesPage.xaml
index 5c902af..173515b 100644
--- a/ModernKeePass/Pages/RecentDatabasesPage.xaml
+++ b/ModernKeePass/Pages/MainPageFrames/RecentDatabasesPage.xaml
@@ -17,7 +17,7 @@
-
+
- Save
+
+
+ This will save and close the currently opened database.
diff --git a/ModernKeePass/Pages/SaveDatabasePage.xaml.cs b/ModernKeePass/Pages/MainPageFrames/SaveDatabasePage.xaml.cs
similarity index 100%
rename from ModernKeePass/Pages/SaveDatabasePage.xaml.cs
rename to ModernKeePass/Pages/MainPageFrames/SaveDatabasePage.xaml.cs
diff --git a/ModernKeePass/Pages/WelcomePage.xaml b/ModernKeePass/Pages/MainPageFrames/WelcomePage.xaml
similarity index 100%
rename from ModernKeePass/Pages/WelcomePage.xaml
rename to ModernKeePass/Pages/MainPageFrames/WelcomePage.xaml
diff --git a/ModernKeePass/Pages/WelcomePage.xaml.cs b/ModernKeePass/Pages/MainPageFrames/WelcomePage.xaml.cs
similarity index 100%
rename from ModernKeePass/Pages/WelcomePage.xaml.cs
rename to ModernKeePass/Pages/MainPageFrames/WelcomePage.xaml.cs
diff --git a/ModernKeePass/Pages/SettingsPage.xaml b/ModernKeePass/Pages/SettingsPage.xaml
new file mode 100644
index 0000000..e4785f9
--- /dev/null
+++ b/ModernKeePass/Pages/SettingsPage.xaml
@@ -0,0 +1,181 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ModernKeePass/Pages/SettingsPage.xaml.cs b/ModernKeePass/Pages/SettingsPage.xaml.cs
new file mode 100644
index 0000000..8763d08
--- /dev/null
+++ b/ModernKeePass/Pages/SettingsPage.xaml.cs
@@ -0,0 +1,255 @@
+using ModernKeePass.Common;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices.WindowsRuntime;
+using System.Windows.Input;
+using Windows.Foundation;
+using Windows.Foundation.Collections;
+using Windows.UI.ViewManagement;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Controls.Primitives;
+using Windows.UI.Xaml.Data;
+using Windows.UI.Xaml.Input;
+using Windows.UI.Xaml.Media;
+using Windows.UI.Xaml.Navigation;
+
+// The Split Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234234
+
+namespace ModernKeePass.Pages
+{
+ ///
+ /// A page that displays a group title, a list of items within the group, and details for
+ /// the currently selected item.
+ ///
+ public sealed partial class SettingsPage : Page
+ {
+ private NavigationHelper navigationHelper;
+ private ObservableDictionary defaultViewModel = new ObservableDictionary();
+
+ ///
+ /// This can be changed to a strongly typed view model.
+ ///
+ public ObservableDictionary DefaultViewModel
+ {
+ get { return this.defaultViewModel; }
+ }
+
+ ///
+ /// NavigationHelper is used on each page to aid in navigation and
+ /// process lifetime management
+ ///
+ public NavigationHelper NavigationHelper
+ {
+ get { return this.navigationHelper; }
+ }
+
+ public SettingsPage()
+ {
+ this.InitializeComponent();
+
+ // Setup the navigation helper
+ this.navigationHelper = new NavigationHelper(this);
+ this.navigationHelper.LoadState += navigationHelper_LoadState;
+ this.navigationHelper.SaveState += navigationHelper_SaveState;
+
+ // Setup the logical page navigation components that allow
+ // the page to only show one pane at a time.
+ this.navigationHelper.GoBackCommand = new ModernKeePass.Common.RelayCommand(() => this.GoBack(), () => this.CanGoBack());
+ this.itemListView.SelectionChanged += itemListView_SelectionChanged;
+
+ // Start listening for Window size changes
+ // to change from showing two panes to showing a single pane
+ Window.Current.SizeChanged += Window_SizeChanged;
+ this.InvalidateVisualState();
+ }
+
+ void itemListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ if (this.UsingLogicalPageNavigation())
+ {
+ this.navigationHelper.GoBackCommand.RaiseCanExecuteChanged();
+ }
+ }
+
+ ///
+ /// Populates the page with content passed during navigation. Any saved state is also
+ /// provided when recreating a page from a prior session.
+ ///
+ ///
+ /// The source of the event; typically
+ ///
+ /// Event data that provides both the navigation parameter passed to
+ /// when this page was initially requested and
+ /// a dictionary of state preserved by this page during an earlier
+ /// session. The state will be null the first time a page is visited.
+ private void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
+ {
+ // TODO: Assign a bindable group to Me.DefaultViewModel("Group")
+ // TODO: Assign a collection of bindable items to Me.DefaultViewModel("Items")
+
+ if (e.PageState == null)
+ {
+ // When this is a new page, select the first item automatically unless logical page
+ // navigation is being used (see the logical page navigation #region below.)
+ if (!this.UsingLogicalPageNavigation() && this.itemsViewSource.View != null)
+ {
+ this.itemsViewSource.View.MoveCurrentToFirst();
+ }
+ }
+ else
+ {
+ // Restore the previously saved state associated with this page
+ if (e.PageState.ContainsKey("SelectedItem") && this.itemsViewSource.View != null)
+ {
+ // TODO: Invoke Me.itemsViewSource.View.MoveCurrentTo() with the selected
+ // item as specified by the value of pageState("SelectedItem")
+
+ }
+ }
+ }
+
+ ///
+ /// Preserves state associated with this page in case the application is suspended or the
+ /// page is discarded from the navigation cache. Values must conform to the serialization
+ /// requirements of .
+ ///
+ /// The source of the event; typically
+ /// Event data that provides an empty dictionary to be populated with
+ /// serializable state.
+ private void navigationHelper_SaveState(object sender, SaveStateEventArgs e)
+ {
+ if (this.itemsViewSource.View != null)
+ {
+ // TODO: Derive a serializable navigation parameter and assign it to
+ // pageState("SelectedItem")
+
+ }
+ }
+
+ #region Logical page navigation
+
+ // The split page is designed so that when the Window does have enough space to show
+ // both the list and the details, only one pane will be shown at at time.
+ //
+ // This is all implemented with a single physical page that can represent two logical
+ // pages. The code below achieves this goal without making the user aware of the
+ // distinction.
+
+ private const int MinimumWidthForSupportingTwoPanes = 768;
+
+ ///
+ /// Invoked to determine whether the page should act as one logical page or two.
+ ///
+ /// True if the window should show act as one logical page, false
+ /// otherwise.
+ private bool UsingLogicalPageNavigation()
+ {
+ return Window.Current.Bounds.Width < MinimumWidthForSupportingTwoPanes;
+ }
+
+ ///
+ /// Invoked with the Window changes size
+ ///
+ /// The current Window
+ /// Event data that describes the new size of the Window
+ private void Window_SizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
+ {
+ this.InvalidateVisualState();
+ }
+
+ ///
+ /// Invoked when an item within the list is selected.
+ ///
+ /// The GridView displaying the selected item.
+ /// Event data that describes how the selection was changed.
+ private void ItemListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ // Invalidate the view state when logical page navigation is in effect, as a change
+ // in selection may cause a corresponding change in the current logical page. When
+ // an item is selected this has the effect of changing from displaying the item list
+ // to showing the selected item's details. When the selection is cleared this has the
+ // opposite effect.
+ if (this.UsingLogicalPageNavigation()) this.InvalidateVisualState();
+ }
+
+ private bool CanGoBack()
+ {
+ if (this.UsingLogicalPageNavigation() && this.itemListView.SelectedItem != null)
+ {
+ return true;
+ }
+ else
+ {
+ return this.navigationHelper.CanGoBack();
+ }
+ }
+ private void GoBack()
+ {
+ if (this.UsingLogicalPageNavigation() && this.itemListView.SelectedItem != null)
+ {
+ // When logical page navigation is in effect and there's a selected item that
+ // item's details are currently displayed. Clearing the selection will return to
+ // the item list. From the user's point of view this is a logical backward
+ // navigation.
+ this.itemListView.SelectedItem = null;
+ }
+ else
+ {
+ this.navigationHelper.GoBack();
+ }
+ }
+
+ private void InvalidateVisualState()
+ {
+ var visualState = DetermineVisualState();
+ VisualStateManager.GoToState(this, visualState, false);
+ this.navigationHelper.GoBackCommand.RaiseCanExecuteChanged();
+ }
+
+ ///
+ /// Invoked to determine the name of the visual state that corresponds to an application
+ /// view state.
+ ///
+ /// The name of the desired visual state. This is the same as the name of the
+ /// view state except when there is a selected item in portrait and snapped views where
+ /// this additional logical page is represented by adding a suffix of _Detail.
+ private string DetermineVisualState()
+ {
+ if (!UsingLogicalPageNavigation())
+ return "PrimaryView";
+
+ // Update the back button's enabled state when the view state changes
+ var logicalPageBack = this.UsingLogicalPageNavigation() && this.itemListView.SelectedItem != null;
+
+ return logicalPageBack ? "SinglePane_Detail" : "SinglePane";
+ }
+
+ #endregion
+
+ #region NavigationHelper registration
+
+ /// The methods provided in this section are simply used to allow
+ /// NavigationHelper to respond to the page's navigation methods.
+ ///
+ /// Page specific logic should be placed in event handlers for the
+ ///
+ /// and .
+ /// The navigation parameter is available in the LoadState method
+ /// in addition to page state preserved during an earlier session.
+
+ protected override void OnNavigatedTo(NavigationEventArgs e)
+ {
+ navigationHelper.OnNavigatedTo(e);
+ }
+
+ protected override void OnNavigatedFrom(NavigationEventArgs e)
+ {
+ navigationHelper.OnNavigatedFrom(e);
+ }
+
+ #endregion
+ }
+}
diff --git a/ModernKeePass/Controls/FirstItemDataTemplateSelector.cs b/ModernKeePass/TemplateSelectors/FirstItemDataTemplateSelector.cs
similarity index 93%
rename from ModernKeePass/Controls/FirstItemDataTemplateSelector.cs
rename to ModernKeePass/TemplateSelectors/FirstItemDataTemplateSelector.cs
index 7501176..e9da649 100644
--- a/ModernKeePass/Controls/FirstItemDataTemplateSelector.cs
+++ b/ModernKeePass/TemplateSelectors/FirstItemDataTemplateSelector.cs
@@ -1,7 +1,7 @@
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
-namespace ModernKeePass.Controls
+namespace ModernKeePass.TemplateSelectors
{
public class FirstItemDataTemplateSelector: DataTemplateSelector
{
diff --git a/ModernKeePass/ViewModels/Items/MainMenuItemVm.cs b/ModernKeePass/ViewModels/Items/MainMenuItemVm.cs
index 1d7e5b8..f871336 100644
--- a/ModernKeePass/ViewModels/Items/MainMenuItemVm.cs
+++ b/ModernKeePass/ViewModels/Items/MainMenuItemVm.cs
@@ -5,7 +5,7 @@ using ModernKeePass.Interfaces;
namespace ModernKeePass.ViewModels
{
- public class MainMenuItemVm: NotifyPropertyChangedBase, IIsEnabled
+ public class MainMenuItemVm: NotifyPropertyChangedBase, IIsEnabled, ISelectableModel
{
private bool _isSelected;
diff --git a/ModernKeePass/ViewModels/MainVm.cs b/ModernKeePass/ViewModels/MainVm.cs
index cf935fe..4daef6d 100644
--- a/ModernKeePass/ViewModels/MainVm.cs
+++ b/ModernKeePass/ViewModels/MainVm.cs
@@ -5,11 +5,13 @@ using Windows.Storage.AccessCache;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using ModernKeePass.Common;
+using ModernKeePass.Interfaces;
using ModernKeePass.Pages;
+using ModernKeePass.Pages.BasePages;
namespace ModernKeePass.ViewModels
{
- public class MainVm : NotifyPropertyChangedBase
+ public class MainVm : NotifyPropertyChangedBase, IHasSelectableObject
{
private IOrderedEnumerable> _mainMenuItems;
private MainMenuItemVm _selectedItem;
@@ -22,7 +24,7 @@ namespace ModernKeePass.ViewModels
set { SetProperty(ref _mainMenuItems, value); }
}
- public MainMenuItemVm SelectedItem
+ public ISelectableModel SelectedItem
{
get { return _selectedItem; }
set
@@ -33,7 +35,7 @@ namespace ModernKeePass.ViewModels
_selectedItem.IsSelected = false;
}
- SetProperty(ref _selectedItem, value);
+ SetProperty(ref _selectedItem, (MainMenuItemVm)value);
if (_selectedItem != null)
{