■ ServiceCollectionExtensions 클래스의 AddTransientWithShellRoute 확장 메소드를 사용해 MVVM 패턴에서 의존성 주입을 설정하는 방법을 보여준다.
▶ VIEWMODEL/BaseViewModel.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 |
using CommunityToolkit.Mvvm.ComponentModel; namespace TestProject; /// <summary> /// 베이스 뷰 모델 /// </summary> [INotifyPropertyChanged] public abstract partial class BaseViewModel { } |
▶ VIEWMODEL/MainPageViewModel.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; namespace TestProject { /// <summary> /// 메인 페이지 뷰 모델 /// </summary> public partial class MainPageViewModel : BaseViewModel { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 입력 텍스트 /// </summary> [ObservableProperty] private string inputText = null; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainPageViewModel() /// <summary> /// 생성자 /// </summary> public MainPageViewModel() { } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private #region 초기화하기 - Reset() /// <summary> /// 초기화하기 /// </summary> [RelayCommand] private void Reset() { InputText = string.Empty; } #endregion #region 상세 페이지로 이동하기 - MoveDetailPage() /// <summary> /// 상세 페이지로 이동하기 /// </summary> [RelayCommand] private async Task MoveDetailPage() { await Shell.Current.GoToAsync("//메인페이지/메인상세페이지"); } #endregion } } |
▶ VIEWMODEL/MainDetailPageViewMode.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
using CommunityToolkit.Mvvm.Input; namespace TestProject { /// <summary> /// 메인 상세 페이지 뷰 모델 /// </summary> public partial class MainDetailPageViewModel : BaseViewModel { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainDetailPageViewModel() /// <summary> /// 생성자 /// </summary> public MainDetailPageViewModel() { } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private #region 부모 페이지로 이동하기 - MoveParentPage() /// <summary> /// 부모 페이지로 이동하기 /// </summary> [RelayCommand] private async Task MoveParentPage() { await Shell.Current.GoToAsync(".."); } #endregion } } |
▶ VIEWMODEL/SecondPageViewModel.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; namespace TestProject { /// <summary> /// 두번째 페이지 뷰 모델 /// </summary> public partial class SecondPageViewModel : BaseViewModel { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 입력 텍스트 /// </summary> [ObservableProperty] private string inputText = null; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - SecondPageViewModel() /// <summary> /// 생성자 /// </summary> public SecondPageViewModel() { } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private #region 초기화하기 - Reset() /// <summary> /// 초기화하기 /// </summary> [RelayCommand] private void Reset() { InputText = string.Empty; } #endregion } } |
▶ VIEW/BasePage.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
namespace TestProject; /// <summary> /// 베이스 페이지 /// </summary> public abstract class BasePage : ContentPage { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Protected #region 생성자 - BasePage(viewModel) /// <summary> /// 생성자 /// </summary> /// <param name="viewModel">뷰 모델</param> protected BasePage(object viewModel = null) { BindingContext = viewModel; if(string.IsNullOrWhiteSpace(Title)) { Title = GetType().Name; } } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Protected #region 페이지가 나타나는 경우 처리하기 - OnAppearing() /// <summary> /// 페이지가 나타나는 경우 처리하기 /// </summary> protected override void OnAppearing() { base.OnAppearing(); // 추후 기능을 추가한다. } #endregion #region 페이지가 사라지는 경우 처리하기 - OnDisappearing() /// <summary> /// 페이지가 사라지는 경우 처리하기 /// </summary> protected override void OnDisappearing() { base.OnDisappearing(); // 추후 기능을 추가한다. } #endregion } /// <summary> /// 베이스 페이지 /// </summary> /// <typeparam name="TViewModel">뷰 모델 타입</typeparam> public abstract class BasePage<TViewModel> : BasePage where TViewModel : BaseViewModel { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 바인딩 컨텍스트 - BindingContext /// <summary> /// 바인딩 컨텍스트 /// </summary> public new TViewModel BindingContext => (TViewModel)base.BindingContext; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Protected #region 생성자 - BasePage(viewModel) /// <summary> /// 생성자 /// </summary> /// <param name="viewModel">뷰 모델</param> protected BasePage(TViewModel viewModel) : base(viewModel) { } #endregion } |
▶ VIEW/MainPage.xaml
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 |
<?xml version="1.0" encoding="utf-8" ?> <local:BasePage x:Class="TestProject.MainPage" xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:TestProject" x:TypeArguments="local:MainPageViewModel" Title="메인 페이지"> <VerticalStackLayout HorizontalOptions="Center" VerticalOptions="Center" Spacing="10"> <Entry HorizontalOptions="Center" Placeholder="텍스트를 입력해 주시기 바랍니다." FontSize="16" Text="{Binding InputText}" /> <Button HorizontalOptions="Center" Text="초기화" Command="{Binding ResetCommand}" /> <Button HorizontalOptions="Center" Text="상세 페이지 이동하기" Command="{Binding MoveDetailPageCommand}" /> </VerticalStackLayout> </local:BasePage> |
▶ VIEW/MainPage.xaml.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
namespace TestProject; /// <summary> /// 메인 페이지 /// </summary> public partial class MainPage : BasePage<MainPageViewModel> { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainPage() /// <summary> /// 생성자 /// </summary> public MainPage(MainPageViewModel viewModel) : base(viewModel) { InitializeComponent(); } #endregion } |
▶ VIEW/MainDetailPage.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<?xml version="1.0" encoding="utf-8" ?> <local:BasePage x:Class="TestProject.MainDetailPage" xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:TestProject" x:TypeArguments="local:MainDetailPageViewModel" Title="메인 상세 페이지"> <VerticalStackLayout HorizontalOptions="Center" VerticalOptions="Center" Spacing="10"> <Label HorizontalOptions="Center" FontSize="24" Text="메인 상세 페이지" /> <Button HorizontalOptions="Center" Text="부모 페이지로 이동하기" Command="{Binding MoveParentPageCommand}" /> </VerticalStackLayout> </local:BasePage> |
▶ VIEW/MainDetailPage.xaml.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
namespace TestProject; /// <summary> /// 메인 상세 페이지 /// </summary> public partial class MainDetailPage : BasePage<MainDetailPageViewModel> { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainPage() /// <summary> /// 생성자 /// </summary> public MainDetailPage(MainDetailPageViewModel viewModel) : base(viewModel) { InitializeComponent(); } #endregion } |
▶ VIEW/SecondPage.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<?xml version="1.0" encoding="utf-8" ?> <local:BasePage x:Class="TestProject.SecondPage" xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:TestProject" x:TypeArguments="local:SecondPageViewModel" Title="두번째 페이지"> <VerticalStackLayout HorizontalOptions="Center" VerticalOptions="Center" Spacing="10"> <Entry HorizontalOptions="Center" Placeholder="텍스트를 입력해 주시기 바랍니다." FontSize="16" Text="{Binding InputText}" /> <Button HorizontalOptions="Center" Text="초기화" Command="{Binding ResetCommand}" /> </VerticalStackLayout> </local:BasePage> |
▶ VIEW/SecondPage.xaml.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
namespace TestProject; /// <summary> /// 두번째 페이지 /// </summary> public partial class SecondPage : BasePage<SecondPageViewModel> { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - SecondPage() /// <summary> /// 생성자 /// </summary> public SecondPage(SecondPageViewModel viewModel) : base(viewModel) { InitializeComponent(); } #endregion } |
▶ AppShell.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?xml version="1.0" encoding="UTF-8" ?> <Shell x:Class="TestProject.AppShell" xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:TestProject"> <FlyoutItem Title="메인 페이지"> <ShellContent ContentTemplate="{DataTemplate local:MainPage}" /> </FlyoutItem> <FlyoutItem Title="두번째 페이지"> <ShellContent ContentTemplate="{DataTemplate local:SecondPage}" /> </FlyoutItem> </Shell> |
▶ AppShell.xaml.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
namespace TestProject; /// <summary> /// 앱 셸 /// </summary> public partial class AppShell : Shell { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - AppShell() /// <summary> /// 생성자 /// </summary> public AppShell() { InitializeComponent(); } #endregion } |
▶ MauiProgram.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
using CommunityToolkit.Maui; namespace TestProject; /// <summary> /// MAUI 프로그램 /// </summary> public static class MauiProgram { //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region MAUI 앱 생성하기 - CreateMauiApp() /// <summary> /// MAUI 앱 생성하기 /// </summary> /// <returns>MAUI 앱</returns> public static MauiApp CreateMauiApp() { MauiAppBuilder builder = MauiApp.CreateBuilder(); builder .UseMauiApp<App>() .UseMauiCommunityToolkit() .ConfigureFonts ( fontCollection => { fontCollection.AddFont("OpenSans-Regular.ttf" , "OpenSansRegular" ); fontCollection.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); } ); builder.Services.AddTransientWithShellRoute<MainPage , MainPageViewModel >("//메인페이지" ); builder.Services.AddTransientWithShellRoute<MainDetailPage, MainDetailPageViewModel>("//메인페이지/메인상세페이지"); builder.Services.AddTransientWithShellRoute<SecondPage , SecondPageViewModel >("//두번째페이지" ); return builder.Build(); } #endregion } |