├── MauiShellApp ├── Resources │ ├── icon_about.png │ ├── icon_feed.png │ ├── xamarin_logo.png │ ├── Fonts │ │ └── OpenSans-Regular.ttf │ ├── appicon.svg │ ├── appiconfg.svg │ └── Images │ │ └── dotnet_bot.svg ├── Properties │ └── launchSettings.json ├── Models │ └── Item.cs ├── Views │ ├── AboutPage.xaml.cs │ ├── ItemDetailPage.xaml.cs │ ├── LoginPage.xaml.cs │ ├── NewItemPage.xaml.cs │ ├── ItemsPage.xaml.cs │ ├── ItemDetailPage.xaml │ ├── LoginPage.xaml │ ├── NewItemPage.xaml │ ├── ItemsPage.xaml │ └── AboutPage.xaml ├── Platforms │ ├── Android │ │ ├── Resources │ │ │ └── values │ │ │ │ └── colors.xml │ │ ├── MainApplication.cs │ │ ├── AndroidManifest.xml │ │ └── MainActivity.cs │ ├── iOS │ │ ├── AppDelegate.cs │ │ ├── Program.cs │ │ └── Info.plist │ ├── MacCatalyst │ │ ├── AppDelegate.cs │ │ ├── Program.cs │ │ └── Info.plist │ └── Windows │ │ ├── App.xaml │ │ ├── app.manifest │ │ ├── App.xaml.cs │ │ └── Package.appxmanifest ├── App.xaml.cs ├── Services │ ├── IDataStore.cs │ └── MockDataStore.cs ├── MauiProgram.cs ├── ViewModels │ ├── AboutViewModel.cs │ ├── LoginViewModel.cs │ ├── ItemDetailViewModel.cs │ ├── BaseViewModel.cs │ ├── NewItemViewModel.cs │ └── ItemsViewModel.cs ├── MainPage.xaml.cs ├── AppShell.xaml.cs ├── App.xaml ├── MainPage.xaml ├── MauiShellApp.csproj └── AppShell.xaml ├── MauiShellApp.sln └── .gitignore /MauiShellApp/Resources/icon_about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfversluis/MauiShellAppTemplate/HEAD/MauiShellApp/Resources/icon_about.png -------------------------------------------------------------------------------- /MauiShellApp/Resources/icon_feed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfversluis/MauiShellAppTemplate/HEAD/MauiShellApp/Resources/icon_feed.png -------------------------------------------------------------------------------- /MauiShellApp/Resources/xamarin_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfversluis/MauiShellAppTemplate/HEAD/MauiShellApp/Resources/xamarin_logo.png -------------------------------------------------------------------------------- /MauiShellApp/Resources/Fonts/OpenSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jfversluis/MauiShellAppTemplate/HEAD/MauiShellApp/Resources/Fonts/OpenSans-Regular.ttf -------------------------------------------------------------------------------- /MauiShellApp/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Windows Machine": { 4 | "commandName": "MsixPackage", 5 | "nativeDebugging": false 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /MauiShellApp/Models/Item.cs: -------------------------------------------------------------------------------- 1 | namespace MauiShellApp.Models; 2 | 3 | public class Item 4 | { 5 | public string Id { get; set; } 6 | public string Text { get; set; } 7 | public string Description { get; set; } 8 | } -------------------------------------------------------------------------------- /MauiShellApp/Views/AboutPage.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace MauiShellApp.Views; 2 | 3 | public partial class AboutPage : ContentPage 4 | { 5 | public AboutPage() 6 | { 7 | InitializeComponent(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /MauiShellApp/Resources/appicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /MauiShellApp/Platforms/Android/Resources/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #512BD4 4 | #2B0B98 5 | #2B0B98 6 | -------------------------------------------------------------------------------- /MauiShellApp/Platforms/iOS/AppDelegate.cs: -------------------------------------------------------------------------------- 1 | using Foundation; 2 | 3 | namespace MauiShellApp; 4 | 5 | [Register("AppDelegate")] 6 | public class AppDelegate : MauiUIApplicationDelegate 7 | { 8 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); 9 | } 10 | -------------------------------------------------------------------------------- /MauiShellApp/Platforms/MacCatalyst/AppDelegate.cs: -------------------------------------------------------------------------------- 1 | using Foundation; 2 | 3 | namespace MauiShellApp; 4 | 5 | [Register("AppDelegate")] 6 | public class AppDelegate : MauiUIApplicationDelegate 7 | { 8 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); 9 | } 10 | -------------------------------------------------------------------------------- /MauiShellApp/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using MauiShellApp.Services; 2 | 3 | namespace MauiShellApp; 4 | 5 | public partial class App : Application 6 | { 7 | public App() 8 | { 9 | InitializeComponent(); 10 | 11 | DependencyService.Register(); 12 | MainPage = new AppShell(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /MauiShellApp/Views/ItemDetailPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using MauiShellApp.ViewModels; 2 | 3 | namespace MauiShellApp.Views; 4 | 5 | public partial class ItemDetailPage : ContentPage 6 | { 7 | public ItemDetailPage() 8 | { 9 | InitializeComponent(); 10 | BindingContext = new ItemDetailViewModel(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /MauiShellApp/Services/IDataStore.cs: -------------------------------------------------------------------------------- 1 | namespace MauiShellApp.Services; 2 | public interface IDataStore 3 | { 4 | Task AddItemAsync(T item); 5 | Task UpdateItemAsync(T item); 6 | Task DeleteItemAsync(string id); 7 | Task GetItemAsync(string id); 8 | Task> GetItemsAsync(bool forceRefresh = false); 9 | } 10 | -------------------------------------------------------------------------------- /MauiShellApp/Platforms/Windows/App.xaml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /MauiShellApp/Views/LoginPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using MauiShellApp.ViewModels; 2 | 3 | namespace MauiShellApp.Views; 4 | 5 | [XamlCompilation(XamlCompilationOptions.Compile)] 6 | public partial class LoginPage : ContentPage 7 | { 8 | public LoginPage() 9 | { 10 | InitializeComponent(); 11 | this.BindingContext = new LoginViewModel(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MauiShellApp/Views/NewItemPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using MauiShellApp.Models; 2 | using MauiShellApp.ViewModels; 3 | 4 | namespace MauiShellApp.Views; 5 | 6 | public partial class NewItemPage : ContentPage 7 | { 8 | public Item Item { get; set; } 9 | 10 | public NewItemPage() 11 | { 12 | InitializeComponent(); 13 | BindingContext = new NewItemViewModel(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /MauiShellApp/MauiProgram.cs: -------------------------------------------------------------------------------- 1 | namespace MauiShellApp; 2 | 3 | public static class MauiProgram 4 | { 5 | public static MauiApp CreateMauiApp() 6 | { 7 | var builder = MauiApp.CreateBuilder(); 8 | builder 9 | .UseMauiApp() 10 | .ConfigureFonts(fonts => 11 | { 12 | fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); 13 | }); 14 | 15 | return builder.Build(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /MauiShellApp/Platforms/Android/MainApplication.cs: -------------------------------------------------------------------------------- 1 | using Android.App; 2 | using Android.Runtime; 3 | 4 | namespace MauiShellApp; 5 | 6 | [Application] 7 | public class MainApplication : MauiApplication 8 | { 9 | public MainApplication(IntPtr handle, JniHandleOwnership ownership) 10 | : base(handle, ownership) 11 | { 12 | } 13 | 14 | protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); 15 | } 16 | -------------------------------------------------------------------------------- /MauiShellApp/ViewModels/AboutViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Input; 2 | 3 | namespace MauiShellApp.ViewModels; 4 | 5 | public class AboutViewModel : BaseViewModel 6 | { 7 | public AboutViewModel() 8 | { 9 | Title = "About"; 10 | OpenWebCommand = new Command(async () => await Browser.OpenAsync("https://aka.ms/xamarin-quickstart")); 11 | } 12 | 13 | public ICommand OpenWebCommand { get; } 14 | } 15 | -------------------------------------------------------------------------------- /MauiShellApp/MainPage.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace MauiShellApp; 2 | 3 | public partial class MainPage : ContentPage 4 | { 5 | int count = 0; 6 | 7 | public MainPage() 8 | { 9 | InitializeComponent(); 10 | } 11 | 12 | private void OnCounterClicked(object sender, EventArgs e) 13 | { 14 | count++; 15 | CounterLabel.Text = $"Current count: {count}"; 16 | 17 | SemanticScreenReader.Announce(CounterLabel.Text); 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /MauiShellApp/Platforms/iOS/Program.cs: -------------------------------------------------------------------------------- 1 | using ObjCRuntime; 2 | using UIKit; 3 | 4 | namespace MauiShellApp; 5 | 6 | public class Program 7 | { 8 | // This is the main entry point of the application. 9 | static void Main(string[] args) 10 | { 11 | // if you want to use a different Application Delegate class from "AppDelegate" 12 | // you can specify it here. 13 | UIApplication.Main(args, null, typeof(AppDelegate)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /MauiShellApp/Platforms/MacCatalyst/Program.cs: -------------------------------------------------------------------------------- 1 | using ObjCRuntime; 2 | using UIKit; 3 | 4 | namespace MauiShellApp; 5 | 6 | public class Program 7 | { 8 | // This is the main entry point of the application. 9 | static void Main(string[] args) 10 | { 11 | // if you want to use a different Application Delegate class from "AppDelegate" 12 | // you can specify it here. 13 | UIApplication.Main(args, null, typeof(AppDelegate)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /MauiShellApp/Platforms/Android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /MauiShellApp/Views/ItemsPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using MauiShellApp.ViewModels; 2 | 3 | namespace MauiShellApp.Views; 4 | 5 | public partial class ItemsPage : ContentPage 6 | { 7 | ItemsViewModel _viewModel; 8 | 9 | public ItemsPage() 10 | { 11 | InitializeComponent(); 12 | 13 | BindingContext = _viewModel = new ItemsViewModel(); 14 | } 15 | 16 | protected override void OnAppearing() 17 | { 18 | base.OnAppearing(); 19 | _viewModel.OnAppearing(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /MauiShellApp/AppShell.xaml.cs: -------------------------------------------------------------------------------- 1 | using MauiShellApp.Views; 2 | 3 | namespace MauiShellApp; 4 | 5 | public partial class AppShell : Shell 6 | { 7 | public AppShell() 8 | { 9 | InitializeComponent(); 10 | Routing.RegisterRoute(nameof(ItemDetailPage), typeof(ItemDetailPage)); 11 | Routing.RegisterRoute(nameof(NewItemPage), typeof(NewItemPage)); 12 | } 13 | 14 | private async void OnMenuItemClicked(object sender, EventArgs e) 15 | { 16 | await Shell.Current.GoToAsync("//LoginPage"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /MauiShellApp/ViewModels/LoginViewModel.cs: -------------------------------------------------------------------------------- 1 | using MauiShellApp.Views; 2 | 3 | namespace MauiShellApp.ViewModels; 4 | 5 | public class LoginViewModel : BaseViewModel 6 | { 7 | public Command LoginCommand { get; } 8 | 9 | public LoginViewModel() 10 | { 11 | LoginCommand = new Command(OnLoginClicked); 12 | } 13 | 14 | private async void OnLoginClicked(object obj) 15 | { 16 | // Prefixing with `//` switches to a different navigation stack instead of pushing to the active one 17 | await Shell.Current.GoToAsync($"//{nameof(AboutPage)}"); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /MauiShellApp/Views/ItemDetailPage.xaml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 13 | 14 | -------------------------------------------------------------------------------- /MauiShellApp/Views/LoginPage.xaml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /MauiShellApp/ViewModels/ItemDetailViewModel.cs: -------------------------------------------------------------------------------- 1 | using MauiShellApp.Models; 2 | using System.Diagnostics; 3 | 4 | namespace MauiShellApp.ViewModels; 5 | 6 | [QueryProperty(nameof(ItemId), nameof(ItemId))] 7 | public class ItemDetailViewModel : BaseViewModel 8 | { 9 | private string itemId; 10 | private string text; 11 | private string description; 12 | public string Id { get; set; } 13 | 14 | public string Text 15 | { 16 | get => text; 17 | set => SetProperty(ref text, value); 18 | } 19 | 20 | public string Description 21 | { 22 | get => description; 23 | set => SetProperty(ref description, value); 24 | } 25 | 26 | public string ItemId 27 | { 28 | get 29 | { 30 | return itemId; 31 | } 32 | set 33 | { 34 | itemId = value; 35 | LoadItemId(value); 36 | } 37 | } 38 | 39 | public async void LoadItemId(string itemId) 40 | { 41 | try 42 | { 43 | var item = await DataStore.GetItemAsync(itemId); 44 | Id = item.Id; 45 | Text = item.Text; 46 | Description = item.Description; 47 | } 48 | catch (Exception) 49 | { 50 | Debug.WriteLine("Failed to Load Item"); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /MauiShellApp.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31611.283 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MauiShellApp", "MauiShellApp\MauiShellApp.csproj", "{4AD51E54-62D3-4A0E-99F4-830132AD9087}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {4AD51E54-62D3-4A0E-99F4-830132AD9087}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {4AD51E54-62D3-4A0E-99F4-830132AD9087}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {4AD51E54-62D3-4A0E-99F4-830132AD9087}.Debug|Any CPU.Deploy.0 = Debug|Any CPU 17 | {4AD51E54-62D3-4A0E-99F4-830132AD9087}.Release|Any CPU.ActiveCfg = Release|Any CPU 18 | {4AD51E54-62D3-4A0E-99F4-830132AD9087}.Release|Any CPU.Build.0 = Release|Any CPU 19 | {4AD51E54-62D3-4A0E-99F4-830132AD9087}.Release|Any CPU.Deploy.0 = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | GlobalSection(ExtensibilityGlobals) = postSolution 25 | SolutionGuid = {61F7FB11-1E47-470C-91E2-47F8143E1572} 26 | EndGlobalSection 27 | EndGlobal 28 | -------------------------------------------------------------------------------- /MauiShellApp/ViewModels/BaseViewModel.cs: -------------------------------------------------------------------------------- 1 | using MauiShellApp.Models; 2 | using MauiShellApp.Services; 3 | using System.ComponentModel; 4 | using System.Runtime.CompilerServices; 5 | 6 | namespace MauiShellApp.ViewModels; 7 | 8 | public class BaseViewModel : INotifyPropertyChanged 9 | { 10 | public IDataStore DataStore => DependencyService.Get>(); 11 | 12 | bool isBusy = false; 13 | public bool IsBusy 14 | { 15 | get { return isBusy; } 16 | set { SetProperty(ref isBusy, value); } 17 | } 18 | 19 | string title = string.Empty; 20 | public string Title 21 | { 22 | get { return title; } 23 | set { SetProperty(ref title, value); } 24 | } 25 | 26 | protected bool SetProperty(ref T backingStore, T value, 27 | [CallerMemberName] string propertyName = "", 28 | Action onChanged = null) 29 | { 30 | if (EqualityComparer.Default.Equals(backingStore, value)) 31 | return false; 32 | 33 | backingStore = value; 34 | onChanged?.Invoke(); 35 | OnPropertyChanged(propertyName); 36 | return true; 37 | } 38 | 39 | #region INotifyPropertyChanged 40 | public event PropertyChangedEventHandler PropertyChanged; 41 | protected void OnPropertyChanged([CallerMemberName] string propertyName = "") 42 | { 43 | var changed = PropertyChanged; 44 | if (changed == null) 45 | return; 46 | 47 | changed.Invoke(this, new PropertyChangedEventArgs(propertyName)); 48 | } 49 | #endregion 50 | } -------------------------------------------------------------------------------- /MauiShellApp/ViewModels/NewItemViewModel.cs: -------------------------------------------------------------------------------- 1 | using MauiShellApp.Models; 2 | 3 | namespace MauiShellApp.ViewModels; 4 | 5 | public class NewItemViewModel : BaseViewModel 6 | { 7 | private string text; 8 | private string description; 9 | 10 | public NewItemViewModel() 11 | { 12 | SaveCommand = new Command(OnSave, ValidateSave); 13 | CancelCommand = new Command(OnCancel); 14 | this.PropertyChanged += 15 | (_, __) => SaveCommand.ChangeCanExecute(); 16 | } 17 | 18 | private bool ValidateSave() 19 | { 20 | return !String.IsNullOrWhiteSpace(text) 21 | && !String.IsNullOrWhiteSpace(description); 22 | } 23 | 24 | public string Text 25 | { 26 | get => text; 27 | set => SetProperty(ref text, value); 28 | } 29 | 30 | public string Description 31 | { 32 | get => description; 33 | set => SetProperty(ref description, value); 34 | } 35 | 36 | public Command SaveCommand { get; } 37 | public Command CancelCommand { get; } 38 | 39 | private async void OnCancel() 40 | { 41 | // This will pop the current page off the navigation stack 42 | await Shell.Current.GoToAsync(".."); 43 | } 44 | 45 | private async void OnSave() 46 | { 47 | Item newItem = new Item() 48 | { 49 | Id = Guid.NewGuid().ToString(), 50 | Text = Text, 51 | Description = Description 52 | }; 53 | 54 | await DataStore.AddItemAsync(newItem); 55 | 56 | // This will pop the current page off the navigation stack 57 | await Shell.Current.GoToAsync(".."); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /MauiShellApp/App.xaml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | #2196F3 10 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /MauiShellApp/Resources/appiconfg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MauiShellApp/MainPage.xaml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 9 | 10 |