├── art
└── logo.png
├── iOS
├── Assets.xcassets
│ ├── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── packages.config
├── Entitlements.plist
├── Main.cs
├── AppDelegate.cs
├── LaunchScreen.storyboard
├── Info.plist
└── VMFirstNav.Demo.iOS.csproj
├── Droid
├── Resources
│ ├── drawable
│ │ └── icon.png
│ ├── drawable-hdpi
│ │ └── icon.png
│ ├── drawable-xhdpi
│ │ └── icon.png
│ ├── drawable-xxhdpi
│ │ └── icon.png
│ ├── layout
│ │ ├── Toolbar.axml
│ │ └── Tabbar.axml
│ ├── values
│ │ └── styles.xml
│ └── AboutResources.txt
├── Properties
│ ├── AndroidManifest.xml
│ └── AssemblyInfo.cs
├── Assets
│ └── AboutAssets.txt
├── packages.config
├── MainActivity.cs
└── VMFirstNav.Demo.Droid.csproj
├── VMFirstNav
├── IViewModel.cs
├── IMasterListItem.cs
├── IViewFor.cs
├── MasterListItem.cs
├── VMFirstNav.csproj
├── INavigationService.cs
└── NavigationService.cs
├── VMFirstNav.Demo
├── packages.config
├── VMFirstNav.DemoPage.xaml.cs
├── App.xaml
├── VMFirstNav.DemoPage.xaml
├── Views
│ ├── MasterDetailRootPage.xaml.cs
│ ├── Tabs
│ │ ├── TabOneView.xaml
│ │ ├── TabTwoView.xaml
│ │ ├── TabOneChildView.xaml
│ │ ├── TabTwoChildView.xaml
│ │ ├── TabOneView.xaml.cs
│ │ ├── TabTwoView.xaml.cs
│ │ ├── TabOneChildView.xaml.cs
│ │ └── TabTwoChildView.xaml.cs
│ ├── Normal
│ │ ├── NormalModalPage.xaml
│ │ ├── NormalOnePage.xaml
│ │ ├── NormalChildTwoPage.xaml
│ │ ├── NormalChildThreePage.xaml
│ │ ├── NormalOneChildPage.xaml
│ │ ├── NormalOnePage.xaml.cs
│ │ ├── NormalChildThreePage.xaml.cs
│ │ ├── NormalModalPage.xaml.cs
│ │ ├── NormalChildTwoPage.xaml.cs
│ │ └── NormalOneChildPage.xaml.cs
│ ├── RootTabPage.xaml
│ ├── MasterDetail
│ │ ├── MasterListNavPage.xaml.cs
│ │ └── MasterListNavPage.xaml
│ ├── MasterDetailRootPage.xaml
│ └── RootTabPage.xaml.cs
├── ViewModels
│ ├── Tabs
│ │ ├── RootTabViewModel.cs
│ │ ├── TabTwoChildViewModel.cs
│ │ ├── TabTwoViewModel.cs
│ │ ├── TabOneViewModel.cs
│ │ └── TabOneChildViewModel.cs
│ ├── Normal
│ │ ├── NormalChildTwoViewModel.cs
│ │ ├── NormalModalViewModel.cs
│ │ ├── NormalChildThreeViewModel.cs
│ │ ├── NormalOneViewModel.cs
│ │ └── NormalOneChildViewModel.cs
│ └── MasterDetail
│ │ └── MasterListNavViewModel.cs
├── Converters
│ └── SelectedItemEventArgsToSelectedItemConverter.cs
├── App.xaml.cs
├── Properties
│ └── AssemblyInfo.cs
├── Behaviors
│ └── ListViewSelectedItemBehavior.cs
└── VMFirstNav.Demo.csproj
├── changelog.md
├── appveyor.yml
├── LICENSE
├── .gitignore
├── README.md
├── bootstrapper.ps1
└── VMFirstNav.sln
/art/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codemillmatt/codemill.vmfirstnav/HEAD/art/logo.png
--------------------------------------------------------------------------------
/iOS/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Droid/Resources/drawable/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codemillmatt/codemill.vmfirstnav/HEAD/Droid/Resources/drawable/icon.png
--------------------------------------------------------------------------------
/Droid/Resources/drawable-hdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codemillmatt/codemill.vmfirstnav/HEAD/Droid/Resources/drawable-hdpi/icon.png
--------------------------------------------------------------------------------
/Droid/Resources/drawable-xhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codemillmatt/codemill.vmfirstnav/HEAD/Droid/Resources/drawable-xhdpi/icon.png
--------------------------------------------------------------------------------
/Droid/Resources/drawable-xxhdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/codemillmatt/codemill.vmfirstnav/HEAD/Droid/Resources/drawable-xxhdpi/icon.png
--------------------------------------------------------------------------------
/VMFirstNav/IViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | namespace CodeMill.VMFirstNav
3 | {
4 | // Marker interface
5 | public interface IViewModel
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/iOS/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/VMFirstNav/IMasterListItem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace CodeMill.VMFirstNav
4 | {
5 | public interface IMasterListItem where T : class, IViewModel
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/iOS/Entitlements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/VMFirstNav.DemoPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using Xamarin.Forms;
2 |
3 | namespace VMFirstNav.Demo
4 | {
5 | public partial class VMFirstNav_DemoPage : ContentPage
6 | {
7 | public VMFirstNav_DemoPage()
8 | {
9 | InitializeComponent();
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/VMFirstNav/IViewFor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | namespace CodeMill.VMFirstNav
3 | {
4 | // IViewFor should only be a marker interface
5 | public interface IViewFor { }
6 |
7 | public interface IViewFor : IViewFor where T : IViewModel
8 | {
9 | T ViewModel { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/App.xaml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/VMFirstNav/MasterListItem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | namespace CodeMill.VMFirstNav
3 | {
4 | public class MasterListItem : IMasterListItem where T : class, IViewModel
5 | {
6 | public string DisplayName { get; set; }
7 |
8 | public MasterListItem(string displayName)
9 | {
10 | DisplayName = displayName;
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Droid/Properties/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/VMFirstNav.DemoPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Droid/Resources/layout/Toolbar.axml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/changelog.md:
--------------------------------------------------------------------------------
1 | - 1.0.1.31 - Added a fix to check if VM already registered. See [PR #14](https://github.com/codemillmatt/codemill.vmfirstnav/pull/14).
2 | - 0.0.9999 - 1.0.0.22 - Basic setting up of CI and Nuget - see [ReadMe](https://github.com/codemillmatt/codemill.vmfirstnav/blob/master/README.md) and this [blog post](https://codemilltech.com/xamarin-forms-viewmodel-first-navigation-library) for details on how to use the library.
3 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: 1.0.1.{build}
2 | image: Visual Studio 2017
3 | assembly_info:
4 | patch: true
5 | assembly_version: '{version}'
6 | assembly_file_version: '{version}'
7 | assembly_informational_version: '{version}'
8 | branches:
9 | only:
10 | - master
11 | build_script:
12 | - cmd: >-
13 | nuget restore .\VMFirstNav.sln
14 |
15 | powershell .\bootstrapper.ps1 -Target NuGetPack -Verbosity diagnostic
16 | artifacts:
17 | - path: '*.nupkg'
18 | name: NuGet
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/MasterDetailRootPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | using Xamarin.Forms;
5 |
6 | namespace VMFirstNav.Demo
7 | {
8 | public partial class MasterDetailRootPage : MasterDetailPage
9 | {
10 | public MasterDetailRootPage()
11 | {
12 | InitializeComponent();
13 |
14 | listNav.ViewModel = new MasterListNavViewModel();
15 | normalOne.ViewModel = new NormalOneViewModel();
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Droid/Resources/layout/Tabbar.axml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/iOS/Main.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | using Foundation;
6 | using UIKit;
7 |
8 | namespace VMFirstNav.Demo.iOS
9 | {
10 | public class Application
11 | {
12 | // This is the main entry point of the application.
13 | static void Main(string[] args)
14 | {
15 | // if you want to use a different Application Delegate class from "AppDelegate"
16 | // you can specify it here.
17 | UIApplication.Main(args, null, "AppDelegate");
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/Tabs/TabOneView.xaml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/Tabs/TabTwoView.xaml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/Tabs/TabOneChildView.xaml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/Tabs/TabTwoChildView.xaml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/Normal/NormalModalPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/Normal/NormalOnePage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/Normal/NormalChildTwoPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/Normal/NormalChildThreePage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/VMFirstNav/VMFirstNav.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard1.0
5 | CodeMill.VMFirstNav
6 | CodeMill.VMFirstNav
7 | portable-net45+win8+wpa81+wp8
8 | codemill.VMFirstNav
9 | Matt Soucoup
10 | Code Mill Technologies, Inc
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/ViewModels/Tabs/RootTabViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using CodeMill.VMFirstNav;
4 | namespace VMFirstNav.Demo
5 | {
6 | public class RootTabViewModel : IViewModel, INotifyPropertyChanged
7 | {
8 | public RootTabViewModel()
9 | {
10 | Title = "Root Tabs";
11 | }
12 |
13 | string title;
14 | public string Title
15 | {
16 | get => title;
17 | set
18 | {
19 | title = value;
20 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title)));
21 | }
22 | }
23 |
24 | public event PropertyChangedEventHandler PropertyChanged;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/Normal/NormalOneChildPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/Tabs/TabOneView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | using Xamarin.Forms;
5 | using CodeMill.VMFirstNav;
6 |
7 | namespace VMFirstNav.Demo
8 | {
9 | public partial class TabOneView : ContentPage, IViewFor
10 | {
11 | public TabOneView()
12 | {
13 | InitializeComponent();
14 | }
15 |
16 | TabOneViewModel vm;
17 | public TabOneViewModel ViewModel
18 | {
19 | get => vm;
20 | set
21 | {
22 | vm = value;
23 | BindingContext = vm;
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/Tabs/TabTwoView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | using Xamarin.Forms;
5 | using CodeMill.VMFirstNav;
6 |
7 | namespace VMFirstNav.Demo
8 | {
9 | public partial class TabTwoView : ContentPage, IViewFor
10 | {
11 | public TabTwoView()
12 | {
13 | InitializeComponent();
14 | }
15 |
16 | TabTwoViewModel vm;
17 | public TabTwoViewModel ViewModel
18 | {
19 | get => vm;
20 | set {
21 | vm = value;
22 | BindingContext = vm;
23 | }
24 |
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/RootTabPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/Normal/NormalOnePage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | using Xamarin.Forms;
5 | using CodeMill.VMFirstNav;
6 |
7 | namespace VMFirstNav.Demo
8 | {
9 | public partial class NormalOnePage : ContentPage, IViewFor
10 | {
11 | public NormalOnePage()
12 | {
13 | InitializeComponent();
14 | }
15 |
16 | NormalOneViewModel vm;
17 | public NormalOneViewModel ViewModel
18 | {
19 | get => vm;
20 | set
21 | {
22 | vm = value;
23 | BindingContext = vm;
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Droid/Assets/AboutAssets.txt:
--------------------------------------------------------------------------------
1 | Any raw assets you want to be deployed with your application can be placed in
2 | this directory (and child directories) and given a Build Action of "AndroidAsset".
3 |
4 | These files will be deployed with your package and will be accessible using Android's
5 | AssetManager, like this:
6 |
7 | public class ReadAsset : Activity
8 | {
9 | protected override void OnCreate (Bundle bundle)
10 | {
11 | base.OnCreate (bundle);
12 |
13 | InputStream input = Assets.Open ("my_asset.txt");
14 | }
15 | }
16 |
17 | Additionally, some Android functions will automatically load asset files:
18 |
19 | Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
20 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/MasterDetail/MasterListNavPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | using Xamarin.Forms;
5 | using CodeMill.VMFirstNav;
6 |
7 | namespace VMFirstNav.Demo
8 | {
9 | public partial class MasterListNavPage : ContentPage, IViewFor
10 | {
11 | public MasterListNavPage()
12 | {
13 | InitializeComponent();
14 | }
15 |
16 | MasterListNavViewModel vm;
17 | public MasterListNavViewModel ViewModel { get => vm;
18 | set
19 | {
20 | vm = value;
21 | BindingContext = vm;
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/Tabs/TabOneChildView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | using Xamarin.Forms;
5 | using CodeMill.VMFirstNav;
6 |
7 | namespace VMFirstNav.Demo
8 | {
9 | public partial class TabOneChildView : ContentPage, IViewFor
10 | {
11 | public TabOneChildView()
12 | {
13 | InitializeComponent();
14 | }
15 |
16 | TabOneChildViewModel vm;
17 | public TabOneChildViewModel ViewModel
18 | {
19 | get => vm;
20 | set
21 | {
22 | vm = value;
23 | BindingContext = vm;
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/Tabs/TabTwoChildView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | using Xamarin.Forms;
5 | using CodeMill.VMFirstNav;
6 |
7 | namespace VMFirstNav.Demo
8 | {
9 | public partial class TabTwoChildView : ContentPage, IViewFor
10 | {
11 | public TabTwoChildView()
12 | {
13 | InitializeComponent();
14 | }
15 |
16 | TabTwoChildViewModel vm;
17 | public TabTwoChildViewModel ViewModel
18 | {
19 | get => vm;
20 | set
21 | {
22 | vm = value;
23 | BindingContext = vm;
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/Normal/NormalChildThreePage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | using Xamarin.Forms;
5 | using CodeMill.VMFirstNav;
6 |
7 | namespace VMFirstNav.Demo
8 | {
9 | public partial class NormalChildThreePage : ContentPage, IViewFor
10 | {
11 | public NormalChildThreePage()
12 | {
13 | InitializeComponent();
14 | }
15 |
16 | NormalChildThreeViewModel vm;
17 | public NormalChildThreeViewModel ViewModel {
18 | get => vm;
19 | set {
20 | vm = value;
21 | BindingContext = vm;
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/Normal/NormalModalPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | using Xamarin.Forms;
5 | using CodeMill.VMFirstNav;
6 |
7 | namespace VMFirstNav.Demo
8 | {
9 | public partial class NormalModalPage : ContentPage, IViewFor
10 | {
11 | public NormalModalPage()
12 | {
13 | InitializeComponent();
14 | }
15 |
16 | NormalModalViewModel vm;
17 | public NormalModalViewModel ViewModel
18 | {
19 | get => vm;
20 | set
21 | {
22 | vm = value;
23 | BindingContext = vm;
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/Normal/NormalChildTwoPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | using Xamarin.Forms;
5 | using CodeMill.VMFirstNav;
6 |
7 | namespace VMFirstNav.Demo
8 | {
9 | public partial class NormalChildTwoPage : ContentPage, IViewFor
10 | {
11 | public NormalChildTwoPage()
12 | {
13 | InitializeComponent();
14 | }
15 |
16 | NormalChildTwoViewModel vm;
17 | public NormalChildTwoViewModel ViewModel {
18 | get => vm;
19 | set
20 | {
21 | vm = value;
22 | BindingContext = vm;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/Normal/NormalOneChildPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | using Xamarin.Forms;
5 | using CodeMill.VMFirstNav;
6 |
7 | namespace VMFirstNav.Demo
8 | {
9 | public partial class NormalOneChildPage : ContentPage, IViewFor
10 | {
11 | public NormalOneChildPage()
12 | {
13 | InitializeComponent();
14 | }
15 |
16 | NormalOneChildViewModel vm;
17 | public NormalOneChildViewModel ViewModel
18 | {
19 | get => vm;
20 | set
21 | {
22 | vm = value;
23 | BindingContext = vm;
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/MasterDetailRootPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/iOS/AppDelegate.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | using Foundation;
6 | using UIKit;
7 | using CodeMill.VMFirstNav;
8 |
9 | namespace VMFirstNav.Demo.iOS
10 | {
11 | [Register("AppDelegate")]
12 | public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
13 | {
14 | public override bool FinishedLaunching(UIApplication app, NSDictionary options)
15 | {
16 | global::Xamarin.Forms.Forms.Init();
17 |
18 | LoadApplication(new App());
19 |
20 | NavigationService.Instance.RegisterViewModels(typeof(App).Assembly);
21 |
22 | return base.FinishedLaunching(app, options);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/RootTabPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | using Xamarin.Forms;
5 | using CodeMill.VMFirstNav;
6 |
7 | namespace VMFirstNav.Demo
8 | {
9 | public partial class RootTabPage : TabbedPage, IViewFor
10 | {
11 | public RootTabPage()
12 | {
13 | InitializeComponent();
14 |
15 | tabOne.ViewModel = new TabOneViewModel();
16 | tabTwo.ViewModel = new TabTwoViewModel();
17 | }
18 |
19 | RootTabViewModel vm;
20 | public RootTabViewModel ViewModel
21 | {
22 | get => vm;
23 | set
24 | {
25 | vm = value;
26 | BindingContext = vm;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Converters/SelectedItemEventArgsToSelectedItemConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using Xamarin.Forms;
4 |
5 | namespace VMFirstNav.Demo
6 | {
7 | ///
8 | /// Selected item event arguments to selected item converter.
9 | /// Thanks David Britch!
10 | /// https://github.com/davidbritch/xamarin-forms/tree/master/ItemSelectedBehavior
11 | ///
12 | public class SelectedItemEventArgsToSelectedItemConverter : IValueConverter
13 | {
14 | public SelectedItemEventArgsToSelectedItemConverter()
15 | {
16 | }
17 |
18 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
19 | {
20 | var eventArgs = value as SelectedItemChangedEventArgs;
21 | return eventArgs?.SelectedItem;
22 | }
23 |
24 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
25 | {
26 | throw new NotImplementedException();
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Droid/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Droid/MainActivity.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | using Android.App;
4 | using Android.Content;
5 | using Android.Content.PM;
6 | using Android.Runtime;
7 | using Android.Views;
8 | using Android.Widget;
9 | using Android.OS;
10 | using CodeMill.VMFirstNav;
11 |
12 | namespace VMFirstNav.Demo.Droid
13 | {
14 | [Activity(Label = "VMFirstNav.Demo.Droid", Icon = "@drawable/icon", Theme = "@style/MyTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
15 | public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
16 | {
17 | protected override void OnCreate(Bundle bundle)
18 | {
19 | TabLayoutResource = Resource.Layout.Tabbar;
20 | ToolbarResource = Resource.Layout.Toolbar;
21 |
22 | base.OnCreate(bundle);
23 |
24 | global::Xamarin.Forms.Forms.Init(this, bundle);
25 |
26 | NavigationService.Instance.RegisterViewModels(typeof(App).Assembly);
27 |
28 | LoadApplication(new App());
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/VMFirstNav/INavigationService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 |
4 | namespace CodeMill.VMFirstNav
5 | {
6 | public interface INavigationService
7 | {
8 | void RegisterViewModels(System.Reflection.Assembly asm);
9 | void Register(Type viewModelType, Type viewType);
10 |
11 | Task PopAsync();
12 | Task PopModalAsync();
13 | void PopTo() where T : class, IViewModel;
14 | Task PopAsync(Action reInitialize = null) where T : class, IViewModel;
15 | Task PushAsync(T viewModel) where T : class, IViewModel;
16 | Task PushAsync(Action initialize = null) where T : class, IViewModel;
17 | Task PushModalAsync(Action initialize = null) where T : class, IViewModel;
18 | Task PushModalAsync(T viewModel) where T : class, IViewModel;
19 | Task PopToRootAsync(bool animate);
20 | void SwitchDetailPage(Action initialize = null) where T : class, IViewModel;
21 | void SwitchDetailPage(T viewModel) where T : class, IViewModel;
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/ViewModels/Normal/NormalChildTwoViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using CodeMill.VMFirstNav;
3 | using System.ComponentModel;
4 | using Xamarin.Forms;
5 |
6 | namespace VMFirstNav.Demo
7 | {
8 | public class NormalChildTwoViewModel : IViewModel, INotifyPropertyChanged
9 | {
10 | INavigationService _navService;
11 | public NormalChildTwoViewModel()
12 | {
13 | Title = "Normal Two";
14 | _navService = NavigationService.Instance;
15 | }
16 |
17 | string title;
18 | public string Title
19 | {
20 | get => title;
21 | set
22 | {
23 | title = value;
24 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title)));
25 | }
26 | }
27 |
28 | Command _navigateThree;
29 |
30 | public event PropertyChangedEventHandler PropertyChanged;
31 |
32 | public Command NavigateThree
33 | {
34 | get
35 | {
36 | if (_navigateThree == null)
37 | {
38 | _navigateThree = new Command(async () => await _navService.PushAsync());
39 | }
40 |
41 | return _navigateThree;
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/ViewModels/Normal/NormalModalViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using CodeMill.VMFirstNav;
3 | using System.ComponentModel;
4 | using System.Windows.Input;
5 | using Xamarin.Forms;
6 |
7 | namespace VMFirstNav.Demo
8 | {
9 | public class NormalModalViewModel : IViewModel, INotifyPropertyChanged
10 | {
11 | INavigationService _navService;
12 |
13 | public NormalModalViewModel()
14 | {
15 | Title = "Normal Modal";
16 |
17 | _navService = NavigationService.Instance;
18 | }
19 |
20 | string title;
21 | public string Title
22 | {
23 | get => title;
24 | set
25 | {
26 | title = value;
27 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title)));
28 | }
29 | }
30 |
31 | ICommand _dismissModal;
32 |
33 | public event PropertyChangedEventHandler PropertyChanged;
34 |
35 | public ICommand DismissModalCommand
36 | {
37 | get
38 | {
39 | if (_dismissModal == null)
40 | {
41 | _dismissModal = new Command(async () => await _navService.PopModalAsync());
42 | }
43 | return _dismissModal;
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Matt Soucoup
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/ViewModels/Normal/NormalChildThreeViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using CodeMill.VMFirstNav;
3 | using System.Runtime.CompilerServices;
4 | using System.ComponentModel;
5 | using Xamarin.Forms;
6 |
7 | namespace VMFirstNav.Demo
8 | {
9 | public class NormalChildThreeViewModel : IViewModel, INotifyPropertyChanged
10 | {
11 | INavigationService _navService;
12 |
13 | public NormalChildThreeViewModel()
14 | {
15 | Title = "Three";
16 | _navService = NavigationService.Instance;
17 | }
18 |
19 | string title;
20 | public string Title
21 | {
22 | get => title;
23 | set
24 | {
25 | title = value;
26 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title)));
27 | }
28 | }
29 |
30 | Command _navigateOne;
31 |
32 | public event PropertyChangedEventHandler PropertyChanged;
33 |
34 | public Command NavigateOne
35 | {
36 | get
37 | {
38 | if (_navigateOne == null)
39 | {
40 | _navigateOne = new Command(() => _navService.PopTo());
41 | }
42 |
43 | return _navigateOne;
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/ViewModels/Tabs/TabTwoChildViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Windows.Input;
4 | using CodeMill.VMFirstNav;
5 | using Xamarin.Forms;
6 |
7 | namespace VMFirstNav.Demo
8 | {
9 | public class TabTwoChildViewModel : IViewModel, INotifyPropertyChanged
10 | {
11 | readonly INavigationService _navService;
12 | public TabTwoChildViewModel()
13 | {
14 | Title = "Tab Two Child";
15 |
16 | _navService = NavigationService.Instance;
17 | }
18 |
19 | string title;
20 | public string Title
21 | {
22 | get => title;
23 | set
24 | {
25 | title = value;
26 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title)));
27 | }
28 | }
29 |
30 |
31 | ICommand _navToParent;
32 |
33 | public event PropertyChangedEventHandler PropertyChanged;
34 |
35 | public ICommand NavigateBack
36 | {
37 | get
38 | {
39 | if (_navToParent == null)
40 | {
41 | _navToParent = new Command(async () =>
42 | await _navService.PopAsync()
43 | );
44 | }
45 | return _navToParent;
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/ViewModels/Tabs/TabTwoViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Windows.Input;
4 | using CodeMill.VMFirstNav;
5 | using Xamarin.Forms;
6 |
7 | namespace VMFirstNav.Demo
8 | {
9 | public class TabTwoViewModel : IViewModel, INotifyPropertyChanged
10 | {
11 | readonly INavigationService _navService;
12 | public TabTwoViewModel()
13 | {
14 | Title = "Tab Two";
15 |
16 | _navService = NavigationService.Instance;
17 | }
18 |
19 | string title;
20 | public string Title
21 | {
22 | get => title;
23 | set
24 | {
25 | title = value;
26 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title)));
27 | }
28 | }
29 |
30 | ICommand _navToChild;
31 |
32 | public event PropertyChangedEventHandler PropertyChanged;
33 |
34 | public ICommand NavigateToChild
35 | {
36 | get
37 | {
38 | if (_navToChild == null)
39 | {
40 | _navToChild = new Command(async () =>
41 | {
42 | await _navService.PushAsync();
43 | });
44 | }
45 | return _navToChild;
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using Xamarin.Forms;
2 |
3 | namespace VMFirstNav.Demo
4 | {
5 | public partial class App : Application
6 | {
7 | public App()
8 | {
9 | InitializeComponent();
10 |
11 |
12 | // ******
13 | // MasterDetail Pages
14 | MainPage = new MasterDetailRootPage();
15 | // ******
16 |
17 | // ******
18 | // Tab pages
19 | // MainPage = new RootTabPage();
20 | // ******
21 |
22 |
23 | // ******
24 | // Sets up a normal navigation stack
25 |
26 | //var normalVM = new NormalOneViewModel();
27 | // var normalPage = new NormalOnePage { ViewModel = normalVM };
28 |
29 | //MainPage = new NavigationPage(normalPage);
30 | // ******
31 | }
32 |
33 | protected override void OnStart()
34 | {
35 | // Handle when your app starts
36 | }
37 |
38 | protected override void OnSleep()
39 | {
40 | // Handle when your app sleeps
41 | }
42 |
43 | protected override void OnResume()
44 | {
45 | // Handle when your app resumes
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 |
4 | // Information about this assembly is defined by the following attributes.
5 | // Change them to the values specific to your project.
6 |
7 | [assembly: AssemblyTitle("VMFirstNav.Demo")]
8 | [assembly: AssemblyDescription("")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("Code Mill Technologies, Inc")]
11 | [assembly: AssemblyProduct("")]
12 | [assembly: AssemblyCopyright("2017 - All Rights Reserved")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
17 | // The form "{Major}.{Minor}.*" will automatically update the build and revision,
18 | // and "{Major}.{Minor}.{Build}.*" will update just the revision.
19 |
20 | [assembly: AssemblyVersion("1.0.*")]
21 |
22 | // The following attributes are used to specify the signing key for the assembly,
23 | // if desired. See the Mono documentation for more information about signing.
24 |
25 | //[assembly: AssemblyDelaySign(false)]
26 | //[assembly: AssemblyKeyFile("")]
27 |
--------------------------------------------------------------------------------
/Droid/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using Android.App;
4 |
5 | // Information about this assembly is defined by the following attributes.
6 | // Change them to the values specific to your project.
7 |
8 | [assembly: AssemblyTitle("VMFirstNav.Demo.Droid")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Code Mill Technologies, Inc")]
12 | [assembly: AssemblyProduct("")]
13 | [assembly: AssemblyCopyright("2017 - All Rights Reserved")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
18 | // The form "{Major}.{Minor}.*" will automatically update the build and revision,
19 | // and "{Major}.{Minor}.{Build}.*" will update just the revision.
20 |
21 | [assembly: AssemblyVersion("1.0.0")]
22 |
23 | // The following attributes are used to specify the signing key for the assembly,
24 | // if desired. See the Mono documentation for more information about signing.
25 |
26 | //[assembly: AssemblyDelaySign(false)]
27 | //[assembly: AssemblyKeyFile("")]
28 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/ViewModels/Tabs/TabOneViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using CodeMill.VMFirstNav;
3 | using System.ComponentModel;
4 | using System.Windows.Input;
5 | using Xamarin.Forms;
6 |
7 | namespace VMFirstNav.Demo
8 | {
9 | public class TabOneViewModel : IViewModel, INotifyPropertyChanged
10 | {
11 | readonly INavigationService _navService;
12 | public TabOneViewModel()
13 | {
14 | Title = "Tab One";
15 |
16 | _navService = NavigationService.Instance;
17 | }
18 |
19 | string title;
20 | public string Title
21 | {
22 | get => title;
23 | set
24 | {
25 | title = value;
26 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title)));
27 | }
28 | }
29 |
30 |
31 | ICommand _navToChild;
32 |
33 | public event PropertyChangedEventHandler PropertyChanged;
34 |
35 | public ICommand NavigateToChild
36 | {
37 | get
38 | {
39 | if (_navToChild == null)
40 | {
41 | _navToChild = new Command(async () =>
42 | {
43 | await _navService.PushAsync((vm) => vm.InitializeDisplay("Title from initialization routine"));
44 | }
45 | );
46 | }
47 | return _navToChild;
48 | }
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/ViewModels/Tabs/TabOneChildViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Windows.Input;
4 | using CodeMill.VMFirstNav;
5 | using Xamarin.Forms;
6 |
7 | namespace VMFirstNav.Demo
8 | {
9 | public class TabOneChildViewModel : IViewModel, INotifyPropertyChanged
10 | {
11 | readonly INavigationService _navService;
12 | public TabOneChildViewModel()
13 | {
14 | Title = "Tab One Child";
15 |
16 | _navService = NavigationService.Instance;
17 | }
18 |
19 | string title;
20 | public string Title
21 | {
22 | get => title;
23 | set
24 | {
25 | title = value;
26 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title)));
27 | }
28 | }
29 |
30 | public void InitializeDisplay(string theTitle)
31 | {
32 | Title = theTitle;
33 | }
34 |
35 | ICommand _navToParent;
36 |
37 | public event PropertyChangedEventHandler PropertyChanged;
38 |
39 | public ICommand NavigateBack
40 | {
41 | get
42 | {
43 | if (_navToParent == null)
44 | {
45 | _navToParent = new Command(async () =>
46 | await _navService.PopAsync(tovm => tovm.Title = "Back to the future")
47 | );
48 | }
49 | return _navToParent;
50 | }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Droid/Resources/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
24 |
27 |
28 |
--------------------------------------------------------------------------------
/iOS/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/ViewModels/Normal/NormalOneViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using CodeMill.VMFirstNav;
3 | using System.ComponentModel;
4 | using System.Windows.Input;
5 | using Xamarin.Forms;
6 |
7 | namespace VMFirstNav.Demo
8 | {
9 | public class NormalOneViewModel : IViewModel, INotifyPropertyChanged
10 | {
11 | INavigationService _navService;
12 |
13 | public NormalOneViewModel()
14 | {
15 | Title = "Normal";
16 |
17 | _navService = NavigationService.Instance;
18 |
19 | Description = "Normal navigation stack only";
20 | }
21 |
22 | string title;
23 | public string Title
24 | {
25 | get => title;
26 | set
27 | {
28 | title = value;
29 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title)));
30 | }
31 | }
32 |
33 | string _description;
34 | public string Description
35 | {
36 | get => _description;
37 | set
38 | {
39 | _description = value;
40 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Description)));
41 | }
42 | }
43 |
44 | ICommand _navToChild;
45 |
46 | public event PropertyChangedEventHandler PropertyChanged;
47 |
48 | public ICommand NavigateToChild
49 | {
50 | get
51 | {
52 | if (_navToChild == null)
53 | {
54 | _navToChild = new Command(async () =>
55 | {
56 | await _navService.PushAsync((vm) => vm.InitializeDisplay("Normal child!"));
57 | }
58 | );
59 | }
60 | return _navToChild;
61 | }
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDisplayName
6 | VMFirstNav.Demo
7 | CFBundleName
8 | VMFirstNav.Demo
9 | CFBundleIdentifier
10 | com.codemilltech.vmfirstnav-demo
11 | CFBundleShortVersionString
12 | 1.0
13 | CFBundleVersion
14 | 1.0
15 | LSRequiresIPhoneOS
16 |
17 | MinimumOSVersion
18 | 8.0
19 | UIDeviceFamily
20 |
21 | 1
22 | 2
23 |
24 | UILaunchStoryboardName
25 | LaunchScreen
26 | UIRequiredDeviceCapabilities
27 |
28 | armv7
29 |
30 | UISupportedInterfaceOrientations
31 |
32 | UIInterfaceOrientationPortrait
33 | UIInterfaceOrientationLandscapeLeft
34 | UIInterfaceOrientationLandscapeRight
35 |
36 | UISupportedInterfaceOrientations~ipad
37 |
38 | UIInterfaceOrientationPortrait
39 | UIInterfaceOrientationPortraitUpsideDown
40 | UIInterfaceOrientationLandscapeLeft
41 | UIInterfaceOrientationLandscapeRight
42 |
43 | XSAppIconAssets
44 | Assets.xcassets/AppIcon.appiconset
45 |
46 |
47 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Views/MasterDetail/MasterListNavPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Droid/Resources/AboutResources.txt:
--------------------------------------------------------------------------------
1 | Images, layout descriptions, binary blobs and string dictionaries can be included
2 | in your application as resource files. Various Android APIs are designed to
3 | operate on the resource IDs instead of dealing with images, strings or binary blobs
4 | directly.
5 |
6 | For example, a sample Android app that contains a user interface layout (main.axml),
7 | an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
8 | would keep its resources in the "Resources" directory of the application:
9 |
10 | Resources/
11 | drawable/
12 | icon.png
13 |
14 | layout/
15 | main.axml
16 |
17 | values/
18 | strings.xml
19 |
20 | In order to get the build system to recognize Android resources, set the build action to
21 | "AndroidResource". The native Android APIs do not operate directly with filenames, but
22 | instead operate on resource IDs. When you compile an Android application that uses resources,
23 | the build system will package the resources for distribution and generate a class called "R"
24 | (this is an Android convention) that contains the tokens for each one of the resources
25 | included. For example, for the above Resources layout, this is what the R class would expose:
26 |
27 | public class R {
28 | public class drawable {
29 | public const int icon = 0x123;
30 | }
31 |
32 | public class layout {
33 | public const int main = 0x456;
34 | }
35 |
36 | public class strings {
37 | public const int first_string = 0xabc;
38 | public const int second_string = 0xbcd;
39 | }
40 | }
41 |
42 | You would then use R.drawable.icon to reference the drawable/icon.png file, or R.layout.main
43 | to reference the layout/main.axml file, or R.strings.first_string to reference the first
44 | string in the dictionary file values/strings.xml.
45 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/ViewModels/Normal/NormalOneChildViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Windows.Input;
4 | using CodeMill.VMFirstNav;
5 | using Xamarin.Forms;
6 |
7 | namespace VMFirstNav.Demo
8 | {
9 | public class NormalOneChildViewModel : IViewModel, INotifyPropertyChanged
10 | {
11 | INavigationService _navService;
12 | public NormalOneChildViewModel()
13 | {
14 | Title = "Normal Child";
15 |
16 | _navService = NavigationService.Instance;
17 | }
18 |
19 | string title;
20 | public string Title
21 | {
22 | get => title;
23 | set
24 | {
25 | title = value;
26 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title)));
27 | }
28 | }
29 |
30 | public void InitializeDisplay(string description)
31 | {
32 | Description = description;
33 | }
34 |
35 | string _description;
36 | public string Description
37 | {
38 | get => _description;
39 | set
40 | {
41 | _description = value;
42 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Description)));
43 | }
44 | }
45 |
46 | ICommand _navToChild;
47 | public ICommand NavigatePopup
48 | {
49 | get
50 | {
51 | if (_navToChild == null)
52 | {
53 | _navToChild = new Command(async () =>
54 | {
55 | await _navService.PushModalAsync();
56 | });
57 | }
58 | return _navToChild;
59 | }
60 | }
61 |
62 | Command _navigateTwo;
63 |
64 | public event PropertyChangedEventHandler PropertyChanged;
65 |
66 | public Command NavigateTwo
67 | {
68 | get
69 | {
70 | if (_navigateTwo == null)
71 | _navigateTwo = new Command(async () => await _navService.PushAsync());
72 |
73 | return _navigateTwo;
74 | }
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/Behaviors/ListViewSelectedItemBehavior.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows.Input;
3 | using Xamarin.Forms;
4 |
5 | namespace VMFirstNav.Demo
6 | {
7 | ///
8 | /// List view selected item behavior.
9 | /// Used to give the list view's ItemSelected event a command to bind to
10 | /// See this: https://blog.xamarin.com/turn-events-into-commands-with-behaviors/
11 | ///
12 | public class ListViewSelectedItemBehavior : Behavior
13 | {
14 | public static readonly BindableProperty CommandProperty =
15 | BindableProperty.Create("Command", typeof(ICommand), typeof(ListViewSelectedItemBehavior), null);
16 | public static readonly BindableProperty InputConverterProperty =
17 | BindableProperty.Create("Converter", typeof(IValueConverter), typeof(ListViewSelectedItemBehavior), null);
18 |
19 | public ICommand Command
20 | {
21 | get { return (ICommand)GetValue(CommandProperty); }
22 | set { SetValue(CommandProperty, value); }
23 | }
24 |
25 | public IValueConverter Converter
26 | {
27 | get { return (IValueConverter)GetValue(InputConverterProperty); }
28 | set { SetValue(InputConverterProperty, value); }
29 | }
30 |
31 | public ListView AssociatedObject { get; private set; }
32 |
33 | protected override void OnAttachedTo(ListView bindable)
34 | {
35 | base.OnAttachedTo(bindable);
36 | AssociatedObject = bindable;
37 | bindable.BindingContextChanged += OnBindingContextChanged;
38 | bindable.ItemSelected += OnListViewItemSelected;
39 | }
40 |
41 | protected override void OnDetachingFrom(ListView bindable)
42 | {
43 | base.OnDetachingFrom(bindable);
44 | bindable.BindingContextChanged -= OnBindingContextChanged;
45 | bindable.ItemSelected -= OnListViewItemSelected;
46 | AssociatedObject = null;
47 | }
48 |
49 | void OnBindingContextChanged(object sender, EventArgs e)
50 | {
51 | OnBindingContextChanged();
52 | }
53 |
54 | void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs e)
55 | {
56 | if (Command == null)
57 | {
58 | return;
59 | }
60 |
61 | object parameter = Converter.Convert(e, typeof(object), null, null);
62 | if (Command.CanExecute(parameter))
63 | {
64 | Command.Execute(parameter);
65 | }
66 | }
67 |
68 | protected override void OnBindingContextChanged()
69 | {
70 | base.OnBindingContextChanged();
71 | BindingContext = AssociatedObject.BindingContext;
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/ViewModels/MasterDetail/MasterListNavViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Windows.Input;
4 | using CodeMill.VMFirstNav;
5 | using Xamarin.Forms;
6 | using System.ComponentModel;
7 |
8 | namespace VMFirstNav.Demo
9 | {
10 | public class MasterListNavViewModel : IViewModel, INotifyPropertyChanged
11 | {
12 | INavigationService _navService;
13 |
14 | // The overall list that will keep track of which view models can be navigated
15 | // to and displayed in the "master" portion of master/detail
16 | public List> AvailablePages { get; set; }
17 |
18 |
19 | public MasterListNavViewModel()
20 | {
21 | _navService = NavigationService.Instance;
22 |
23 | // This is where we add the view models we can navigate to
24 | // And the descriptions to be displayed
25 | AvailablePages = new List>();
26 | AvailablePages.Add(new MasterListItem("Normal Nav"));
27 | AvailablePages.Add(new MasterListItem("Tab Pages"));
28 |
29 | Title = "Nav";
30 | }
31 |
32 | string title;
33 | public string Title
34 | {
35 | get => title;
36 | set
37 | {
38 | title = value;
39 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title)));
40 | }
41 | }
42 |
43 | ICommand _navCommand;
44 |
45 | public event PropertyChangedEventHandler PropertyChanged;
46 |
47 | public ICommand NavigateCommand
48 | {
49 | get
50 | {
51 | if (_navCommand == null)
52 | {
53 | _navCommand = new Command((selectedItem) =>
54 | {
55 | // Get the selected item from the command
56 | var itemToNavigate = selectedItem as IMasterListItem;
57 |
58 | if (itemToNavigate != null)
59 | {
60 | // Get the view model type
61 | var viewModelType = itemToNavigate.GetType().GenericTypeArguments[0];
62 |
63 | // Get a view model instance
64 | var viewModel = Activator.CreateInstance(viewModelType) as IViewModel;
65 |
66 | // Perform the switch
67 | _navService.SwitchDetailPage(viewModel);
68 | }
69 | });
70 | }
71 | return _navCommand;
72 | }
73 | }
74 |
75 | public T Cast(object input)
76 | {
77 | return (T)input;
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/iOS/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images": [
3 | {
4 | "idiom": "iphone",
5 | "size": "29x29",
6 | "scale": "1x"
7 | },
8 | {
9 | "idiom": "iphone",
10 | "size": "29x29",
11 | "scale": "2x"
12 | },
13 | {
14 | "idiom": "iphone",
15 | "size": "29x29",
16 | "scale": "3x"
17 | },
18 | {
19 | "idiom": "iphone",
20 | "size": "40x40",
21 | "scale": "2x"
22 | },
23 | {
24 | "idiom": "iphone",
25 | "size": "40x40",
26 | "scale": "3x"
27 | },
28 | {
29 | "idiom": "iphone",
30 | "size": "57x57",
31 | "scale": "1x"
32 | },
33 | {
34 | "idiom": "iphone",
35 | "size": "57x57",
36 | "scale": "2x"
37 | },
38 | {
39 | "idiom": "iphone",
40 | "size": "60x60",
41 | "scale": "2x"
42 | },
43 | {
44 | "idiom": "iphone",
45 | "size": "60x60",
46 | "scale": "3x"
47 | },
48 | {
49 | "idiom": "ipad",
50 | "size": "29x29",
51 | "scale": "1x"
52 | },
53 | {
54 | "idiom": "ipad",
55 | "size": "29x29",
56 | "scale": "2x"
57 | },
58 | {
59 | "idiom": "ipad",
60 | "size": "40x40",
61 | "scale": "1x"
62 | },
63 | {
64 | "idiom": "ipad",
65 | "size": "40x40",
66 | "scale": "2x"
67 | },
68 | {
69 | "idiom": "ipad",
70 | "size": "50x50",
71 | "scale": "1x"
72 | },
73 | {
74 | "idiom": "ipad",
75 | "size": "50x50",
76 | "scale": "2x"
77 | },
78 | {
79 | "idiom": "ipad",
80 | "size": "72x72",
81 | "scale": "1x"
82 | },
83 | {
84 | "idiom": "ipad",
85 | "size": "72x72",
86 | "scale": "2x"
87 | },
88 | {
89 | "idiom": "ipad",
90 | "size": "76x76",
91 | "scale": "1x"
92 | },
93 | {
94 | "idiom": "ipad",
95 | "size": "76x76",
96 | "scale": "2x"
97 | },
98 | {
99 | "size": "24x24",
100 | "idiom": "watch",
101 | "scale": "2x",
102 | "role": "notificationCenter",
103 | "subtype": "38mm"
104 | },
105 | {
106 | "size": "27.5x27.5",
107 | "idiom": "watch",
108 | "scale": "2x",
109 | "role": "notificationCenter",
110 | "subtype": "42mm"
111 | },
112 | {
113 | "size": "29x29",
114 | "idiom": "watch",
115 | "role": "companionSettings",
116 | "scale": "2x"
117 | },
118 | {
119 | "size": "29x29",
120 | "idiom": "watch",
121 | "role": "companionSettings",
122 | "scale": "3x"
123 | },
124 | {
125 | "size": "40x40",
126 | "idiom": "watch",
127 | "scale": "2x",
128 | "role": "appLauncher",
129 | "subtype": "38mm"
130 | },
131 | {
132 | "size": "44x44",
133 | "idiom": "watch",
134 | "scale": "2x",
135 | "role": "longLook",
136 | "subtype": "42mm"
137 | },
138 | {
139 | "size": "86x86",
140 | "idiom": "watch",
141 | "scale": "2x",
142 | "role": "quickLook",
143 | "subtype": "38mm"
144 | },
145 | {
146 | "size": "98x98",
147 | "idiom": "watch",
148 | "scale": "2x",
149 | "role": "quickLook",
150 | "subtype": "42mm"
151 | }
152 | ],
153 | "info": {
154 | "version": 1,
155 | "author": "xcode"
156 | }
157 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # .NET Core
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 | **/Properties/launchSettings.json
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # Visual Studio code coverage results
117 | *.coverage
118 | *.coveragexml
119 |
120 | # NCrunch
121 | _NCrunch_*
122 | .*crunch*.local.xml
123 | nCrunchTemp_*
124 |
125 | # MightyMoose
126 | *.mm.*
127 | AutoTest.Net/
128 |
129 | # Web workbench (sass)
130 | .sass-cache/
131 |
132 | # Installshield output folder
133 | [Ee]xpress/
134 |
135 | # DocProject is a documentation generator add-in
136 | DocProject/buildhelp/
137 | DocProject/Help/*.HxT
138 | DocProject/Help/*.HxC
139 | DocProject/Help/*.hhc
140 | DocProject/Help/*.hhk
141 | DocProject/Help/*.hhp
142 | DocProject/Help/Html2
143 | DocProject/Help/html
144 |
145 | # Click-Once directory
146 | publish/
147 |
148 | # Publish Web Output
149 | *.[Pp]ublish.xml
150 | *.azurePubxml
151 | # TODO: Comment the next line if you want to checkin your web deploy settings
152 | # but database connection strings (with potential passwords) will be unencrypted
153 | *.pubxml
154 | *.publishproj
155 |
156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
157 | # checkin your Azure Web App publish settings, but sensitive information contained
158 | # in these scripts will be unencrypted
159 | PublishScripts/
160 |
161 | # NuGet Packages
162 | *.nupkg
163 | # The packages folder can be ignored because of Package Restore
164 | **/packages/*
165 | # except build/, which is used as an MSBuild target.
166 | !**/packages/build/
167 | # Uncomment if necessary however generally it will be regenerated when needed
168 | #!**/packages/repositories.config
169 | # NuGet v3's project.json files produces more ignorable files
170 | *.nuget.props
171 | *.nuget.targets
172 |
173 | # Microsoft Azure Build Output
174 | csx/
175 | *.build.csdef
176 |
177 | # Microsoft Azure Emulator
178 | ecf/
179 | rcf/
180 |
181 | # Windows Store app package directories and files
182 | AppPackages/
183 | BundleArtifacts/
184 | Package.StoreAssociation.xml
185 | _pkginfo.txt
186 |
187 | # Visual Studio cache files
188 | # files ending in .cache can be ignored
189 | *.[Cc]ache
190 | # but keep track of directories ending in .cache
191 | !*.[Cc]ache/
192 |
193 | # Others
194 | ClientBin/
195 | ~$*
196 | *~
197 | *.dbmdl
198 | *.dbproj.schemaview
199 | *.jfm
200 | *.pfx
201 | *.publishsettings
202 | orleans.codegen.cs
203 |
204 | # Since there are multiple workflows, uncomment next line to ignore bower_components
205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
206 | #bower_components/
207 |
208 | # RIA/Silverlight projects
209 | Generated_Code/
210 |
211 | # Backup & report files from converting an old project file
212 | # to a newer Visual Studio version. Backup files are not needed,
213 | # because we have git ;-)
214 | _UpgradeReport_Files/
215 | Backup*/
216 | UpgradeLog*.XML
217 | UpgradeLog*.htm
218 |
219 | # SQL Server files
220 | *.mdf
221 | *.ldf
222 | *.ndf
223 |
224 | # Business Intelligence projects
225 | *.rdl.data
226 | *.bim.layout
227 | *.bim_*.settings
228 |
229 | # Microsoft Fakes
230 | FakesAssemblies/
231 |
232 | # GhostDoc plugin setting file
233 | *.GhostDoc.xml
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 | node_modules/
238 |
239 | # Typescript v1 declaration files
240 | typings/
241 |
242 | # Visual Studio 6 build log
243 | *.plg
244 |
245 | # Visual Studio 6 workspace options file
246 | *.opt
247 |
248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
249 | *.vbw
250 |
251 | # Visual Studio LightSwitch build output
252 | **/*.HTMLClient/GeneratedArtifacts
253 | **/*.DesktopClient/GeneratedArtifacts
254 | **/*.DesktopClient/ModelManifest.xml
255 | **/*.Server/GeneratedArtifacts
256 | **/*.Server/ModelManifest.xml
257 | _Pvt_Extensions
258 |
259 | # Paket dependency manager
260 | .paket/paket.exe
261 | paket-files/
262 |
263 | # FAKE - F# Make
264 | .fake/
265 |
266 | # JetBrains Rider
267 | .idea/
268 | *.sln.iml
269 |
270 | # CodeRush
271 | .cr/
272 |
273 | # Python Tools for Visual Studio (PTVS)
274 | __pycache__/
275 | *.pyc
276 |
277 | # Cake - Uncomment if you are using it
278 | # tools/**
279 | # !tools/packages.config
280 |
281 | # Telerik's JustMock configuration file
282 | *.jmconfig
283 |
284 | # BizTalk build output
285 | *.btp.cs
286 | *.btm.cs
287 | *.odx.cs
288 | *.xsd.cs
289 |
290 | .droidres/.vmfirstnav.droidres.db
291 |
292 | .droidres/.vmfirstnav.droidres.db
293 |
294 | *.db
295 |
--------------------------------------------------------------------------------
/iOS/VMFirstNav.Demo.iOS.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | iPhoneSimulator
6 | {E91062C4-A4F8-486B-9A6C-326306748405}
7 | {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
8 | Exe
9 | VMFirstNav.Demo.iOS
10 | VMFirstNav.Demo.iOS
11 | Resources
12 |
13 |
14 | true
15 | full
16 | false
17 | bin\iPhoneSimulator\Debug
18 | DEBUG;ENABLE_TEST_CLOUD;
19 | prompt
20 | 4
21 | iPhone Developer
22 | true
23 | true
24 | true
25 | true
26 | true
27 | 31694
28 | None
29 | i386, x86_64
30 | HttpClientHandler
31 |
32 |
33 | pdbonly
34 | true
35 | bin\iPhone\Release
36 |
37 |
38 | prompt
39 | 4
40 | iPhone Developer
41 | true
42 | Entitlements.plist
43 | SdkOnly
44 | ARMv7, ARM64
45 | HttpClientHandler
46 |
47 |
48 | pdbonly
49 | true
50 | bin\iPhoneSimulator\Release
51 |
52 |
53 | prompt
54 | 4
55 | iPhone Developer
56 | true
57 | true
58 | None
59 | i386, x86_64
60 | HttpClientHandler
61 |
62 |
63 | true
64 | full
65 | false
66 | bin\iPhone\Debug
67 | DEBUG;ENABLE_TEST_CLOUD;
68 | prompt
69 | 4
70 | iPhone Developer
71 | true
72 | true
73 | true
74 | true
75 | true
76 | true
77 | Entitlements.plist
78 | 49223
79 | SdkOnly
80 | ARMv7, ARM64
81 | HttpClientHandler
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | ..\packages\Xamarin.Forms.2.3.4.247\lib\Xamarin.iOS10\Xamarin.Forms.Core.dll
90 |
91 |
92 | ..\packages\Xamarin.Forms.2.3.4.247\lib\Xamarin.iOS10\Xamarin.Forms.Platform.dll
93 |
94 |
95 | ..\packages\Xamarin.Forms.2.3.4.247\lib\Xamarin.iOS10\Xamarin.Forms.Platform.iOS.dll
96 |
97 |
98 | ..\packages\Xamarin.Forms.2.3.4.247\lib\Xamarin.iOS10\Xamarin.Forms.Xaml.dll
99 |
100 |
101 |
102 |
103 | false
104 |
105 |
106 | false
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 | {522AF6C4-EB3D-46A9-A7D9-10374DB176A6}
127 | VMFirstNav.Demo
128 |
129 |
130 | {2B91892E-8113-4E9E-982C-7E186FEEB214}
131 | VMFirstNav
132 |
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CodeMill ViewModel First Navigation Library
2 | A Xamarin.Forms ViewModel First Navigation Library
3 |
4 | ### Build Status
5 | 
6 |
7 | ### NuGet
8 | [CodeMill.VMFirstNav](https://www.nuget.org/packages/CodeMill.VMFirstNav/)
9 |
10 | ## Installation
11 | The installation is pretty straight forward - head on out to NuGet and search for [CodeMill.VMFirstNav](https://www.nuget.org/packages/CodeMill.VMFirstNav/). Or you could run `Install-Package CodeMill.VMFirstNav` from the package manager console.
12 |
13 | At this time, this package will need to be installed into both the platform and core projects.
14 |
15 | The library is .netstandard1.0 with a dependency on Xamarin.Forms 2.3.4.247 and above.
16 |
17 | ## The API
18 | There are 3 main interfaces that are a part of this library.
19 | - `IViewModel`
20 | - `IViewFor`
21 | - `INavigationService`
22 |
23 | `IViewModel` and `IViewFor` are used to associate a view->view model pair.
24 |
25 | `IViewModel` is nothing but a marker interface and should be put onto every view model class that is to participate in VM first navigation.
26 |
27 | `IViewFor` goes onto the `Pages` that are associated with the view model - the `T` will be the `IViewModel` it is associated with. There is one property that must be implemented: `T ViewModel { get; set; }`
28 |
29 | In a class that implements `IViewFor` I would recommend implementing that property as follows:
30 | ```csharp
31 | ChildViewModel vm;
32 | public ChildViewModel ViewModel {
33 | get => vm;
34 | set
35 | {
36 | vm = value;
37 | BindingContext = vm;
38 | }
39 | }
40 | ```
41 |
42 | ### Initialization
43 | At runtime , the library will take care of finding the view -> view-model pairs when ```RegisterViewModels``` is called and it's passed the assembly of where the views and view models live. _(Currently they have to both be in the same assembly)._
44 |
45 | You would do this in either the `AppDelegate` or `MainActivity` class:
46 |
47 | ```csharp
48 | NavigationService.Instance.RegisterViewModels(typeof(App).Assembly);
49 | ```
50 |
51 | As you may have noted above - everything runs through a class called `NavigationService`. You don't instantiate it directly, because it needs to keep track of that internal view->view model dictionary, but rather accessed through a singleton called `Instance`. This way it'll stay in memory for the life of the app.
52 |
53 | It conforms to another interface called `INavigationService` whose definition looks like the following:
54 |
55 | ```csharp
56 | public interface INavigationService
57 | {
58 | void RegisterViewModels(System.Reflection.Assembly asm);
59 | void Register(Type viewModelType, Type viewType);
60 |
61 | Task PopAsync();
62 | Task PopAsync(Action reInitialize = null) where T : class, IViewModel;
63 | Task PopModalAsync();
64 | void PopTo() where T : class, IViewModel;
65 | Task PopToRootAsync(bool animate);
66 |
67 | Task PushAsync(T viewModel) where T : class, IViewModel;
68 | Task PushAsync(Action initialize = null) where T : class, IViewModel;
69 | Task PushModalAsync(T viewModel) where T : class, IViewModel;
70 | Task PushModalAsync(Action initialize = null) where T : class, IViewModel;
71 |
72 | void SwitchDetailPage(T viewModel) where T : class, IViewModel;
73 | void SwitchDetailPage(Action initialize = null) where T : class, IViewModel;
74 | }
75 | ```
76 | As I break these down one by one - when I refer to a view->view model combination being on the stack, I'm really only referring to the view (or `Page`) residing in the Xamarin.Forms `INavigation.NavigationStack` and then being able to find it's associated view model via the internal dictionary. So... instead of saying that... it's easier to refer to them as both being on the stack.
77 |
78 | #### Registration
79 | - `void RegisterViewModels(System.Reflection.Assembly asm)` - invoked in the `AppDelegate` or `MainActivity` to have the service enumerate all the view->view model pairs and register them in the internal dictionary.
80 | - `void Register(Type viewModelType, Type viewType)` - used to register a single view->view model pair in the dictionary manually.
81 |
82 | #### Popping
83 | - `Task PopAsync()` - when used inside a view model, pops the associated view (or `Page`) off the navigation stack.
84 | - `Task PopAsync(Action reInitialize = null) where T : class, IViewModel` - used to pop the current view->view model combination off the stack. If the next view model in the stack is of type `T` it will run whatever action passed in on that view model. In otherwise it will only perform a `PopAsync()`.
85 | - `Task PopModalAsync()` - removes the current view->view model combination from the stack.
86 | - `void PopTo() where T : class, IViewModel` - pops everything off the stack until it finds a view->view model combination where the view model is of the type `T`. This is kind of hacky - as you may or may not see all of the previous pages being pulled from the stack.
87 | - `Task PopToRootAsync(bool animate)` - removes everything from the navigation stack except for the root view->view model combination.
88 |
89 | #### Pushing
90 | - `Task PushAsync(T viewModel) where T : class, IViewModel` - used to push a new view->view model combination onto the navigation stack. Here the view model has already been instantiated _before_ this function is called.
91 | - `Task PushAsync(Action initialize = null) where T : class, IViewModel` - used to push a new view->view model combination onto the stack - and optionally invoke an action on the view model _before_ the combo is pushed. Here the view model is instantiated by the library.
92 | - `Task PushModalAsync(T viewModel) where T : class, IViewModel` - used to push a modal view->view model combination onto the stack when the instantiated view model already is in hand.
93 | - `Task PushModalAsync(Action initialize = null) where T : class, IViewModel` - used to push a modal view->view model combination onto the stack and optionally invoke an action on the view model _before_ the combo is pushed. The view model is instantiated by the library.
94 |
95 | #### Switching
96 | Used with `MasterDetailPages` to switch the `MasterDetailPage.Detail` page or the `App.MainPage`.
97 |
98 | - `void SwitchDetailPage(T viewModel) where T : class, IViewModel` - used to switch the page when the view model is already instantiated.
99 | - `void SwitchDetailPage(Action initialize = null) where T : class, IViewModel` - used to switch the page and optionally invoke a function on the view model _before_ the view->view model combination is make the active page.
100 |
101 | ##### A Word On Master/Detail Pages
102 | The library also provides a class to help with `MasterDetailPages` when the master page is composed of a list with options that when selected open a new list. `MasterListItem`. It contains one property, `DisplayName` that is meant for display in the `ListView`, and the `T` is the `IViewModel`.
103 |
104 | The idea here is that when the item gets selected from the `ListView`, you'll have a `MasterListItem` class. From that you can create extract the `T`, new up the view model, and then swap the `Detail` page.
105 |
--------------------------------------------------------------------------------
/Droid/VMFirstNav.Demo.Droid.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | {89D44D6A-1205-4A75-AE82-42111FDE9286}
7 | {EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
8 | Library
9 | VMFirstNav.Demo.Droid
10 | VMFirstNav.Demo.Droid
11 | v7.1
12 | True
13 | Resources\Resource.designer.cs
14 | Resource
15 | Properties\AndroidManifest.xml
16 | Resources
17 | Assets
18 | true
19 |
20 |
21 | true
22 | full
23 | false
24 | bin\Debug
25 | DEBUG;
26 | prompt
27 | 4
28 | None
29 | arm64-v8a;armeabi;armeabi-v7a;x86
30 |
31 |
32 | true
33 | pdbonly
34 | true
35 | bin\Release
36 | prompt
37 | 4
38 | true
39 | false
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | ..\packages\Xamarin.Android.Support.v4.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v4.dll
48 |
49 |
50 | ..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.Vector.Drawable.dll
51 |
52 |
53 | ..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.Animated.Vector.Drawable.dll
54 |
55 |
56 | ..\packages\Xamarin.Android.Support.v7.AppCompat.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.AppCompat.dll
57 |
58 |
59 | ..\packages\Xamarin.Android.Support.v7.RecyclerView.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.RecyclerView.dll
60 |
61 |
62 | ..\packages\Xamarin.Android.Support.Design.23.3.0\lib\MonoAndroid43\Xamarin.Android.Support.Design.dll
63 |
64 |
65 | ..\packages\Xamarin.Android.Support.v7.CardView.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.CardView.dll
66 |
67 |
68 | ..\packages\Xamarin.Android.Support.v7.MediaRouter.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.MediaRouter.dll
69 |
70 |
71 | ..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\FormsViewGroup.dll
72 |
73 |
74 | ..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Core.dll
75 |
76 |
77 | ..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Platform.Android.dll
78 |
79 |
80 | ..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Platform.dll
81 |
82 |
83 | ..\packages\Xamarin.Forms.2.3.4.247\lib\MonoAndroid10\Xamarin.Forms.Xaml.dll
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 | {522AF6C4-EB3D-46A9-A7D9-10374DB176A6}
109 | VMFirstNav.Demo
110 |
111 |
112 | {2B91892E-8113-4E9E-982C-7E186FEEB214}
113 | VMFirstNav
114 |
115 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/VMFirstNav/NavigationService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Xamarin.Forms;
6 | using System.Reflection;
7 |
8 | namespace CodeMill.VMFirstNav
9 | {
10 | public class NavigationService : INavigationService
11 | {
12 | static INavigationService instance;
13 | public static INavigationService Instance => instance ?? (instance = new NavigationService());
14 |
15 | private NavigationService()
16 | {
17 |
18 | }
19 |
20 | INavigation FormsNavigation
21 | {
22 | get
23 | {
24 | var tabController = Application.Current.MainPage as TabbedPage;
25 | var masterController = Application.Current.MainPage as MasterDetailPage;
26 |
27 | // First check to see if we're on a tabbed page, then master detail, finally go to overall fallback
28 | return tabController?.CurrentPage?.Navigation ??
29 | (masterController?.Detail as TabbedPage)?.CurrentPage?.Navigation ?? // special consideration for a tabbed page inside master/detail
30 | masterController?.Detail?.Navigation ??
31 | Application.Current.MainPage.Navigation;
32 | }
33 | }
34 |
35 | // View model to view lookup - making the assumption that view model to view will always be 1:1
36 | readonly Dictionary _viewModelViewDictionary = new Dictionary();
37 |
38 | #region Replace
39 |
40 | // Because we're going to do a hard switch of the page, either return
41 | // the detail page, or if that's null, then the current main page
42 | Page DetailPage
43 | {
44 | get
45 | {
46 | var masterController = Application.Current.MainPage as MasterDetailPage;
47 |
48 | return masterController?.Detail ?? Application.Current.MainPage;
49 | }
50 | set
51 | {
52 | var masterController = Application.Current.MainPage as MasterDetailPage;
53 |
54 | if (masterController != null)
55 | {
56 | masterController.Detail = value;
57 | masterController.IsPresented = false;
58 | }
59 | else
60 | {
61 | Application.Current.MainPage = value;
62 | }
63 | }
64 | }
65 |
66 | public void SwitchDetailPage(T viewModel) where T : class, IViewModel
67 | {
68 |
69 | var view = InstantiateViewForSwitchDetailPage(viewModel);
70 |
71 | Page newDetailPage;
72 |
73 | // Tab pages shouldn't go into navigation pages
74 | if (view is TabbedPage)
75 | newDetailPage = (Page)view;
76 | else
77 | newDetailPage = new NavigationPage((Page)view);
78 |
79 | DetailPage = newDetailPage;
80 | }
81 |
82 | public void SwitchDetailPage(Action initialize = null) where T : class, IViewModel
83 | {
84 | T viewModel;
85 |
86 | // First instantiate the view model
87 | viewModel = Activator.CreateInstance();
88 | initialize?.Invoke(viewModel);
89 |
90 | // Actually switch the page
91 | SwitchDetailPage(viewModel);
92 | }
93 |
94 | #endregion
95 |
96 | #region Registration
97 |
98 | public void RegisterViewModels(System.Reflection.Assembly asm)
99 | {
100 | // Loop through everything in the assembley that implements IViewFor
101 | foreach (var type in asm.DefinedTypes.Where(dt => !dt.IsAbstract &&
102 | dt.ImplementedInterfaces.Any(ii => ii == typeof(IViewFor))))
103 | {
104 |
105 | // Get the IViewFor portion of the type that implements it
106 | var viewForType = type.ImplementedInterfaces.FirstOrDefault(
107 | ii => ii.IsConstructedGenericType &&
108 | ii.GetGenericTypeDefinition() == typeof(IViewFor<>));
109 |
110 | // Register it, using the T as the key and the view as the value
111 | Register(viewForType.GenericTypeArguments[0], type.AsType());
112 | }
113 | }
114 |
115 | public void Register(Type viewModelType, Type viewType)
116 | {
117 | // ensure Register can be called again without register the same viewmodel again.
118 | if (_viewModelViewDictionary.ContainsKey(viewModelType))
119 | return;
120 |
121 | _viewModelViewDictionary.Add(viewModelType, viewType);
122 | }
123 |
124 | #endregion
125 |
126 | #region Pop
127 |
128 | public async Task PopAsync(Action reInitialize = null) where T : class, IViewModel
129 | {
130 | await PopAsync();
131 |
132 | var topPage = FormsNavigation.NavigationStack.Last() as IViewFor;
133 |
134 | if (topPage != null)
135 | reInitialize?.Invoke(topPage.ViewModel);
136 | }
137 |
138 | public async Task PopAsync()
139 | {
140 | await FormsNavigation.PopAsync(true);
141 | }
142 |
143 | public async Task PopModalAsync()
144 | {
145 | await FormsNavigation.PopModalAsync(true);
146 | }
147 |
148 | public async Task PopToRootAsync(bool animate)
149 | {
150 | await FormsNavigation.PopToRootAsync(animate);
151 | }
152 |
153 | public void PopTo() where T : class, IViewModel
154 | {
155 | var pagesToRemove = new List();
156 | var upper = FormsNavigation.NavigationStack.Count;
157 |
158 | // Loop through the nav stack backwards
159 | for (int i = upper - 1; i >= 0; i--)
160 | {
161 | var currentPage = FormsNavigation.NavigationStack[i] as IViewFor;
162 |
163 | // Stop the whole show if one of the pages isn't an IViewFor
164 | if (currentPage == null)
165 | return;
166 |
167 | var strongTypedPaged = currentPage as IViewFor;
168 |
169 | // If we hit the view model type, break out
170 | if (strongTypedPaged != null)
171 | break;
172 |
173 | // Finally - always add to the list
174 | pagesToRemove.Add(currentPage as Page);
175 | }
176 |
177 | foreach (var item in pagesToRemove)
178 | {
179 | FormsNavigation.RemovePage(item);
180 | }
181 | }
182 |
183 | #endregion
184 |
185 | #region Push
186 |
187 | public async Task PushAsync(T viewModel) where T : class, IViewModel
188 | {
189 | var view = InstantiateView(viewModel);
190 |
191 | await FormsNavigation.PushAsync((Page)view);
192 | }
193 |
194 | public async Task PushModalAsync(T viewModel) where T : class, IViewModel
195 | {
196 | var view = InstantiateView(viewModel);
197 |
198 | // Most likely we're going to want to put this into a navigation page so we can have a title bar on it
199 | var nv = new NavigationPage((Page)view);
200 |
201 | await FormsNavigation.PushModalAsync(nv);
202 | }
203 |
204 | public async Task PushAsync(Action initialize = null) where T : class, IViewModel
205 | {
206 | T viewModel;
207 |
208 | // Instantiate the view model & invoke the initialize method, if any
209 | viewModel = Activator.CreateInstance();
210 | initialize?.Invoke(viewModel);
211 |
212 | await PushAsync(viewModel);
213 | }
214 |
215 | public async Task PushModalAsync(Action initialize = null) where T : class, IViewModel
216 | {
217 | T viewModel;
218 |
219 | // Instantiate the view model & invoke the initialize method, if any
220 | viewModel = Activator.CreateInstance();
221 | initialize?.Invoke(viewModel);
222 |
223 | await PushModalAsync(viewModel);
224 | }
225 |
226 | #endregion
227 |
228 | IViewFor InstantiateView(T viewModel) where T : class, IViewModel
229 | {
230 | // Figure out what type the view model is
231 | var viewModelType = viewModel.GetType();
232 |
233 | // look up what type of view it corresponds to
234 | var viewType = _viewModelViewDictionary[viewModelType];
235 |
236 | // instantiate it
237 | var view = (IViewFor)Activator.CreateInstance(viewType);
238 |
239 | view.ViewModel = viewModel;
240 |
241 | return view;
242 | }
243 |
244 | IViewFor InstantiateViewForSwitchDetailPage(T viewModel) where T : class, IViewModel
245 | {
246 | var viewModelType = viewModel.GetType();
247 |
248 | var viewType = _viewModelViewDictionary[viewModelType];
249 |
250 | var view = (IViewFor)Activator.CreateInstance(viewType);
251 |
252 | var viewModelProperty = view.GetType().GetRuntimeProperty(nameof(IViewFor.ViewModel));
253 |
254 | viewModelProperty?.SetValue(view, viewModel);
255 |
256 | return view;
257 | }
258 | }
259 | }
260 |
--------------------------------------------------------------------------------
/bootstrapper.ps1:
--------------------------------------------------------------------------------
1 | ##########################################################################
2 | # This is the Cake bootstrapper script for PowerShell.
3 | # This file was downloaded from https://github.com/cake-build/resources
4 | # Feel free to change this file to fit your needs.
5 | ##########################################################################
6 |
7 | <#
8 | .SYNOPSIS
9 | This is a Powershell script to bootstrap a Cake build.
10 | .DESCRIPTION
11 | This Powershell script will download NuGet if missing, restore NuGet tools (including Cake)
12 | and execute your Cake build script with the parameters you provide.
13 | .PARAMETER Script
14 | The build script to execute.
15 | .PARAMETER Target
16 | The build script target to run.
17 | .PARAMETER Configuration
18 | The build configuration to use.
19 | .PARAMETER Verbosity
20 | Specifies the amount of information to be displayed.
21 | .PARAMETER Experimental
22 | Tells Cake to use the latest Roslyn release.
23 | .PARAMETER WhatIf
24 | Performs a dry run of the build script.
25 | No tasks will be executed.
26 | .PARAMETER Mono
27 | Tells Cake to use the Mono scripting engine.
28 | .PARAMETER SkipToolPackageRestore
29 | Skips restoring of packages.
30 | .PARAMETER ScriptArgs
31 | Remaining arguments are added here.
32 | .LINK
33 | http://cakebuild.net
34 | #>
35 |
36 | [CmdletBinding()]
37 | Param(
38 | [string]$Script = "build.cake",
39 | [string]$Target = "Default",
40 | [ValidateSet("Release", "Debug")]
41 | [string]$Configuration = "Release",
42 | [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")]
43 | [string]$Verbosity = "Verbose",
44 | [switch]$Experimental,
45 | [Alias("DryRun","Noop")]
46 | [switch]$WhatIf,
47 | [switch]$Mono,
48 | [switch]$SkipToolPackageRestore,
49 | [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
50 | [string[]]$ScriptArgs
51 | )
52 |
53 | [Reflection.Assembly]::LoadWithPartialName("System.Security") | Out-Null
54 | function MD5HashFile([string] $filePath)
55 | {
56 | if ([string]::IsNullOrEmpty($filePath) -or !(Test-Path $filePath -PathType Leaf))
57 | {
58 | return $null
59 | }
60 |
61 | [System.IO.Stream] $file = $null;
62 | [System.Security.Cryptography.MD5] $md5 = $null;
63 | try
64 | {
65 | $md5 = [System.Security.Cryptography.MD5]::Create()
66 | $file = [System.IO.File]::OpenRead($filePath)
67 | return [System.BitConverter]::ToString($md5.ComputeHash($file))
68 | }
69 | finally
70 | {
71 | if ($file -ne $null)
72 | {
73 | $file.Dispose()
74 | }
75 | }
76 | }
77 |
78 | Write-Host "Preparing to run build script..."
79 |
80 | if(!$PSScriptRoot){
81 | $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
82 | }
83 |
84 | $TOOLS_DIR = Join-Path $PSScriptRoot "tools"
85 | $ADDINS_DIR = Join-Path $TOOLS_DIR "addins"
86 | $MODULES_DIR = Join-Path $TOOLS_DIR "modules"
87 | $NUGET_EXE = Join-Path $TOOLS_DIR "nuget.exe"
88 | $CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe"
89 | $NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe"
90 | $PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config"
91 | $PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum"
92 | $ADDINS_PACKAGES_CONFIG = Join-Path $ADDINS_DIR "packages.config"
93 | $MODULES_PACKAGES_CONFIG = Join-Path $MODULES_DIR "packages.config"
94 |
95 | # Should we use mono?
96 | $UseMono = "";
97 | if($Mono.IsPresent) {
98 | Write-Verbose -Message "Using the Mono based scripting engine."
99 | $UseMono = "-mono"
100 | }
101 |
102 | # Should we use the new Roslyn?
103 | $UseExperimental = "";
104 | if($Experimental.IsPresent -and !($Mono.IsPresent)) {
105 | Write-Verbose -Message "Using experimental version of Roslyn."
106 | $UseExperimental = "-experimental"
107 | }
108 |
109 | # Is this a dry run?
110 | $UseDryRun = "";
111 | if($WhatIf.IsPresent) {
112 | $UseDryRun = "-dryrun"
113 | }
114 |
115 | # Make sure tools folder exists
116 | if ((Test-Path $PSScriptRoot) -and !(Test-Path $TOOLS_DIR)) {
117 | Write-Verbose -Message "Creating tools directory..."
118 | New-Item -Path $TOOLS_DIR -Type directory | out-null
119 | }
120 |
121 | # Make sure that packages.config exist.
122 | if (!(Test-Path $PACKAGES_CONFIG)) {
123 | Write-Verbose -Message "Downloading packages.config..."
124 | try { (New-Object System.Net.WebClient).DownloadFile("http://cakebuild.net/download/bootstrapper/packages", $PACKAGES_CONFIG) } catch {
125 | Throw "Could not download packages.config."
126 | }
127 | }
128 |
129 | # Try find NuGet.exe in path if not exists
130 | if (!(Test-Path $NUGET_EXE)) {
131 | Write-Verbose -Message "Trying to find nuget.exe in PATH..."
132 | $existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_ -PathType Container) }
133 | $NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1
134 | if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) {
135 | Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)."
136 | $NUGET_EXE = $NUGET_EXE_IN_PATH.FullName
137 | }
138 | }
139 |
140 | # Try download NuGet.exe if not exists
141 | if (!(Test-Path $NUGET_EXE)) {
142 | Write-Verbose -Message "Downloading NuGet.exe..."
143 | try {
144 | (New-Object System.Net.WebClient).DownloadFile($NUGET_URL, $NUGET_EXE)
145 | } catch {
146 | Throw "Could not download NuGet.exe."
147 | }
148 | }
149 |
150 | # Save nuget.exe path to environment to be available to child processed
151 | $ENV:NUGET_EXE = $NUGET_EXE
152 |
153 | # Restore tools from NuGet?
154 | if(-Not $SkipToolPackageRestore.IsPresent) {
155 | Push-Location
156 | Set-Location $TOOLS_DIR
157 |
158 | # Check for changes in packages.config and remove installed tools if true.
159 | [string] $md5Hash = MD5HashFile($PACKAGES_CONFIG)
160 | if((!(Test-Path $PACKAGES_CONFIG_MD5)) -Or
161 | ($md5Hash -ne (Get-Content $PACKAGES_CONFIG_MD5 ))) {
162 | Write-Verbose -Message "Missing or changed package.config hash..."
163 | Remove-Item * -Recurse -Exclude packages.config,nuget.exe
164 | }
165 |
166 | Write-Verbose -Message "Restoring tools from NuGet..."
167 | $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$TOOLS_DIR`""
168 |
169 | if ($LASTEXITCODE -ne 0) {
170 | Throw "An error occured while restoring NuGet tools."
171 | }
172 | else
173 | {
174 | $md5Hash | Out-File $PACKAGES_CONFIG_MD5 -Encoding "ASCII"
175 | }
176 | Write-Verbose -Message ($NuGetOutput | out-string)
177 |
178 | Pop-Location
179 | }
180 |
181 | # Restore addins from NuGet
182 | if (Test-Path $ADDINS_PACKAGES_CONFIG) {
183 | Push-Location
184 | Set-Location $ADDINS_DIR
185 |
186 | Write-Verbose -Message "Restoring addins from NuGet..."
187 | $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$ADDINS_DIR`""
188 |
189 | if ($LASTEXITCODE -ne 0) {
190 | Throw "An error occured while restoring NuGet addins."
191 | }
192 |
193 | Write-Verbose -Message ($NuGetOutput | out-string)
194 |
195 | Pop-Location
196 | }
197 |
198 | # Restore modules from NuGet
199 | if (Test-Path $MODULES_PACKAGES_CONFIG) {
200 | Push-Location
201 | Set-Location $MODULES_DIR
202 |
203 | Write-Verbose -Message "Restoring modules from NuGet..."
204 | $NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install -ExcludeVersion -OutputDirectory `"$MODULES_DIR`""
205 |
206 | if ($LASTEXITCODE -ne 0) {
207 | Throw "An error occured while restoring NuGet modules."
208 | }
209 |
210 | Write-Verbose -Message ($NuGetOutput | out-string)
211 |
212 | Pop-Location
213 | }
214 |
215 | # Make sure that Cake has been installed.
216 | if (!(Test-Path $CAKE_EXE)) {
217 | Throw "Could not find Cake.exe at $CAKE_EXE"
218 | }
219 |
220 | # Start Cake
221 | Write-Host "Running build script..."
222 | Invoke-Expression "& `"$CAKE_EXE`" `"$Script`" -target=`"$Target`" -configuration=`"$Configuration`" -verbosity=`"$Verbosity`" $UseMono $UseDryRun $UseExperimental $ScriptArgs"
223 | exit $LASTEXITCODE
--------------------------------------------------------------------------------
/VMFirstNav.sln:
--------------------------------------------------------------------------------
1 | Microsoft Visual Studio Solution File, Format Version 12.00
2 | # Visual Studio 15
3 | VisualStudioVersion = 15.0.26430.16
4 | MinimumVisualStudioVersion = 10.0.40219.1
5 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VMFirstNav", "VMFirstNav\VMFirstNav.csproj", "{2B91892E-8113-4E9E-982C-7E186FEEB214}"
6 | EndProject
7 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Demo", "Demo", "{06BA6D54-BC2F-42C6-A9B2-46725C2A81CC}"
8 | EndProject
9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VMFirstNav.Demo", "VMFirstNav.Demo\VMFirstNav.Demo.csproj", "{522AF6C4-EB3D-46A9-A7D9-10374DB176A6}"
10 | EndProject
11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VMFirstNav.Demo.Droid", "Droid\VMFirstNav.Demo.Droid.csproj", "{89D44D6A-1205-4A75-AE82-42111FDE9286}"
12 | EndProject
13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VMFirstNav.Demo.iOS", "iOS\VMFirstNav.Demo.iOS.csproj", "{E91062C4-A4F8-486B-9A6C-326306748405}"
14 | EndProject
15 | Global
16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
17 | AppVeyor|Any CPU = AppVeyor|Any CPU
18 | AppVeyor|iPhone = AppVeyor|iPhone
19 | AppVeyor|iPhoneSimulator = AppVeyor|iPhoneSimulator
20 | Debug|Any CPU = Debug|Any CPU
21 | Debug|iPhone = Debug|iPhone
22 | Debug|iPhoneSimulator = Debug|iPhoneSimulator
23 | Release|Any CPU = Release|Any CPU
24 | Release|iPhone = Release|iPhone
25 | Release|iPhoneSimulator = Release|iPhoneSimulator
26 | EndGlobalSection
27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
28 | {2B91892E-8113-4E9E-982C-7E186FEEB214}.AppVeyor|Any CPU.ActiveCfg = Release|Any CPU
29 | {2B91892E-8113-4E9E-982C-7E186FEEB214}.AppVeyor|Any CPU.Build.0 = Release|Any CPU
30 | {2B91892E-8113-4E9E-982C-7E186FEEB214}.AppVeyor|iPhone.ActiveCfg = Debug|Any CPU
31 | {2B91892E-8113-4E9E-982C-7E186FEEB214}.AppVeyor|iPhone.Build.0 = Debug|Any CPU
32 | {2B91892E-8113-4E9E-982C-7E186FEEB214}.AppVeyor|iPhoneSimulator.ActiveCfg = Debug|Any CPU
33 | {2B91892E-8113-4E9E-982C-7E186FEEB214}.AppVeyor|iPhoneSimulator.Build.0 = Debug|Any CPU
34 | {2B91892E-8113-4E9E-982C-7E186FEEB214}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {2B91892E-8113-4E9E-982C-7E186FEEB214}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {2B91892E-8113-4E9E-982C-7E186FEEB214}.Debug|iPhone.ActiveCfg = Debug|Any CPU
37 | {2B91892E-8113-4E9E-982C-7E186FEEB214}.Debug|iPhone.Build.0 = Debug|Any CPU
38 | {2B91892E-8113-4E9E-982C-7E186FEEB214}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
39 | {2B91892E-8113-4E9E-982C-7E186FEEB214}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
40 | {2B91892E-8113-4E9E-982C-7E186FEEB214}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {2B91892E-8113-4E9E-982C-7E186FEEB214}.Release|Any CPU.Build.0 = Release|Any CPU
42 | {2B91892E-8113-4E9E-982C-7E186FEEB214}.Release|iPhone.ActiveCfg = Release|Any CPU
43 | {2B91892E-8113-4E9E-982C-7E186FEEB214}.Release|iPhone.Build.0 = Release|Any CPU
44 | {2B91892E-8113-4E9E-982C-7E186FEEB214}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
45 | {2B91892E-8113-4E9E-982C-7E186FEEB214}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
46 | {522AF6C4-EB3D-46A9-A7D9-10374DB176A6}.AppVeyor|Any CPU.ActiveCfg = Debug|Any CPU
47 | {522AF6C4-EB3D-46A9-A7D9-10374DB176A6}.AppVeyor|iPhone.ActiveCfg = Release|Any CPU
48 | {522AF6C4-EB3D-46A9-A7D9-10374DB176A6}.AppVeyor|iPhone.Build.0 = Release|Any CPU
49 | {522AF6C4-EB3D-46A9-A7D9-10374DB176A6}.AppVeyor|iPhoneSimulator.ActiveCfg = Release|Any CPU
50 | {522AF6C4-EB3D-46A9-A7D9-10374DB176A6}.AppVeyor|iPhoneSimulator.Build.0 = Release|Any CPU
51 | {522AF6C4-EB3D-46A9-A7D9-10374DB176A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
52 | {522AF6C4-EB3D-46A9-A7D9-10374DB176A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
53 | {522AF6C4-EB3D-46A9-A7D9-10374DB176A6}.Debug|iPhone.ActiveCfg = Debug|Any CPU
54 | {522AF6C4-EB3D-46A9-A7D9-10374DB176A6}.Debug|iPhone.Build.0 = Debug|Any CPU
55 | {522AF6C4-EB3D-46A9-A7D9-10374DB176A6}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
56 | {522AF6C4-EB3D-46A9-A7D9-10374DB176A6}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
57 | {522AF6C4-EB3D-46A9-A7D9-10374DB176A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
58 | {522AF6C4-EB3D-46A9-A7D9-10374DB176A6}.Release|Any CPU.Build.0 = Release|Any CPU
59 | {522AF6C4-EB3D-46A9-A7D9-10374DB176A6}.Release|iPhone.ActiveCfg = Release|Any CPU
60 | {522AF6C4-EB3D-46A9-A7D9-10374DB176A6}.Release|iPhone.Build.0 = Release|Any CPU
61 | {522AF6C4-EB3D-46A9-A7D9-10374DB176A6}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
62 | {522AF6C4-EB3D-46A9-A7D9-10374DB176A6}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
63 | {89D44D6A-1205-4A75-AE82-42111FDE9286}.AppVeyor|Any CPU.ActiveCfg = Debug|Any CPU
64 | {89D44D6A-1205-4A75-AE82-42111FDE9286}.AppVeyor|iPhone.ActiveCfg = Release|Any CPU
65 | {89D44D6A-1205-4A75-AE82-42111FDE9286}.AppVeyor|iPhone.Build.0 = Release|Any CPU
66 | {89D44D6A-1205-4A75-AE82-42111FDE9286}.AppVeyor|iPhone.Deploy.0 = Release|Any CPU
67 | {89D44D6A-1205-4A75-AE82-42111FDE9286}.AppVeyor|iPhoneSimulator.ActiveCfg = Release|Any CPU
68 | {89D44D6A-1205-4A75-AE82-42111FDE9286}.AppVeyor|iPhoneSimulator.Build.0 = Release|Any CPU
69 | {89D44D6A-1205-4A75-AE82-42111FDE9286}.AppVeyor|iPhoneSimulator.Deploy.0 = Release|Any CPU
70 | {89D44D6A-1205-4A75-AE82-42111FDE9286}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
71 | {89D44D6A-1205-4A75-AE82-42111FDE9286}.Debug|Any CPU.Build.0 = Debug|Any CPU
72 | {89D44D6A-1205-4A75-AE82-42111FDE9286}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
73 | {89D44D6A-1205-4A75-AE82-42111FDE9286}.Debug|iPhone.ActiveCfg = Debug|Any CPU
74 | {89D44D6A-1205-4A75-AE82-42111FDE9286}.Debug|iPhone.Build.0 = Debug|Any CPU
75 | {89D44D6A-1205-4A75-AE82-42111FDE9286}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
76 | {89D44D6A-1205-4A75-AE82-42111FDE9286}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
77 | {89D44D6A-1205-4A75-AE82-42111FDE9286}.Release|Any CPU.ActiveCfg = Release|Any CPU
78 | {89D44D6A-1205-4A75-AE82-42111FDE9286}.Release|Any CPU.Build.0 = Release|Any CPU
79 | {89D44D6A-1205-4A75-AE82-42111FDE9286}.Release|iPhone.ActiveCfg = Release|Any CPU
80 | {89D44D6A-1205-4A75-AE82-42111FDE9286}.Release|iPhone.Build.0 = Release|Any CPU
81 | {89D44D6A-1205-4A75-AE82-42111FDE9286}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
82 | {89D44D6A-1205-4A75-AE82-42111FDE9286}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
83 | {E91062C4-A4F8-486B-9A6C-326306748405}.AppVeyor|Any CPU.ActiveCfg = Debug|iPhoneSimulator
84 | {E91062C4-A4F8-486B-9A6C-326306748405}.AppVeyor|iPhone.ActiveCfg = Release|iPhone
85 | {E91062C4-A4F8-486B-9A6C-326306748405}.AppVeyor|iPhone.Build.0 = Release|iPhone
86 | {E91062C4-A4F8-486B-9A6C-326306748405}.AppVeyor|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
87 | {E91062C4-A4F8-486B-9A6C-326306748405}.AppVeyor|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
88 | {E91062C4-A4F8-486B-9A6C-326306748405}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator
89 | {E91062C4-A4F8-486B-9A6C-326306748405}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator
90 | {E91062C4-A4F8-486B-9A6C-326306748405}.Debug|iPhone.ActiveCfg = Debug|iPhone
91 | {E91062C4-A4F8-486B-9A6C-326306748405}.Debug|iPhone.Build.0 = Debug|iPhone
92 | {E91062C4-A4F8-486B-9A6C-326306748405}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator
93 | {E91062C4-A4F8-486B-9A6C-326306748405}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator
94 | {E91062C4-A4F8-486B-9A6C-326306748405}.Release|Any CPU.ActiveCfg = Release|iPhone
95 | {E91062C4-A4F8-486B-9A6C-326306748405}.Release|Any CPU.Build.0 = Release|iPhone
96 | {E91062C4-A4F8-486B-9A6C-326306748405}.Release|iPhone.ActiveCfg = Release|iPhone
97 | {E91062C4-A4F8-486B-9A6C-326306748405}.Release|iPhone.Build.0 = Release|iPhone
98 | {E91062C4-A4F8-486B-9A6C-326306748405}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator
99 | {E91062C4-A4F8-486B-9A6C-326306748405}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator
100 | EndGlobalSection
101 | GlobalSection(SolutionProperties) = preSolution
102 | HideSolutionNode = FALSE
103 | EndGlobalSection
104 | GlobalSection(NestedProjects) = preSolution
105 | {522AF6C4-EB3D-46A9-A7D9-10374DB176A6} = {06BA6D54-BC2F-42C6-A9B2-46725C2A81CC}
106 | {89D44D6A-1205-4A75-AE82-42111FDE9286} = {06BA6D54-BC2F-42C6-A9B2-46725C2A81CC}
107 | {E91062C4-A4F8-486B-9A6C-326306748405} = {06BA6D54-BC2F-42C6-A9B2-46725C2A81CC}
108 | EndGlobalSection
109 | EndGlobal
110 |
--------------------------------------------------------------------------------
/VMFirstNav.Demo/VMFirstNav.Demo.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | {522AF6C4-EB3D-46A9-A7D9-10374DB176A6}
7 | {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
8 | true
9 | Library
10 | VMFirstNav.Demo
11 | VMFirstNav.Demo
12 | v4.5
13 | Profile111
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug
20 | DEBUG;
21 | prompt
22 | 4
23 |
24 |
25 | true
26 | bin\Release
27 | prompt
28 | 4
29 |
30 |
31 |
32 |
33 |
34 | MSBuild:UpdateDesignTimeXaml
35 |
36 |
37 | MSBuild:UpdateDesignTimeXaml
38 |
39 |
40 | MSBuild:UpdateDesignTimeXaml
41 |
42 |
43 | MSBuild:UpdateDesignTimeXaml
44 |
45 |
46 | MSBuild:UpdateDesignTimeXaml
47 |
48 |
49 | MSBuild:UpdateDesignTimeXaml
50 |
51 |
52 | MSBuild:UpdateDesignTimeXaml
53 |
54 |
55 | MSBuild:UpdateDesignTimeXaml
56 |
57 |
58 | MSBuild:UpdateDesignTimeXaml
59 |
60 |
61 | MSBuild:UpdateDesignTimeXaml
62 |
63 |
64 | MSBuild:UpdateDesignTimeXaml
65 |
66 |
67 | MSBuild:UpdateDesignTimeXaml
68 |
69 |
70 |
71 |
72 | App.xaml
73 |
74 |
75 | VMFirstNav.DemoPage.xaml
76 |
77 |
78 |
79 |
80 |
81 | MasterDetailRootPage.xaml
82 |
83 |
84 | RootTabPage.xaml
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 | NormalOnePage.xaml
99 |
100 |
101 | NormalOneChildPage.xaml
102 |
103 |
104 | NormalModalPage.xaml
105 |
106 |
107 | NormalChildTwoPage.xaml
108 |
109 |
110 | NormalChildThreePage.xaml
111 |
112 |
113 | MasterListNavPage.xaml
114 |
115 |
116 | TabOneView.xaml
117 |
118 |
119 | TabTwoView.xaml
120 |
121 |
122 | TabOneChildView.xaml
123 |
124 |
125 | TabTwoChildView.xaml
126 |
127 |
128 |
129 |
130 | ..\packages\Xamarin.Forms.2.3.4.247\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Core.dll
131 |
132 |
133 | ..\packages\Xamarin.Forms.2.3.4.247\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Platform.dll
134 |
135 |
136 | ..\packages\Xamarin.Forms.2.3.4.247\lib\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+Xamarin.iOS10+xamarinmac20\Xamarin.Forms.Xaml.dll
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 | {2B91892E-8113-4E9E-982C-7E186FEEB214}
157 | VMFirstNav
158 |
159 |
160 |
161 |
162 |
--------------------------------------------------------------------------------