A small application to demo how to structure and architect a MAUI application.
The app is built based on Chick & Paddy UI/UX design by Na Le
As we organize our app in Features with a consistent fold structure as description in High Level Design, below are key steps to add a new page for a feature.
- Create a feature folder under
Features
if not exist- folder name must be the feature name
- Create a
Pages
folder under the created feature folder - Create
- a XAML page - inherits from
BasePage
- a VM class - inherits from
NavigationAwareBaseViewModel
orBaseViewModel
- a XAML page - inherits from
e.g. The SignIn
page of Auth
feature will have below structure
|
|--Features
|--Auth
|--Pages
|--SignInPage.xaml
|--SignInPage.xaml.cs
|--SignInPageViewModel.cs
class diagram
classDiagram
BasePage <|-- SignInPage: extends
BaseViewModel <|-- NavigationAwareBaseViewModel: extends
NavigationAwareBaseViewModel <|-- SignInPageViewModel: extends
SignInPage o-- SignInPageViewModel: BindingContext
class BaseViewModel {
+ Task OnAppearingAsync()
+ Task OnDisappearingAsync()
}
<<abstract>> BaseViewModel
class NavigationAwareBaseViewModel {
+ void OnBack(IDictionary<string, object> query)
+ void OnInit(IDictionary<string, object> query)
}
<<abstract>> NavigationAwareBaseViewModel
class BasePage {
# void OnAppearing()
# void OnDisappearing()
}
<<abstract>> BasePage
# e.g. dotnet cake --target=page --feature Auth --name SignIn
dotnet cake --target=page --feature FEATURE_NAME --name PAGE_NAME_WO_SUFFIX
As we organize our app in Features with a consistent fold structure as description in High Level Design, below are key steps to add a new popup for a feature.
- Create a feature folder under
Features
if not exist- folder name must be the feature name
- Create a
Popups
folder under the created feature folder - Create
- a XAML page - inherits from
BasePopup
- a VM class - inherits from
NavigationAwareBaseViewModel
orBaseViewModel
- a XAML page - inherits from
e.g. The PairingRejectedPopup
page of Pairing
feature will have below structure
|
|--Features
|--Pairing
|--Popups
|--PairingRejectedPopup.xaml
|--PairingRejectedPopup.xaml.cs
|--PairingRejectedPopupViewModel.cs
class diagram
classDiagram
BasePage <|-- BasePopup: extends
BasePopup <|-- PairingRejectedPopup: extends
BaseViewModel <|-- NavigationAwareBaseViewModel: extends
NavigationAwareBaseViewModel <|-- PairingRejectedPopupViewModel: extends
PairingRejectedPopup o-- PairingRejectedPopupViewModel: BindingContext
class BaseViewModel {
+ Task OnAppearingAsync()
+ Task OnDisappearingAsync()
}
<<abstract>> BaseViewModel
class NavigationAwareBaseViewModel {
+ void OnBack(IDictionary<string, object> query)
+ void OnInit(IDictionary<string, object> query)
}
class BasePopup {
// Shell.PresentationMode="Modal"
}
<<abstract>> BasePopup
class BasePage {
# void OnAppearing()
# void OnDisappearing()
}
<<abstract>> BasePage
# e.g. dotnet cake --target=popup --feature Pairing --name PairingRejected
dotnet cake --target=popup --feature FEATURE_NAME --name POPUP_NAME_WO_SUFFIX
As we organize our app in Features with a consistent fold structure as description in High Level Design, below are key steps to add a new model for a feature.
- Create a feature folder under
Features
if not exist- folder name must be the feature name
- Create a
Models
folder under the created feature folder - Create
- a Model class - inherits from
BaseModel
orBaseFormModel
- a Model class - inherits from
BaseFormModel
will be used when the UI are entry elements; otherwiseBaseModel
.BaseFormModel
will leverage the validation feature of MVVM toolkit.
e.g.
- The
SignIn
form model ofAuth
feature will have below structure
|
|--Features
|--Auth
|--Models
|--SignInFormModel.cs
- The
WalkthroughItem
model ofLanding
feature will have below structure
|
|--Features
|--Landing
|--Models
|--WalkthroughItemModel.cs
class diagram
classDiagram
BaseModel <|-- WalkthroughItemModel: extends
BaseFormModel <|-- SignInFormModel: extends
ObservableValidator <|-- BaseFormModel: extends
ObservableObject <|-- ObservableValidator: extends
ObservableObject <|-- BaseModel: extends
l
class BaseFormModel
<<abstract>> BaseFormModel
class BaseFormModel {
# string[] ValidatableAndSupportPropertyNames
+ bool IsValid()
}
<<abstract>> BaseFormModel
class ObservableValidator {
// MVVM toolkit
}
<<abstract>> ObservableValidator
class ObservableObject {
// MVVM toolkit
}
<<abstract>> ObservableObject
# e.g. dotnet cake --target=model --form true --feature Auth --name SignIn
dotnet cake --target=popup --feature FEATURE_NAME --name MODEL_NAME_WO_SUFFIX --form true
# e.g. dotnet cake --target=model --feature Landing --name WalkthroughItem
dotnet cake --target=popup --feature FEATURE_NAME --name MODEL_NAME_WO_SUFFIX
- Material Design Icons
- Archia Font - paid and in design
- Montserrat Font - Free, alternative
This project is maintained by tuyen-vuduc in his spare time.
If you find this project is useful, please become a sponsor of the project and/or buy him a coffee.
The 3rd libraries will follow their associated licenses. This project itself is license under MIT license.
Copyright 2022 Tuyen Vu
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.