Repository: HenJigg/wpf-abp Branch: master Commit: fa83dae95acb Files: 1609 Total size: 10.5 MB Directory structure: gitextract_zbohz0js/ ├── .gitattributes ├── .gitignore ├── LICENSE ├── README-en.md ├── README.md └── aspnet-core/ ├── .gitattributes ├── .gitignore ├── AppFramework.Mobile.sln ├── AppFramework.Wpf.sln ├── Settings.XamlStyler ├── common.props └── src/ ├── AppFramework.Admin/ │ ├── AdminModuleExtensions.cs │ ├── AppFramework.Admin.csproj │ ├── Behaviors/ │ │ ├── ChatMessageListViewBehavior.cs │ │ └── PasswordBehavior.cs │ ├── Extensions/ │ │ └── EnumerableExtensions.cs │ ├── Models/ │ │ ├── AdminModuleMapper.cs │ │ ├── Auditlogs/ │ │ │ ├── AuditLogListModel.cs │ │ │ ├── GetAuditLogsFilter.cs │ │ │ └── GetEntityChangeFilter.cs │ │ ├── Dashboard/ │ │ │ ├── AreaSeriesChart3DModel.cs │ │ │ ├── DoughnutChartPopulations.cs │ │ │ └── TopStatusItem.cs │ │ ├── DynamicProperty/ │ │ │ └── DynamicPropertyModel.cs │ │ ├── Edition/ │ │ │ ├── EditionCreateModel.cs │ │ │ ├── EditionListModel.cs │ │ │ └── FlatFeatureModel.cs │ │ ├── Filters/ │ │ │ ├── PagedAndSortedFilter.cs │ │ │ └── PagedFilter.cs │ │ ├── Language/ │ │ │ ├── Language.cs │ │ │ ├── LanguageListModel.cs │ │ │ └── LanguageTextListModel.cs │ │ ├── Organizations/ │ │ │ ├── CreateOrganizationUnitModel.cs │ │ │ ├── OrganizationListModel.cs │ │ │ └── OrganizationUnitModel.cs │ │ ├── Permission/ │ │ │ ├── PermissionHelper.cs │ │ │ └── PermissionModel.cs │ │ ├── Roles/ │ │ │ ├── ChooseItem.cs │ │ │ ├── RoleEditModel.cs │ │ │ ├── RoleListModel.cs │ │ │ └── UserRoleModel.cs │ │ ├── Tenants/ │ │ │ ├── GetTenantsFilter.cs │ │ │ └── TenantListModel.cs │ │ ├── Update/ │ │ │ └── VersionListModel.cs │ │ └── Users/ │ │ ├── UserCreateOrUpdateModel.cs │ │ ├── UserEditModel.cs │ │ ├── UserForEditModel.cs │ │ ├── UserListModel.cs │ │ └── UserLoginInfoModel.cs │ ├── Services/ │ │ ├── Account/ │ │ │ ├── AccountService.cs │ │ │ ├── AccountStorageService.cs │ │ │ ├── ApplicationService.cs │ │ │ ├── IAccountService.cs │ │ │ ├── IApplicationService.cs │ │ │ └── UserConfigurationManager.cs │ │ ├── Features/ │ │ │ ├── FeaturesService.cs │ │ │ └── IFeaturesService.cs │ │ ├── Mapper/ │ │ │ └── AppMapper.cs │ │ ├── Navigation/ │ │ │ ├── INavigationMenuService.cs │ │ │ ├── NavigationMenuService.cs │ │ │ ├── NavigationService.cs │ │ │ └── NavigationSingleMenuService.cs │ │ ├── Notification/ │ │ │ └── NotificationService.cs │ │ ├── Permission/ │ │ │ ├── IPermissionTreesService.cs │ │ │ ├── PermissionPorxyService.cs │ │ │ ├── PermissionService.cs │ │ │ └── PermissionTreesService.cs │ │ ├── ServiceExtensions.cs │ │ └── Update/ │ │ └── UpdateService.cs │ ├── Validations/ │ │ ├── AdminValidatorExtensions.cs │ │ ├── EditionValidator.cs │ │ ├── OrganizationUnitValidator.cs │ │ ├── SettingsValidator.cs │ │ ├── TenantValidator.cs │ │ ├── UserValidator.cs │ │ └── VersionValidator.cs │ └── ViewModels/ │ ├── Account/ │ │ ├── ChangeAvatarViewModel.cs │ │ ├── ChangePasswordViewModel.cs │ │ ├── CreateLinkedAccountViewModel.cs │ │ ├── EmailActivationViewModel.cs │ │ ├── ForgotPasswordViewModel.cs │ │ ├── LoginAttemptsViewModel.cs │ │ ├── ManageLinkedAccountsViewModel.cs │ │ ├── ManageNewUserViewModel.cs │ │ ├── ManageUserDelegationsViewModel.cs │ │ ├── MyProfileViewModel.cs │ │ ├── MySettingsViewModel.cs │ │ ├── NotificationViewModel.cs │ │ ├── SelectDateRangeViewModel.cs │ │ └── SendTwoFactorCodeViewModel.cs │ ├── Auditlogs/ │ │ ├── AuditLogsDetailsViewModel.cs │ │ └── AuditLogsViewModel.cs │ ├── Chat/ │ │ ├── FriendsChatViewModel.cs │ │ └── FriendsViewModel.cs │ ├── Dashboard/ │ │ └── DashboardViewModel.cs │ ├── Demo/ │ │ └── DemoViewModel.cs │ ├── DynamicProperty/ │ │ ├── DynamicAddEntityViewModel.cs │ │ ├── DynamicEditValuesViewModel.cs │ │ ├── DynamicEntityDetailsViewModel.cs │ │ ├── DynamicPropertyDetailsViewModel.cs │ │ └── DynamicPropertyViewModel.cs │ ├── Edition/ │ │ ├── EditionDetailsViewModel.cs │ │ └── EditionViewModel.cs │ ├── Language/ │ │ ├── LanguageDetailsViewModel.cs │ │ ├── LanguageTextDetailsViewModel.cs │ │ ├── LanguageTextViewModel.cs │ │ └── LanguageViewModel.cs │ ├── LoginViewModel.cs │ ├── MainTabsViewModel.cs │ ├── Organizations/ │ │ ├── AddRolesViewModel.cs │ │ ├── AddUsersViewModel.cs │ │ ├── OrganizationsAddViewModel.cs │ │ └── OrganizationsViewModel.cs │ ├── Roles/ │ │ ├── RoleDetailsViewModel.cs │ │ ├── RoleViewModel.cs │ │ └── SelectedPermissionViewModel.cs │ ├── Settings/ │ │ └── SettingsViewModel.cs │ ├── Shared/ │ │ ├── DemoUiViewModel.cs │ │ ├── FirstChangedPwdViewModel.cs │ │ ├── SelectTenantViewModel.cs │ │ └── UserPanelViewModel.cs │ ├── SplashScreenViewModel.cs │ ├── TaskBarViewModel.cs │ ├── Tenants/ │ │ ├── TenantChangeFeaturesViewModel.cs │ │ ├── TenantDetailsViewModel.cs │ │ └── TenantViewModel.cs │ ├── Users/ │ │ ├── SelectedUserViewModel.cs │ │ ├── UserChangePermissionViewModel.cs │ │ ├── UserDetailsViewModel.cs │ │ └── UserViewModel.cs │ ├── Version/ │ │ ├── VersionManagerDetailsViewModel.cs │ │ └── VersionManagerViewModel.cs │ └── Visual/ │ └── VisualViewModel.cs ├── AppFramework.Admin.HandyUI/ │ ├── App.xaml │ ├── App.xaml.cs │ ├── AppFramework.Admin.HandyUI.csproj │ ├── Converters/ │ │ └── MenuTitleConverter.cs │ ├── Extensions/ │ │ ├── ContainerExtensions.cs │ │ └── TabControlRegionAdapter.cs │ ├── HandyUIStartService.cs │ ├── Localization/ │ │ ├── LocalTranslationHelper.cs │ │ ├── LocaleCulture.cs │ │ └── Resources/ │ │ ├── LocalTranslation.Designer.cs │ │ ├── LocalTranslation.resx │ │ └── LocalTranslation.zh-Hans.resx │ ├── Services/ │ │ ├── Features/ │ │ │ └── FeaturesService.cs │ │ ├── Permission/ │ │ │ └── PermissionTreesService.cs │ │ └── Sessions/ │ │ └── DialogHostService.cs │ ├── Themes/ │ │ ├── Button.xaml │ │ ├── Controls/ │ │ │ ├── Card.cs │ │ │ ├── DataPager.cs │ │ │ ├── Extensions.cs │ │ │ ├── IntToStringConverter.cs │ │ │ ├── NotConverter.cs │ │ │ ├── PopupBox.cs │ │ │ ├── PopupEx.cs │ │ │ ├── ScrollViewerAssist.cs │ │ │ ├── TabAssist.cs │ │ │ ├── TabCloseItem.cs │ │ │ └── TabControl.cs │ │ ├── DataPager.xaml │ │ ├── Generic.xaml │ │ ├── Host/ │ │ │ ├── DialogClosingEventArgs.cs │ │ │ ├── DialogClosingEventHandler.cs │ │ │ ├── DialogHost.cs │ │ │ ├── DialogHost.xaml │ │ │ ├── DialogHostEx.cs │ │ │ ├── DialogHostServiceExtensions.cs │ │ │ ├── DialogOpenedEventArgs.cs │ │ │ ├── DialogOpenedEventHandler.cs │ │ │ ├── DialogSession.cs │ │ │ ├── TransitionAssist.cs │ │ │ └── ValidationAssist.cs │ │ └── TabControl.xaml │ ├── Views/ │ │ ├── Account/ │ │ │ ├── ChangeAvatarView.xaml │ │ │ ├── ChangeAvatarView.xaml.cs │ │ │ ├── ChangePasswordView.xaml │ │ │ ├── ChangePasswordView.xaml.cs │ │ │ ├── CreateLinkedAccountView.xaml │ │ │ ├── CreateLinkedAccountView.xaml.cs │ │ │ ├── EmailActivationView.xaml │ │ │ ├── EmailActivationView.xaml.cs │ │ │ ├── ForgotPasswordView.xaml │ │ │ ├── ForgotPasswordView.xaml.cs │ │ │ ├── LoginAttemptsView.xaml │ │ │ ├── LoginAttemptsView.xaml.cs │ │ │ ├── ManageLinkedAccountsView.xaml │ │ │ ├── ManageLinkedAccountsView.xaml.cs │ │ │ ├── ManageNewUserView.xaml │ │ │ ├── ManageNewUserView.xaml.cs │ │ │ ├── ManageUserDelegationsView.xaml │ │ │ ├── ManageUserDelegationsView.xaml.cs │ │ │ ├── MyProfileView.xaml │ │ │ ├── MyProfileView.xaml.cs │ │ │ ├── MySettingsView.xaml │ │ │ ├── MySettingsView.xaml.cs │ │ │ ├── NotificationView.xaml │ │ │ ├── NotificationView.xaml.cs │ │ │ ├── SelectDateRangeView.xaml │ │ │ ├── SelectDateRangeView.xaml.cs │ │ │ ├── SendTwoFactorCodeView.xaml │ │ │ └── SendTwoFactorCodeView.xaml.cs │ │ ├── Auditlogs/ │ │ │ ├── AuditLogsDetailsView.xaml │ │ │ ├── AuditLogsDetailsView.xaml.cs │ │ │ ├── AuditLogsView.xaml │ │ │ └── AuditLogsView.xaml.cs │ │ ├── Chat/ │ │ │ ├── FriendsChatView.xaml │ │ │ ├── FriendsChatView.xaml.cs │ │ │ ├── FriendsView.xaml │ │ │ ├── FriendsView.xaml.cs │ │ │ └── Selectors/ │ │ │ └── ChatDataTemplateSelector.cs │ │ ├── Dashboard/ │ │ │ ├── DashboardView.xaml │ │ │ └── DashboardView.xaml.cs │ │ ├── DynamicProperty/ │ │ │ ├── DynamicAddEntityView.xaml │ │ │ ├── DynamicAddEntityView.xaml.cs │ │ │ ├── DynamicEditValuesView.xaml │ │ │ ├── DynamicEditValuesView.xaml.cs │ │ │ ├── DynamicEntityDetailsView.xaml │ │ │ ├── DynamicEntityDetailsView.xaml.cs │ │ │ ├── DynamicPropertyDetailsView.xaml │ │ │ ├── DynamicPropertyDetailsView.xaml.cs │ │ │ ├── DynamicPropertyView.xaml │ │ │ └── DynamicPropertyView.xaml.cs │ │ ├── Edition/ │ │ │ ├── EditionDetailsView.xaml │ │ │ ├── EditionDetailsView.xaml.cs │ │ │ ├── EditionView.xaml │ │ │ └── EditionView.xaml.cs │ │ ├── Language/ │ │ │ ├── LanguageDetailsView.xaml │ │ │ ├── LanguageDetailsView.xaml.cs │ │ │ ├── LanguageTextDetailsView.xaml │ │ │ ├── LanguageTextDetailsView.xaml.cs │ │ │ ├── LanguageTextView.xaml │ │ │ ├── LanguageTextView.xaml.cs │ │ │ ├── LanguageView.xaml │ │ │ └── LanguageView.xaml.cs │ │ ├── LoginView.xaml │ │ ├── LoginView.xaml.cs │ │ ├── MainTabsView.xaml │ │ ├── MainTabsView.xaml.cs │ │ ├── Organizations/ │ │ │ ├── AddRolesView.xaml │ │ │ ├── AddRolesView.xaml.cs │ │ │ ├── AddUsersView.xaml │ │ │ ├── AddUsersView.xaml.cs │ │ │ ├── OrganizationsAddView.xaml │ │ │ ├── OrganizationsAddView.xaml.cs │ │ │ ├── OrganizationsView.xaml │ │ │ └── OrganizationsView.xaml.cs │ │ ├── Roles/ │ │ │ ├── RoleDetailsView.xaml │ │ │ ├── RoleDetailsView.xaml.cs │ │ │ ├── RoleView.xaml │ │ │ ├── RoleView.xaml.cs │ │ │ ├── SelectedPermissionView.xaml │ │ │ └── SelectedPermissionView.xaml.cs │ │ ├── Settings/ │ │ │ ├── SettingsView.xaml │ │ │ └── SettingsView.xaml.cs │ │ ├── Shared/ │ │ │ ├── DemoUiView.xaml │ │ │ ├── DemoUiView.xaml.cs │ │ │ ├── FirstChangedPwdView.xaml │ │ │ ├── FirstChangedPwdView.xaml.cs │ │ │ ├── HostMessageBoxView.xaml │ │ │ ├── HostMessageBoxView.xaml.cs │ │ │ ├── MessageBoxView.xaml │ │ │ ├── MessageBoxView.xaml.cs │ │ │ ├── SelectTenantView.xaml │ │ │ ├── SelectTenantView.xaml.cs │ │ │ ├── SplashScreenView.xaml │ │ │ ├── SplashScreenView.xaml.cs │ │ │ ├── UserPanelView.xaml │ │ │ └── UserPanelView.xaml.cs │ │ ├── Tenants/ │ │ │ ├── TenantChangeFeaturesView.xaml │ │ │ ├── TenantChangeFeaturesView.xaml.cs │ │ │ ├── TenantDetailsView.xaml │ │ │ ├── TenantDetailsView.xaml.cs │ │ │ ├── TenantView.xaml │ │ │ └── TenantView.xaml.cs │ │ ├── Users/ │ │ │ ├── SelectedUserView.xaml │ │ │ ├── SelectedUserView.xaml.cs │ │ │ ├── UserChangePermissionView.xaml │ │ │ ├── UserChangePermissionView.xaml.cs │ │ │ ├── UserDetailsView.xaml │ │ │ ├── UserDetailsView.xaml.cs │ │ │ ├── UserView.xaml │ │ │ └── UserView.xaml.cs │ │ ├── Version/ │ │ │ ├── VersionManagerDetailsView.xaml │ │ │ ├── VersionManagerDetailsView.xaml.cs │ │ │ ├── VersionManagerView.xaml │ │ │ └── VersionManagerView.xaml.cs │ │ └── Visual/ │ │ ├── VisualView.xaml │ │ └── VisualView.xaml.cs │ ├── VisualViewModel.cs │ └── nlog.config ├── AppFramework.Admin.MaterialUI/ │ ├── App.xaml │ ├── App.xaml.cs │ ├── AppFramework.Admin.MaterialUI.csproj │ ├── Converters/ │ │ ├── ColorToBrushConverter.cs │ │ └── MenuTitleConverter.cs │ ├── Extensions/ │ │ ├── ContainerExtensions.cs │ │ └── TabControlRegionAdapter.cs │ ├── Localization/ │ │ ├── LocalTranslationHelper.cs │ │ ├── LocaleCulture.cs │ │ └── Resources/ │ │ ├── LocalTranslation.Designer.cs │ │ ├── LocalTranslation.resx │ │ └── LocalTranslation.zh-Hans.resx │ ├── MaterialUIStartService.cs │ ├── Services/ │ │ ├── Features/ │ │ │ └── FeaturesService.cs │ │ ├── Permission/ │ │ │ └── PermissionTreesService.cs │ │ └── Sessions/ │ │ └── DialogHostService.cs │ ├── Themes/ │ │ ├── Button.xaml │ │ ├── Controls/ │ │ │ ├── DataPager.cs │ │ │ ├── Extensions.cs │ │ │ ├── IntToStringConverter.cs │ │ │ ├── ScrollViewerAssist.cs │ │ │ ├── TabAssist.cs │ │ │ ├── TabCloseItem.cs │ │ │ └── TabControl.cs │ │ ├── DataPager.xaml │ │ ├── Generic.xaml │ │ └── TabControl.xaml │ ├── Views/ │ │ ├── Account/ │ │ │ ├── ChangeAvatarView.xaml │ │ │ ├── ChangeAvatarView.xaml.cs │ │ │ ├── ChangePasswordView.xaml │ │ │ ├── ChangePasswordView.xaml.cs │ │ │ ├── CreateLinkedAccountView.xaml │ │ │ ├── CreateLinkedAccountView.xaml.cs │ │ │ ├── EmailActivationView.xaml │ │ │ ├── EmailActivationView.xaml.cs │ │ │ ├── ForgotPasswordView.xaml │ │ │ ├── ForgotPasswordView.xaml.cs │ │ │ ├── LoginAttemptsView.xaml │ │ │ ├── LoginAttemptsView.xaml.cs │ │ │ ├── ManageLinkedAccountsView.xaml │ │ │ ├── ManageLinkedAccountsView.xaml.cs │ │ │ ├── ManageNewUserView.xaml │ │ │ ├── ManageNewUserView.xaml.cs │ │ │ ├── ManageUserDelegationsView.xaml │ │ │ ├── ManageUserDelegationsView.xaml.cs │ │ │ ├── MyProfileView.xaml │ │ │ ├── MyProfileView.xaml.cs │ │ │ ├── MySettingsView.xaml │ │ │ ├── MySettingsView.xaml.cs │ │ │ ├── NotificationView.xaml │ │ │ ├── NotificationView.xaml.cs │ │ │ ├── SelectDateRangeView.xaml │ │ │ ├── SelectDateRangeView.xaml.cs │ │ │ ├── SendTwoFactorCodeView.xaml │ │ │ └── SendTwoFactorCodeView.xaml.cs │ │ ├── Auditlogs/ │ │ │ ├── AuditLogsDetailsView.xaml │ │ │ ├── AuditLogsDetailsView.xaml.cs │ │ │ ├── AuditLogsView.xaml │ │ │ └── AuditLogsView.xaml.cs │ │ ├── Chat/ │ │ │ ├── FriendsChatView.xaml │ │ │ ├── FriendsChatView.xaml.cs │ │ │ ├── FriendsView.xaml │ │ │ ├── FriendsView.xaml.cs │ │ │ └── Selectors/ │ │ │ └── ChatDataTemplateSelector.cs │ │ ├── Dashboard/ │ │ │ ├── DashboardView.xaml │ │ │ └── DashboardView.xaml.cs │ │ ├── DynamicProperty/ │ │ │ ├── DynamicAddEntityView.xaml │ │ │ ├── DynamicAddEntityView.xaml.cs │ │ │ ├── DynamicEditValuesView.xaml │ │ │ ├── DynamicEditValuesView.xaml.cs │ │ │ ├── DynamicEntityDetailsView.xaml │ │ │ ├── DynamicEntityDetailsView.xaml.cs │ │ │ ├── DynamicPropertyDetailsView.xaml │ │ │ ├── DynamicPropertyDetailsView.xaml.cs │ │ │ ├── DynamicPropertyView.xaml │ │ │ └── DynamicPropertyView.xaml.cs │ │ ├── Edition/ │ │ │ ├── EditionDetailsView.xaml │ │ │ ├── EditionDetailsView.xaml.cs │ │ │ ├── EditionView.xaml │ │ │ └── EditionView.xaml.cs │ │ ├── Language/ │ │ │ ├── LanguageDetailsView.xaml │ │ │ ├── LanguageDetailsView.xaml.cs │ │ │ ├── LanguageTextDetailsView.xaml │ │ │ ├── LanguageTextDetailsView.xaml.cs │ │ │ ├── LanguageTextView.xaml │ │ │ ├── LanguageTextView.xaml.cs │ │ │ ├── LanguageView.xaml │ │ │ └── LanguageView.xaml.cs │ │ ├── LoginView.xaml │ │ ├── LoginView.xaml.cs │ │ ├── MainTabsView.xaml │ │ ├── MainTabsView.xaml.cs │ │ ├── Organizations/ │ │ │ ├── AddRolesView.xaml │ │ │ ├── AddRolesView.xaml.cs │ │ │ ├── AddUsersView.xaml │ │ │ ├── AddUsersView.xaml.cs │ │ │ ├── OrganizationsAddView.xaml │ │ │ ├── OrganizationsAddView.xaml.cs │ │ │ ├── OrganizationsView.xaml │ │ │ └── OrganizationsView.xaml.cs │ │ ├── Roles/ │ │ │ ├── RoleDetailsView.xaml │ │ │ ├── RoleDetailsView.xaml.cs │ │ │ ├── RoleView.xaml │ │ │ ├── RoleView.xaml.cs │ │ │ ├── SelectedPermissionView.xaml │ │ │ └── SelectedPermissionView.xaml.cs │ │ ├── Settings/ │ │ │ ├── SettingsView.xaml │ │ │ └── SettingsView.xaml.cs │ │ ├── Shared/ │ │ │ ├── DemoUiView.xaml │ │ │ ├── DemoUiView.xaml.cs │ │ │ ├── FirstChangedPwdView.xaml │ │ │ ├── FirstChangedPwdView.xaml.cs │ │ │ ├── HostMessageBoxView.xaml │ │ │ ├── HostMessageBoxView.xaml.cs │ │ │ ├── MessageBoxView.xaml │ │ │ ├── MessageBoxView.xaml.cs │ │ │ ├── SelectTenantView.xaml │ │ │ ├── SelectTenantView.xaml.cs │ │ │ ├── SplashScreenView.xaml │ │ │ ├── SplashScreenView.xaml.cs │ │ │ ├── UserPanelView.xaml │ │ │ └── UserPanelView.xaml.cs │ │ ├── Tenants/ │ │ │ ├── TenantChangeFeaturesView.xaml │ │ │ ├── TenantChangeFeaturesView.xaml.cs │ │ │ ├── TenantDetailsView.xaml │ │ │ ├── TenantDetailsView.xaml.cs │ │ │ ├── TenantView.xaml │ │ │ └── TenantView.xaml.cs │ │ ├── Users/ │ │ │ ├── SelectedUserView.xaml │ │ │ ├── SelectedUserView.xaml.cs │ │ │ ├── UserChangePermissionView.xaml │ │ │ ├── UserChangePermissionView.xaml.cs │ │ │ ├── UserDetailsView.xaml │ │ │ ├── UserDetailsView.xaml.cs │ │ │ ├── UserView.xaml │ │ │ └── UserView.xaml.cs │ │ ├── Version/ │ │ │ ├── VersionManagerDetailsView.xaml │ │ │ ├── VersionManagerDetailsView.xaml.cs │ │ │ ├── VersionManagerView.xaml │ │ │ └── VersionManagerView.xaml.cs │ │ └── Visual/ │ │ ├── VisualView.xaml │ │ └── VisualView.xaml.cs │ ├── VisualViewModel.cs │ └── nlog.config ├── AppFramework.Admin.SyncUI/ │ ├── App.xaml │ ├── App.xaml.cs │ ├── AppFramework.Admin.SyncUI.csproj │ ├── Converters/ │ │ └── MenuTitleConverter.cs │ ├── Extensions/ │ │ ├── ContainerExtensions.cs │ │ └── SfTabControlRegionAdapter.cs │ ├── Localization/ │ │ ├── LocalTranslationHelper.cs │ │ ├── LocaleCulture.cs │ │ └── Resources/ │ │ ├── LocalTranslation.Designer.cs │ │ ├── LocalTranslation.resx │ │ └── LocalTranslation.zh-Hans.resx │ ├── Resources/ │ │ ├── en-US/ │ │ │ ├── Syncfusion.Chart.WPF.resx │ │ │ ├── Syncfusion.Diagram.Wpf.resx │ │ │ ├── Syncfusion.Edit.Wpf.resx │ │ │ ├── Syncfusion.Gantt.WPF.resx │ │ │ ├── Syncfusion.Grid.Wpf.resx │ │ │ ├── Syncfusion.OlapChart.WPF.resx │ │ │ ├── Syncfusion.OlapClient.WPF.resx │ │ │ ├── Syncfusion.OlapGauge.wpf.resx │ │ │ ├── Syncfusion.OlapGrid.WPF.resx │ │ │ ├── Syncfusion.OlapShared.WPF.resx │ │ │ ├── Syncfusion.OlapTools.WPF.resx │ │ │ ├── Syncfusion.PdfViewer.WPF.resx │ │ │ ├── Syncfusion.PivotAnalysis.Wpf.resx │ │ │ ├── Syncfusion.PropertyGrid.Wpf.resx │ │ │ ├── Syncfusion.Schedule.WPF.resx │ │ │ ├── Syncfusion.SfChart.WPF.resx │ │ │ ├── Syncfusion.SfColorPalette.Wpf.resx │ │ │ ├── Syncfusion.SfDiagramRibbon.WPF.resx │ │ │ ├── Syncfusion.SfGrid.WPF.resx │ │ │ ├── Syncfusion.SfImageEditor.WPF.resx │ │ │ ├── Syncfusion.SfInput.Wpf.resx │ │ │ ├── Syncfusion.SfKanban.WPF.resx │ │ │ ├── Syncfusion.SfRichTextBoxAdv.WPF.resx │ │ │ ├── Syncfusion.SfRichTextRibbon.WPF.resx │ │ │ ├── Syncfusion.SfScheduler.WPF.resx │ │ │ ├── Syncfusion.SfShared.Wpf.resx │ │ │ ├── Syncfusion.SfSmithChart.WPF.resx │ │ │ ├── Syncfusion.SfSpellChecker.WPF.resx │ │ │ ├── Syncfusion.SfSpreadsheet.Wpf.resx │ │ │ ├── Syncfusion.SfSunburstChart.WPF.resx │ │ │ ├── Syncfusion.SfTreeView.WPF.resx │ │ │ ├── Syncfusion.Shared.Wpf.Classic.resx │ │ │ ├── Syncfusion.Shared.Wpf.resx │ │ │ ├── Syncfusion.Speradsheet.Wpf.resx │ │ │ ├── Syncfusion.Tools.Wpf.Classic.resx │ │ │ ├── Syncfusion.Tools.Wpf.resx │ │ │ └── Syncfusion.UI.Xaml.Diagram.resx │ │ └── zh-CN/ │ │ ├── Syncfusion.Chart.WPF.resx │ │ ├── Syncfusion.Diagram.Wpf.resx │ │ ├── Syncfusion.Edit.Wpf.resx │ │ ├── Syncfusion.Gantt.WPF.resx │ │ ├── Syncfusion.Grid.Wpf.resx │ │ ├── Syncfusion.OlapChart.WPF.resx │ │ ├── Syncfusion.OlapClient.WPF.resx │ │ ├── Syncfusion.OlapGauge.wpf.resx │ │ ├── Syncfusion.OlapGrid.WPF.resx │ │ ├── Syncfusion.OlapShared.WPF.resx │ │ ├── Syncfusion.OlapTools.WPF.resx │ │ ├── Syncfusion.PdfViewer.WPF.resx │ │ ├── Syncfusion.PivotAnalysis.Wpf.resx │ │ ├── Syncfusion.PropertyGrid.Wpf.resx │ │ ├── Syncfusion.Schedule.WPF.resx │ │ ├── Syncfusion.SfChart.WPF.resx │ │ ├── Syncfusion.SfColorPalette.Wpf.resx │ │ ├── Syncfusion.SfDiagramRibbon.WPF.resx │ │ ├── Syncfusion.SfGrid.WPF.zh-CN.resx │ │ ├── Syncfusion.SfImageEditor.WPF.resx │ │ ├── Syncfusion.SfInput.Wpf.resx │ │ ├── Syncfusion.SfKanban.WPF.resx │ │ ├── Syncfusion.SfRichTextBoxAdv.WPF.resx │ │ ├── Syncfusion.SfRichTextRibbon.WPF.resx │ │ ├── Syncfusion.SfScheduler.WPF.resx │ │ ├── Syncfusion.SfShared.Wpf.resx │ │ ├── Syncfusion.SfSmithChart.WPF.resx │ │ ├── Syncfusion.SfSpellChecker.WPF.resx │ │ ├── Syncfusion.SfSpreadsheet.Wpf.resx │ │ ├── Syncfusion.SfSunburstChart.WPF.resx │ │ ├── Syncfusion.SfTreeView.WPF.resx │ │ ├── Syncfusion.Shared.Wpf.Classic.resx │ │ ├── Syncfusion.Shared.Wpf.resx │ │ ├── Syncfusion.Speradsheet.Wpf.resx │ │ ├── Syncfusion.Tools.Wpf.Classic.resx │ │ ├── Syncfusion.Tools.Wpf.zh-CN.resx │ │ └── Syncfusion.UI.Xaml.Diagram.resx │ ├── Services/ │ │ ├── Sessions/ │ │ │ └── DialogHostService.cs │ │ └── Themes/ │ │ ├── SkinManagerExtensions.cs │ │ └── ThemeService.cs │ ├── SyncUIStartService.cs │ ├── Themes/ │ │ ├── Border.xaml │ │ ├── Button.xaml │ │ ├── DataGrid.xaml │ │ ├── Generic.xaml │ │ └── Host/ │ │ ├── Card.cs │ │ ├── DialogClosingEventArgs.cs │ │ ├── DialogClosingEventHandler.cs │ │ ├── DialogHost.cs │ │ ├── DialogHost.xaml │ │ ├── DialogHostEx.cs │ │ ├── DialogHostServiceExtensions.cs │ │ ├── DialogOpenedEventArgs.cs │ │ ├── DialogOpenedEventHandler.cs │ │ ├── DialogSession.cs │ │ ├── PopupEx.cs │ │ ├── TransitionAssist.cs │ │ └── ValidationAssist.cs │ ├── Views/ │ │ ├── Account/ │ │ │ ├── ChangeAvatarView.xaml │ │ │ ├── ChangeAvatarView.xaml.cs │ │ │ ├── ChangePasswordView.xaml │ │ │ ├── ChangePasswordView.xaml.cs │ │ │ ├── CreateLinkedAccountView.xaml │ │ │ ├── CreateLinkedAccountView.xaml.cs │ │ │ ├── EmailActivationView.xaml │ │ │ ├── EmailActivationView.xaml.cs │ │ │ ├── ForgotPasswordView.xaml │ │ │ ├── ForgotPasswordView.xaml.cs │ │ │ ├── LoginAttemptsView.xaml │ │ │ ├── LoginAttemptsView.xaml.cs │ │ │ ├── ManageLinkedAccountsView.xaml │ │ │ ├── ManageLinkedAccountsView.xaml.cs │ │ │ ├── ManageNewUserView.xaml │ │ │ ├── ManageNewUserView.xaml.cs │ │ │ ├── ManageUserDelegationsView.xaml │ │ │ ├── ManageUserDelegationsView.xaml.cs │ │ │ ├── MyProfileView.xaml │ │ │ ├── MyProfileView.xaml.cs │ │ │ ├── MySettingsView.xaml │ │ │ ├── MySettingsView.xaml.cs │ │ │ ├── NotificationView.xaml │ │ │ ├── NotificationView.xaml.cs │ │ │ ├── SelectDateRangeView.xaml │ │ │ ├── SelectDateRangeView.xaml.cs │ │ │ ├── SendTwoFactorCodeView.xaml │ │ │ └── SendTwoFactorCodeView.xaml.cs │ │ ├── Auditlogs/ │ │ │ ├── AuditLogsDetailsView.xaml │ │ │ ├── AuditLogsDetailsView.xaml.cs │ │ │ ├── AuditLogsView.xaml │ │ │ └── AuditLogsView.xaml.cs │ │ ├── Chat/ │ │ │ ├── FriendsChatView.xaml │ │ │ ├── FriendsChatView.xaml.cs │ │ │ ├── FriendsView.xaml │ │ │ ├── FriendsView.xaml.cs │ │ │ └── Selectors/ │ │ │ └── ChatDataTemplateSelector.cs │ │ ├── Dashboard/ │ │ │ ├── DashboardView.xaml │ │ │ └── DashboardView.xaml.cs │ │ ├── Demo/ │ │ │ ├── DemoView.xaml │ │ │ └── DemoView.xaml.cs │ │ ├── DynamicProperty/ │ │ │ ├── DynamicAddEntityView.xaml │ │ │ ├── DynamicAddEntityView.xaml.cs │ │ │ ├── DynamicEditValuesView.xaml │ │ │ ├── DynamicEditValuesView.xaml.cs │ │ │ ├── DynamicEntityDetailsView.xaml │ │ │ ├── DynamicEntityDetailsView.xaml.cs │ │ │ ├── DynamicPropertyDetailsView.xaml │ │ │ ├── DynamicPropertyDetailsView.xaml.cs │ │ │ ├── DynamicPropertyView.xaml │ │ │ └── DynamicPropertyView.xaml.cs │ │ ├── Edition/ │ │ │ ├── EditionDetailsView.xaml │ │ │ ├── EditionDetailsView.xaml.cs │ │ │ ├── EditionView.xaml │ │ │ └── EditionView.xaml.cs │ │ ├── Language/ │ │ │ ├── LanguageDetailsView.xaml │ │ │ ├── LanguageDetailsView.xaml.cs │ │ │ ├── LanguageTextDetailsView.xaml │ │ │ ├── LanguageTextDetailsView.xaml.cs │ │ │ ├── LanguageTextView.xaml │ │ │ ├── LanguageTextView.xaml.cs │ │ │ ├── LanguageView.xaml │ │ │ └── LanguageView.xaml.cs │ │ ├── LoginView.xaml │ │ ├── LoginView.xaml.cs │ │ ├── MainTabsView.xaml │ │ ├── MainTabsView.xaml.cs │ │ ├── Organizations/ │ │ │ ├── AddRolesView.xaml │ │ │ ├── AddRolesView.xaml.cs │ │ │ ├── AddUsersView.xaml │ │ │ ├── AddUsersView.xaml.cs │ │ │ ├── OrganizationsAddView.xaml │ │ │ ├── OrganizationsAddView.xaml.cs │ │ │ ├── OrganizationsView.xaml │ │ │ └── OrganizationsView.xaml.cs │ │ ├── Roles/ │ │ │ ├── RoleDetailsView.xaml │ │ │ ├── RoleDetailsView.xaml.cs │ │ │ ├── RoleView.xaml │ │ │ ├── RoleView.xaml.cs │ │ │ ├── SelectedPermissionView.xaml │ │ │ └── SelectedPermissionView.xaml.cs │ │ ├── Settings/ │ │ │ ├── SettingsView.xaml │ │ │ └── SettingsView.xaml.cs │ │ ├── Shared/ │ │ │ ├── BusyView.xaml │ │ │ ├── BusyView.xaml.cs │ │ │ ├── DemoUiView.xaml │ │ │ ├── DemoUiView.xaml.cs │ │ │ ├── FirstChangedPwdView.xaml │ │ │ ├── FirstChangedPwdView.xaml.cs │ │ │ ├── HostMessageBoxView.xaml │ │ │ ├── HostMessageBoxView.xaml.cs │ │ │ ├── MessageBoxView.xaml │ │ │ ├── MessageBoxView.xaml.cs │ │ │ ├── SelectTenantView.xaml │ │ │ ├── SelectTenantView.xaml.cs │ │ │ ├── SplashScreenView.xaml │ │ │ ├── SplashScreenView.xaml.cs │ │ │ ├── UserPanelView.xaml │ │ │ └── UserPanelView.xaml.cs │ │ ├── Tenants/ │ │ │ ├── TenantChangeFeaturesView.xaml │ │ │ ├── TenantChangeFeaturesView.xaml.cs │ │ │ ├── TenantDetailsView.xaml │ │ │ ├── TenantDetailsView.xaml.cs │ │ │ ├── TenantView.xaml │ │ │ └── TenantView.xaml.cs │ │ ├── Users/ │ │ │ ├── SelectedUserView.xaml │ │ │ ├── SelectedUserView.xaml.cs │ │ │ ├── UserChangePermissionView.xaml │ │ │ ├── UserChangePermissionView.xaml.cs │ │ │ ├── UserDetailsView.xaml │ │ │ ├── UserDetailsView.xaml.cs │ │ │ ├── UserView.xaml │ │ │ └── UserView.xaml.cs │ │ ├── Version/ │ │ │ ├── VersionManagerDetailsView.xaml │ │ │ ├── VersionManagerDetailsView.xaml.cs │ │ │ ├── VersionManagerView.xaml │ │ │ └── VersionManagerView.xaml.cs │ │ ├── ViewsExtensions.cs │ │ └── Visual/ │ │ ├── VisualView.xaml │ │ └── VisualView.xaml.cs │ └── nlog.config ├── AppFramework.Android/ │ ├── AppFramework.Android.csproj │ ├── Assets/ │ │ ├── AboutAssets.txt │ │ └── hello.json │ ├── Localization/ │ │ └── Locale.cs │ ├── MainActivity.cs │ ├── Properties/ │ │ ├── AndroidManifest.xml │ │ └── AssemblyInfo.cs │ ├── Renderers/ │ │ ├── BorderlessEditorRenderer.cs │ │ └── BorderlessEntryRenderer.cs │ └── Resources/ │ ├── AboutResources.txt │ ├── Resource.designer.cs │ ├── drawable/ │ │ └── splash_screen.xml │ ├── mipmap-anydpi-v26/ │ │ ├── icon.xml │ │ └── icon_round.xml │ └── values/ │ ├── colors.xml │ └── styles.xml ├── AppFramework.Application/ │ ├── AppFramework.Application.csproj │ ├── AppFrameworkAppServiceBase.cs │ ├── AppFrameworkApplicationModule.cs │ ├── Auditing/ │ │ ├── AuditLogAndUser.cs │ │ ├── AuditLogAppService.cs │ │ ├── EntityChangeAndUser.cs │ │ ├── ExpiredAndDeletedAuditLogBackupService.cs │ │ ├── ExpiredAuditLogDeleterWorker.cs │ │ ├── Exporting/ │ │ │ ├── AuditLogListExcelExporter.cs │ │ │ └── IAuditLogListExcelExporter.cs │ │ ├── INamespaceStripper.cs │ │ └── NamespaceStripper.cs │ ├── Authorization/ │ │ ├── AbpLoginResultTypeHelper.cs │ │ ├── Accounts/ │ │ │ └── AccountAppService.cs │ │ ├── LogInManager.cs │ │ ├── Permissions/ │ │ │ ├── PermissionAppService.cs │ │ │ └── PermissionManagerExtensions.cs │ │ ├── Roles/ │ │ │ └── RoleAppService.cs │ │ └── Users/ │ │ ├── Delegation/ │ │ │ └── UserDelegationAppService.cs │ │ ├── Exporting/ │ │ │ ├── IUserListExcelExporter.cs │ │ │ └── UserListExcelExporter.cs │ │ ├── Importing/ │ │ │ ├── Dto/ │ │ │ │ └── ImportUserDto.cs │ │ │ ├── IInvalidUserExporter.cs │ │ │ ├── IUserListExcelDataReader.cs │ │ │ ├── ImportUsersToExcelJob.cs │ │ │ ├── InvalidUserExporter.cs │ │ │ └── UserListExcelDataReader.cs │ │ ├── Password/ │ │ │ └── PasswordExpirationBackgroundWorker.cs │ │ ├── Profile/ │ │ │ ├── Cache/ │ │ │ │ ├── SmsVerificationCodeCacheExtensions.cs │ │ │ │ └── SmsVerificationCodeCacheItem.cs │ │ │ └── ProfileAppService.cs │ │ ├── UserAppService.cs │ │ ├── UserLinkAppService.cs │ │ └── UserLoginAppService.cs │ ├── Caching/ │ │ └── CachingAppService.cs │ ├── Chat/ │ │ ├── ChatAppService.cs │ │ └── Exporting/ │ │ ├── ChatMessageListExcelExporter.cs │ │ └── IChatMessageListExcelExporter.cs │ ├── Common/ │ │ └── CommonLookupAppService.cs │ ├── Configuration/ │ │ ├── Host/ │ │ │ └── HostSettingsAppService.cs │ │ ├── IUiCustomizationAppService.cs │ │ ├── SettingsAppServiceBase.cs │ │ ├── Tenants/ │ │ │ └── TenantSettingsAppService.cs │ │ └── UiCustomizationSettingsAppService.cs │ ├── CustomDtoMapper.cs │ ├── DashboardCustomization/ │ │ ├── DashboardCustomizationAppService.cs │ │ ├── Dto/ │ │ │ ├── AddNewPageInput.cs │ │ │ ├── AddNewPageOutput.cs │ │ │ ├── AddWidgetInput.cs │ │ │ ├── DashboardOutput.cs │ │ │ ├── DeletePageInput.cs │ │ │ ├── GetAvailableWidgetDefinitionsForPageInput.cs │ │ │ ├── GetDashboardInput.cs │ │ │ ├── RenamePageInput.cs │ │ │ ├── SavePageInput.cs │ │ │ ├── WidgetFilterOutput.cs │ │ │ └── WidgetOutput.cs │ │ └── IDashboardCustomizationAppService.cs │ ├── DataExporting/ │ │ └── Excel/ │ │ ├── EpPlus/ │ │ │ ├── EpPlusExcelExporterBase.cs │ │ │ └── EpPlusExcelImporterBase.cs │ │ └── NPOI/ │ │ ├── NpoiExcelExporterBase.cs │ │ └── NpoiExcelImporterBase.cs │ ├── Demo/ │ │ └── AbpDemoAppService.cs │ ├── DemoUiComponents/ │ │ └── DemoUiComponentsAppService.cs │ ├── DynamicEntityProperties/ │ │ ├── DynamicEntityPropertyAppService.cs │ │ ├── DynamicEntityPropertyDefinitionAppService.cs │ │ ├── DynamicEntityPropertyValueAppService.cs │ │ ├── DynamicPropertyAppService.cs │ │ └── DynamicPropertyValueAppService.cs │ ├── Editions/ │ │ ├── EditionAppService.cs │ │ ├── MoveTenantsToAnotherEditionJob.cs │ │ └── MoveTenantsToAnotherEditionJobArgs.cs │ ├── Friendships/ │ │ └── FriendshipAppService.cs │ ├── Gdpr/ │ │ ├── ChatUserCollectedDataProvider.cs │ │ ├── IUserCollectedDataProvider.cs │ │ ├── ProfilePictureUserCollectedDataProvider.cs │ │ ├── ProfileUserCollectedDataProvider.cs │ │ └── UserCollectedDataPrepareJob.cs │ ├── HealthChecks/ │ │ ├── AppFrameworkDbContextHealthCheck.cs │ │ ├── AppFrameworkDbContextUsersHealthCheck.cs │ │ └── CacheHealthCheck.cs │ ├── IO/ │ │ └── AppFileHelper.cs │ ├── Install/ │ │ ├── Dto/ │ │ │ ├── AppSettingsJsonDto.cs │ │ │ ├── CheckDatabaseOutput.cs │ │ │ └── InstallDto.cs │ │ ├── IInstallAppService.cs │ │ └── InstallAppService.cs │ ├── Localization/ │ │ ├── FamFamFamFlagsHelper.cs │ │ └── LanguageAppService.cs │ ├── Logging/ │ │ └── WebLogAppService.cs │ ├── MultiTenancy/ │ │ ├── Accounting/ │ │ │ ├── Dto/ │ │ │ │ ├── CreateInvoiceDto.cs │ │ │ │ └── InvoiceDto.cs │ │ │ ├── IInvoiceAppService.cs │ │ │ └── InvoiceAppService.cs │ │ ├── HostDashboard/ │ │ │ ├── HostDashboardAppService.cs │ │ │ ├── IIncomeStatisticsReporter.cs │ │ │ └── IncomeStatisticsReporter.cs │ │ ├── Payments/ │ │ │ ├── PayPalPaymentAppService.cs │ │ │ ├── PaymentAppService.cs │ │ │ └── StripePaymentAppService.cs │ │ ├── SubscriptionAppService.cs │ │ ├── TenantAppService.cs │ │ └── TenantRegistrationAppService.cs │ ├── Notifications/ │ │ └── NotificationAppService.cs │ ├── Organizations/ │ │ └── OrganizationUnitAppService.cs │ ├── Properties/ │ │ └── AssemblyInfo.cs │ ├── Security/ │ │ └── Recaptcha/ │ │ ├── IRecaptchaValidator.cs │ │ └── NullRecaptchaValidator.cs │ ├── Sessions/ │ │ └── SessionAppService.cs │ ├── Tenants/ │ │ └── Dashboard/ │ │ ├── DashboardRandomDataGenerator.cs │ │ └── TenantDashboardAppService.cs │ ├── Timing/ │ │ └── TimingAppService.cs │ ├── UiCustomization/ │ │ ├── IUiCustomizer.cs │ │ └── IUiThemeCustomizerFactory.cs │ ├── Url/ │ │ ├── IAppUrlService.cs │ │ └── NullAppUrlService.cs │ ├── Version/ │ │ └── AbpVersionsAppService.cs │ └── WebHooks/ │ ├── WebhookEventAppService.cs │ ├── WebhookSendAttemptAppService.cs │ └── WebhookSubscriptionAppService.cs ├── AppFramework.Application.Client/ │ ├── ApiClient/ │ │ ├── AbpApiClient.cs │ │ ├── AccessTokenManager.cs │ │ ├── ApiUrlConfig.cs │ │ ├── ApplicationContext.cs │ │ ├── AuthenticationHttpHandler.cs │ │ ├── DebugServerIpAddresses.cs │ │ ├── IAccessTokenManager.cs │ │ ├── IApplicationContext.cs │ │ ├── Models/ │ │ │ ├── AbpAuthenticateModel.cs │ │ │ └── AbpAuthenticateResultModel.cs │ │ ├── ModernHttpClientFactory.cs │ │ └── TenantInformation.cs │ ├── AppFramework.Application.Client.csproj │ ├── AppFrameworkClientModule.cs │ ├── Auditing/ │ │ └── AuditLogAppService.cs │ ├── Authorization/ │ │ ├── Accounts/ │ │ │ ├── ProxyAccountAppService.cs │ │ │ └── ProxyTokenAuthControllerService.cs │ │ ├── Permissions/ │ │ │ └── PermissionAppService.cs │ │ ├── Roles/ │ │ │ └── RoleAppService.cs │ │ └── Users/ │ │ ├── Delegation/ │ │ │ └── UserDelegationAppService.cs │ │ ├── Profile/ │ │ │ ├── ProxyProfileAppService.cs │ │ │ └── ProxyProfileControllerService.cs │ │ ├── ProxyUserAppService.cs │ │ ├── UserLinkAppService.cs │ │ └── UserLoginAppService.cs │ ├── Caching/ │ │ └── CachingAppService.cs │ ├── Chat/ │ │ ├── ChatAppService.cs │ │ └── ProxyChatControllerService.cs │ ├── Common/ │ │ └── ProxyCommonLookupAppService.cs │ ├── Configuration/ │ │ ├── AbpUserConfigurationDtoExtensions.cs │ │ ├── HostSettingsAppService.cs │ │ └── UserConfigurationService.cs │ ├── Demo/ │ │ └── AbpDemoAppService.cs │ ├── DynamicEntityProperties/ │ │ ├── DynamicEntityPropertyAppService.cs │ │ ├── DynamicEntityPropertyDefinitionAppService.cs │ │ ├── DynamicPropertyAppService.cs │ │ └── DynamicPropertyValueAppService.cs │ ├── Edition/ │ │ └── EditionAppService.cs │ ├── Extensions/ │ │ ├── AbpValidationExceptionExtensions.cs │ │ └── ErrorInfoExtensions.cs │ ├── Friendships/ │ │ └── FriendshipAppService.cs │ ├── Localization/ │ │ └── LanguageAppService.cs │ ├── MultiTenancy/ │ │ ├── HostDashboard/ │ │ │ └── HostDashboardAppService.cs │ │ ├── MultiTenancyConfig.cs │ │ └── ProxyTenantAppService.cs │ ├── Notifications/ │ │ └── NotificationAppService.cs │ ├── Organizations/ │ │ └── OrganizationUnitAppService.cs │ ├── ProxyAppServiceBase.cs │ ├── ProxyControllerBase.cs │ ├── Sessions/ │ │ └── ProxySessionAppService.cs │ ├── Tenants/ │ │ └── Dashboard/ │ │ └── TenantDashboardAppService.cs │ └── Version/ │ └── VersionsAppService.cs ├── AppFramework.Application.Shared/ │ ├── AppConsts.cs │ ├── AppFramework.Application.Shared.csproj │ ├── AppFrameworkSharedModule.cs │ ├── Auditing/ │ │ ├── Dto/ │ │ │ ├── AuditLogListDto.cs │ │ │ ├── EntityChangeDto.cs │ │ │ ├── EntityChangeListDto.cs │ │ │ ├── EntityPropertyChangeDto.cs │ │ │ ├── GetAuditLogsInput.cs │ │ │ └── GetEntityChangeInput.cs │ │ ├── IAuditLogAppService.cs │ │ └── IExpiredAndDeletedAuditLogBackupService.cs │ ├── Authorization/ │ │ ├── Accounts/ │ │ │ ├── Dto/ │ │ │ │ ├── ActivateEmailInput.cs │ │ │ │ ├── CurrentTenantInfoDto.cs │ │ │ │ ├── DelegatedImpersonateInput.cs │ │ │ │ ├── ImpersonateOutput.cs │ │ │ │ ├── ImpersonateTenantInput.cs │ │ │ │ ├── ImpersonateUserInput.cs │ │ │ │ ├── IsTenantAvailableInput.cs │ │ │ │ ├── IsTenantAvailableOutput.cs │ │ │ │ ├── RefreshTokenResult.cs │ │ │ │ ├── RegisterInput.cs │ │ │ │ ├── RegisterOutput.cs │ │ │ │ ├── ResetPasswordInput.cs │ │ │ │ ├── ResetPasswordOutput.cs │ │ │ │ ├── ResolveTenantInput.cs │ │ │ │ ├── SendEmailActivationLinkInput.cs │ │ │ │ ├── SendPasswordResetCodeInput.cs │ │ │ │ ├── SwitchToLinkedAccountInput.cs │ │ │ │ ├── SwitchToLinkedAccountOutput.cs │ │ │ │ └── TenantAvailabilityState.cs │ │ │ └── IAccountAppService.cs │ │ ├── Permissions/ │ │ │ ├── Dto/ │ │ │ │ ├── FlatPermissionDto.cs │ │ │ │ └── FlatPermissionWithLevelDto.cs │ │ │ └── IPermissionAppService.cs │ │ ├── Roles/ │ │ │ ├── Dto/ │ │ │ │ ├── CreateOrUpdateRoleInput.cs │ │ │ │ ├── GetRoleForEditOutput.cs │ │ │ │ ├── GetRolesInput.cs │ │ │ │ ├── RoleEditDto.cs │ │ │ │ └── RoleListDto.cs │ │ │ └── IRoleAppService.cs │ │ └── Users/ │ │ ├── Delegation/ │ │ │ ├── Dto/ │ │ │ │ ├── DelegateNewUserInput.cs │ │ │ │ ├── GetUserDelegationsInput.cs │ │ │ │ └── UserDelegationDto.cs │ │ │ └── IUserDelegationAppService.cs │ │ ├── Dto/ │ │ │ ├── ChangeUserLanguageDto.cs │ │ │ ├── CreateOrUpdateUserInput.cs │ │ │ ├── GetLinkedUsersInput.cs │ │ │ ├── GetLoginAttemptsInput.cs │ │ │ ├── GetUserForEditOutput.cs │ │ │ ├── GetUserPermissionsForEditOutput.cs │ │ │ ├── GetUsersInput.cs │ │ │ ├── GetUsersToExcelInput.cs │ │ │ ├── IGetLoginAttemptsInput.cs │ │ │ ├── IGetUsersInput.cs │ │ │ ├── ImportUsersFromExcelJobArgs.cs │ │ │ ├── LinkToUserInput.cs │ │ │ ├── LinkedUserDto.cs │ │ │ ├── UnlinkUserInput.cs │ │ │ ├── UpdateUserPermissionsInput.cs │ │ │ ├── UserEditDto.cs │ │ │ ├── UserListDto.cs │ │ │ ├── UserListRoleDto.cs │ │ │ ├── UserLoginAttemptDto.cs │ │ │ └── UserRoleDto.cs │ │ ├── IUserAppService.cs │ │ ├── IUserLinkAppService.cs │ │ ├── IUserLoginAppService.cs │ │ └── Profile/ │ │ ├── Dto/ │ │ │ ├── ChangePasswordInput.cs │ │ │ ├── CurrentUserProfileEditDto.cs │ │ │ ├── GetFriendProfilePictureInput.cs │ │ │ ├── GetPasswordComplexitySettingOutput.cs │ │ │ ├── GetProfilePictureOutput.cs │ │ │ ├── SendVerificationSmsInputDto.cs │ │ │ ├── UpdateGoogleAuthenticatorKeyOutput.cs │ │ │ ├── UpdateProfilePictureInput.cs │ │ │ ├── UploadFileOutput.cs │ │ │ ├── UploadProfilePictureOutput.cs │ │ │ └── VerifySmsCodeInputDto.cs │ │ └── IProfileAppService.cs │ ├── Caching/ │ │ ├── Dto/ │ │ │ └── CacheDto.cs │ │ └── ICachingAppService.cs │ ├── Chat/ │ │ ├── ChatUploadFileOutput.cs │ │ ├── Dto/ │ │ │ ├── ChatMessageDto.cs │ │ │ ├── ChatMessageExportDto.cs │ │ │ ├── ChatUserDto.cs │ │ │ ├── ChatUserWithMessagesDto.cs │ │ │ ├── GetUserChatFriendsWithSettingsOutput.cs │ │ │ ├── GetUserChatMessagesInput.cs │ │ │ └── MarkMessagesAsReadInput.cs │ │ └── IChatAppService.cs │ ├── Common/ │ │ ├── Dto/ │ │ │ ├── FindUsersInput.cs │ │ │ └── GetDefaultEditionNameOutput.cs │ │ ├── DtoSortingHelper.cs │ │ └── ICommonLookupAppService.cs │ ├── Configuration/ │ │ ├── Dto/ │ │ │ ├── EmailSettingsEditDto.cs │ │ │ ├── ExternalLoginProviderSettingsEditDto.cs │ │ │ ├── ExternalLoginSettingsDto.cs │ │ │ ├── ThemeFooterSettingsDto.cs │ │ │ ├── ThemeHeaderSettingsDto.cs │ │ │ ├── ThemeLayoutSettingsDto.cs │ │ │ ├── ThemeMenuSettingsDto.cs │ │ │ ├── ThemeSettingsDto.cs │ │ │ └── ThemeSubHeaderSettingsDto.cs │ │ ├── Host/ │ │ │ ├── Dto/ │ │ │ │ ├── GeneralSettingsEditDto.cs │ │ │ │ ├── HostBillingSettingsEditDto.cs │ │ │ │ ├── HostSettingsEditDto.cs │ │ │ │ ├── HostUserManagementSettingsEditDto.cs │ │ │ │ ├── OtherSettingsEditDto.cs │ │ │ │ ├── SecuritySettingsEditDto.cs │ │ │ │ ├── SendTestEmailInput.cs │ │ │ │ ├── SessionTimeOutSettingsEditDto.cs │ │ │ │ ├── TenantManagementSettingsEditDto.cs │ │ │ │ ├── TwoFactorLoginSettingsEditDto.cs │ │ │ │ ├── UserLockOutSettingsEditDto.cs │ │ │ │ └── UserPasswordSettingsEditDto.cs │ │ │ └── IHostSettingsAppService.cs │ │ ├── IExternalLoginOptionsCacheManager.cs │ │ ├── NullExternalLoginOptionsCacheManager.cs │ │ └── Tenants/ │ │ ├── Dto/ │ │ │ ├── LdapSettingsEditDto.cs │ │ │ ├── TenantBillingSettingsEditDto.cs │ │ │ ├── TenantEmailSettingsEditDto.cs │ │ │ ├── TenantOtherSettingsEditDto.cs │ │ │ ├── TenantSettingsEditDto.cs │ │ │ └── TenantUserManagementSettingsEditDto.cs │ │ └── ITenantSettingsAppService.cs │ ├── Demo/ │ │ ├── Dtos/ │ │ │ ├── AbpDemoDto.cs │ │ │ └── GetAllAbpDemoInput.cs │ │ └── IAbpDemoAppService.cs │ ├── DemoUiComponents/ │ │ ├── Dto/ │ │ │ ├── DateToStringOutput.cs │ │ │ ├── StringOutput.cs │ │ │ └── UploadFileOutput.cs │ │ └── IDemoUIComponentAppService.cs │ ├── Dto/ │ │ ├── FileDto.cs │ │ ├── PagedAndFilteredInputDto.cs │ │ ├── PagedAndSortedInputDto.cs │ │ ├── PagedInputDto.cs │ │ ├── PagedSortedAndFilteredInputDto.cs │ │ └── VersionDto.cs │ ├── DynamicEntityProperties/ │ │ ├── Dto/ │ │ │ ├── DynamicEntityPropertyDto.cs │ │ │ ├── DynamicEntityPropertyGetAllInput.cs │ │ │ ├── DynamicEntityPropertyValueDto.cs │ │ │ ├── DynamicPropertyDto.cs │ │ │ ├── DynamicPropertyValueDto.cs │ │ │ └── GetAllEntitiesHasDynamicPropertyOutput.cs │ │ ├── IDynamicEntityPropertyAppService.cs │ │ ├── IDynamicEntityPropertyDefinitionAppService.cs │ │ ├── IDynamicEntityPropertyValueAppService.cs │ │ ├── IDynamicPropertyAppService.cs │ │ └── IDynamicPropertyValueAppService.cs │ ├── DynamicEntityPropertyValues/ │ │ └── Dto/ │ │ ├── CleanValuesInput.cs │ │ ├── GetAllDynamicEntityPropertyValuesInput.cs │ │ ├── GetAllDynamicEntityPropertyValuesOutput.cs │ │ ├── GetAllInput.cs │ │ └── InsertOrUpdateAllValuesInput.cs │ ├── Editions/ │ │ ├── Dto/ │ │ │ ├── CreateEditionDto.cs │ │ │ ├── CreateOrUpdateEditionDto.cs │ │ │ ├── EditionCreateDto.cs │ │ │ ├── EditionEditDto.cs │ │ │ ├── EditionListDto.cs │ │ │ ├── EditionSelectDto.cs │ │ │ ├── EditionWithFeaturesDto.cs │ │ │ ├── FeatureInputTypeDto.cs │ │ │ ├── FlatFeatureDto.cs │ │ │ ├── FlatFeatureSelectDto.cs │ │ │ ├── GetEditionEditOutput.cs │ │ │ ├── LocalizableComboboxItemDto.cs │ │ │ ├── LocalizableComboboxItemSourceDto.cs │ │ │ ├── MoveTenantsToAnotherEditionDto.cs │ │ │ ├── SubscribableEditionComboboxItemDto.cs │ │ │ └── UpdateEditionDto.cs │ │ └── IEditionAppService.cs │ ├── Friendships/ │ │ ├── Dto/ │ │ │ ├── AcceptFriendshipRequestInput.cs │ │ │ ├── BlockUserInput.cs │ │ │ ├── CreateFriendshipRequestByUserNameInput.cs │ │ │ ├── CreateFriendshipRequestInput.cs │ │ │ ├── FriendshipDto.cs │ │ │ ├── RemoveFriendInput.cs │ │ │ └── UnblockUserInput.cs │ │ └── IFriendshipAppService.cs │ ├── Localization/ │ │ ├── Dto/ │ │ │ ├── ApplicationLanguageEditDto.cs │ │ │ ├── ApplicationLanguageListDto.cs │ │ │ ├── CreateOrUpdateLanguageInput.cs │ │ │ ├── GetLanguageForEditOutput.cs │ │ │ ├── GetLanguageTextsInput.cs │ │ │ ├── GetLanguagesOutput.cs │ │ │ ├── LanguageTextListDto.cs │ │ │ ├── SetDefaultLanguageInput.cs │ │ │ └── UpdateLanguageTextInput.cs │ │ └── ILanguageAppService.cs │ ├── Logging/ │ │ ├── Dto/ │ │ │ └── GetLatestWebLogsOutput.cs │ │ └── IWebLogAppService.cs │ ├── MultiTenancy/ │ │ ├── Dto/ │ │ │ ├── CreateTenantInput.cs │ │ │ ├── EditionsSelectOutput.cs │ │ │ ├── GetTenantFeaturesEditOutput.cs │ │ │ ├── GetTenantsInput.cs │ │ │ ├── PaymentInfoInput.cs │ │ │ ├── RegisterTenantInput.cs │ │ │ ├── RegisterTenantOutput.cs │ │ │ ├── TenantEditDto.cs │ │ │ ├── TenantListDto.cs │ │ │ └── UpdateTenantFeaturesInput.cs │ │ ├── HostDashboard/ │ │ │ ├── Dto/ │ │ │ │ ├── ChartDateInterval.cs │ │ │ │ ├── DashboardInputBase.cs │ │ │ │ ├── ExpiringTenant.cs │ │ │ │ ├── GetDashboardDataInput.cs │ │ │ │ ├── GetEditionStatisticsInput.cs │ │ │ │ ├── GetEditionTenantStatisticsInput.cs │ │ │ │ ├── GetEditionTenantStatisticsOutput.cs │ │ │ │ ├── GetExpiringTenantsOutput.cs │ │ │ │ ├── GetIncomeStatisticsDataInput.cs │ │ │ │ ├── GetIncomeStatisticsDataOutput.cs │ │ │ │ ├── GetRecentTenantsOutput.cs │ │ │ │ ├── GetTopStatsInput.cs │ │ │ │ ├── IncomeStastistic.cs │ │ │ │ ├── RecentTenant.cs │ │ │ │ ├── TenantEdition.cs │ │ │ │ └── TopStatsData.cs │ │ │ └── IHostDashboardAppService.cs │ │ ├── ISubscriptionAppService.cs │ │ ├── ITenantAppService.cs │ │ ├── ITenantRegistrationAppService.cs │ │ └── Payments/ │ │ ├── Dto/ │ │ │ ├── CancelPaymentDto.cs │ │ │ ├── CreatePaymentDto.cs │ │ │ ├── GetActiveGatewaysInput.cs │ │ │ ├── GetPaymentHistoryInput.cs │ │ │ ├── PaymentInfoDto.cs │ │ │ ├── StripePaymentResultInput.cs │ │ │ ├── SubscriptionPaymentDto.cs │ │ │ └── SubscriptionPaymentListDto.cs │ │ ├── IPaymentAppService.cs │ │ ├── PayPal/ │ │ │ ├── Dto/ │ │ │ │ └── PayPalConfigurationDto.cs │ │ │ └── IPayPalPaymentAppService.cs │ │ └── Stripe/ │ │ ├── Dto/ │ │ │ ├── StripeConfigurationDto.cs │ │ │ ├── StripeConfirmPaymentInput.cs │ │ │ ├── StripeCreatePaymentSessionInput.cs │ │ │ ├── StripeGetPaymentInput.cs │ │ │ └── StripePaymentResultOutput.cs │ │ └── IStripePaymentAppService.cs │ ├── Notifications/ │ │ ├── Dto/ │ │ │ ├── DeleteAllUserNotificationsInput.cs │ │ │ ├── GetNotificationSettingsOutput.cs │ │ │ ├── GetNotificationsOutput.cs │ │ │ ├── GetUserNotificationsInput.cs │ │ │ ├── NotificationSubscriptionDto.cs │ │ │ ├── NotificationSubscriptionWithDisplayNameDto.cs │ │ │ ├── SetNotificationAsReadOutput.cs │ │ │ └── UpdateNotificationSettingsInput.cs │ │ └── INotificationAppService.cs │ ├── Organizations/ │ │ ├── Dto/ │ │ │ ├── CreateOrganizationUnitInput.cs │ │ │ ├── FindOrganizationUnitRolesInput.cs │ │ │ ├── FindOrganizationUnitUsersInput.cs │ │ │ ├── GetOrganizationUnitRolesInput.cs │ │ │ ├── GetOrganizationUnitUsersInput.cs │ │ │ ├── MoveOrganizationUnitInput.cs │ │ │ ├── OrganizationUnitDto.cs │ │ │ ├── OrganizationUnitRoleListDto.cs │ │ │ ├── OrganizationUnitUserListDto.cs │ │ │ ├── RoleToOrganizationUnitInput.cs │ │ │ ├── RolesToOrganizationUnitInput.cs │ │ │ ├── UpdateOrganizationUnitInput.cs │ │ │ ├── UserToOrganizationUnitInput.cs │ │ │ └── UsersToOrganizationUnitInput.cs │ │ └── IOrganizationUnitAppService.cs │ ├── Sessions/ │ │ ├── Dto/ │ │ │ ├── ApplicationInfoDto.cs │ │ │ ├── EditionInfoDto.cs │ │ │ ├── GetCurrentLoginInformationsOutput.cs │ │ │ ├── SubscriptionPaymentInfoDto.cs │ │ │ ├── TenantLoginInfoDto.cs │ │ │ ├── UpdateUserSignInTokenOutput.cs │ │ │ └── UserLoginInfoDto.cs │ │ └── ISessionAppService.cs │ ├── Tenants/ │ │ └── Dashboard/ │ │ ├── Dto/ │ │ │ ├── GetDailySalesOutput.cs │ │ │ ├── GetDashboardDataInput.cs │ │ │ ├── GetDashboardDataOutput.cs │ │ │ ├── GetGeneralStatsOutput.cs │ │ │ ├── GetMemberActivityOutput.cs │ │ │ ├── GetProfitShareOutput.cs │ │ │ ├── GetRegionalStatsOutput.cs │ │ │ ├── GetSalesSummaryInput.cs │ │ │ ├── GetSalesSummaryOutput.cs │ │ │ ├── GetTopStatsOutput.cs │ │ │ ├── MemberActivity.cs │ │ │ ├── RegionalStatCountry.cs │ │ │ ├── SalesSummaryData.cs │ │ │ └── SalesSummaryDatePeriod.cs │ │ └── ITenantDashboardAppService.cs │ ├── Timing/ │ │ ├── Dto/ │ │ │ ├── GetTimezoneComboboxItemsInput.cs │ │ │ └── GetTimezonesInput.cs │ │ └── ITimingAppService.cs │ ├── UiCustomization/ │ │ └── Dto/ │ │ └── UiCustomizationSettingsDto.cs │ ├── Version/ │ │ ├── Dtos/ │ │ │ ├── AbpVersionDto.cs │ │ │ ├── CheckVersionInput.cs │ │ │ ├── CreateOrEditAbpVersionDto.cs │ │ │ ├── GetAllAbpVersionsInput.cs │ │ │ ├── GetAllForLookupTableInput.cs │ │ │ └── UpdateFileOutput.cs │ │ └── IAbpVersionsAppService.cs │ └── WebHooks/ │ ├── Dto/ │ │ ├── ActivateWebhookSubscriptionInput.cs │ │ ├── GetAllAvailableWebhooksOutput.cs │ │ ├── GetAllSendAttemptsInput.cs │ │ ├── GetAllSendAttemptsOfWebhookEventInput.cs │ │ ├── GetAllSendAttemptsOfWebhookEventOutput.cs │ │ ├── GetAllSendAttemptsOutput.cs │ │ └── GetAllSubscriptionsOutput.cs │ ├── IWebhookAttemptAppService.cs │ ├── IWebhookEventAppService.cs │ └── IWebhookSubscriptionAppService.cs ├── AppFramework.Core.Shared/ │ ├── AppFramework.Core.Shared.csproj │ ├── AppFrameworkConsts.cs │ ├── AppFrameworkCoreSharedModule.cs │ ├── AppFrameworkDashboardCustomizationConst.cs │ ├── Authentication/ │ │ ├── FacebookExternalLoginProviderSettings.cs │ │ ├── GoogleExternalLoginProviderSettings.cs │ │ ├── JsonClaimMapDto.cs │ │ ├── MicrosoftExternalLoginProviderSettings.cs │ │ ├── OpenIdConnectExternalLoginProviderSettings.cs │ │ ├── TwitterExternalLoginProviderSettings.cs │ │ └── WsFederationExternalLoginProviderSettings.cs │ ├── Authorization/ │ │ ├── Roles/ │ │ │ └── StaticRoleNames.cs │ │ └── Users/ │ │ └── UserConsts.cs │ ├── Chat/ │ │ ├── ChatMessageReadState.cs │ │ └── ChatSide.cs │ ├── Editions/ │ │ └── EditionPaymentType.cs │ ├── Friendships/ │ │ └── FriendshipState.cs │ ├── MultiTenancy/ │ │ ├── Payments/ │ │ │ ├── CreatePaymentResponse.cs │ │ │ ├── ExecutePaymentResponse.cs │ │ │ ├── PaymentGatewayModel.cs │ │ │ ├── PaymentPeriodType.cs │ │ │ ├── SubscriptionPaymentGatewayType.cs │ │ │ ├── SubscriptionPaymentStatus.cs │ │ │ ├── SubscriptionPaymentType.cs │ │ │ ├── SubscriptionPaymentTypeExtensions.cs │ │ │ └── SubscriptionStartType.cs │ │ └── TenantConsts.cs │ ├── Notifications/ │ │ └── AppNotificationNames.cs │ ├── Security/ │ │ └── PasswordComplexitySetting.cs │ ├── Storage/ │ │ └── BinaryObjectConsts.cs │ ├── Validation/ │ │ └── ValidationHelper.cs │ ├── Version/ │ │ └── AbpVersionConsts.cs │ └── Webhooks/ │ └── AppWebHookNames.cs ├── AppFramework.Mobile/ │ ├── App.xaml │ ├── App.xaml.cs │ ├── AppFramework.Shared.csproj │ ├── AppSettings.cs │ ├── Assets/ │ │ └── AssetsHelper.cs │ ├── Extensions/ │ │ ├── Behaviors/ │ │ │ ├── ActionCollection.cs │ │ │ ├── BehaviorBase.cs │ │ │ ├── BindableObjectCollection.cs │ │ │ ├── ChatMessageListViewBehavior.cs │ │ │ ├── EventHandlerBehavior.cs │ │ │ ├── IAction.cs │ │ │ ├── InvokeCommandAction.cs │ │ │ └── OnBackPressedHandler.cs │ │ ├── Converters/ │ │ │ ├── BackgroundColorConverter.cs │ │ │ ├── BoolToYesNoConverter.cs │ │ │ ├── ByteToImageConverter.cs │ │ │ ├── DatetimeConverter.cs │ │ │ ├── ImageSourceConverter.cs │ │ │ ├── IndentConverter.cs │ │ │ ├── IntToVisibilityConverter.cs │ │ │ ├── InverseBooleanConverter.cs │ │ │ ├── StringFormatConverter.cs │ │ │ ├── StringToBadgeIconConverter.cs │ │ │ ├── UrlToImageConverter.cs │ │ │ └── UserPhotoConverter.cs │ │ ├── DateTimeExtensions.cs │ │ ├── DialogExtensions.cs │ │ ├── LocalizationKeys.cs │ │ ├── MarkupExtensions/ │ │ │ ├── HasPermissionExtension.cs │ │ │ ├── ImageSourceExtension.cs │ │ │ └── TranslateExtension.cs │ │ ├── ThemePaletteExtensions.cs │ │ ├── Threading/ │ │ │ ├── AsyncRuner.cs │ │ │ ├── ExceptionHandler.cs │ │ │ └── WebRequest.cs │ │ └── UserLocalizationConfigDtoExtensions.cs │ ├── Localization/ │ │ ├── LocalTranslationHelper.cs │ │ ├── LocalizationResourceManager.cs │ │ └── Resources/ │ │ ├── LocalTranslation.Designer.cs │ │ ├── LocalTranslation.resx │ │ ├── LocalTranslation.zh-Hans.Designer.cs │ │ └── LocalTranslation.zh-Hans.resx │ ├── Models/ │ │ ├── Auditing/ │ │ │ └── AuditLogListModel.cs │ │ ├── Auth/ │ │ │ ├── AuthTokenPersistanceModel.cs │ │ │ ├── AuthenticateResultPersistanceModel.cs │ │ │ ├── CurrentLoginInformationPersistanceModel.cs │ │ │ ├── TenantInformationPersistanceModel.cs │ │ │ ├── TenantLoginInfoPersistanceModel.cs │ │ │ └── UserLoginInfoPersistanceModel.cs │ │ ├── Chat/ │ │ │ ├── ChatMessageModel.cs │ │ │ └── FriendModel.cs │ │ ├── Configuration/ │ │ │ ├── EmailSettingsEditModel.cs │ │ │ ├── ExternalLoginProviderSettingsEditModel.cs │ │ │ ├── GeneralSettingsEditModel.cs │ │ │ ├── HostBillingSettingsEditModel.cs │ │ │ ├── HostSettingsEditModel.cs │ │ │ ├── HostUserManagementSettingsEditModel.cs │ │ │ ├── OtherSettingsEditModel.cs │ │ │ ├── SecuritySettingsEditModel.cs │ │ │ ├── SessionTimeOutSettingsEditModel.cs │ │ │ ├── TenantManagementSettingsEditModel.cs │ │ │ ├── TwoFactorLoginSettingsEditModel.cs │ │ │ ├── UserLockOutSettingsEditModel.cs │ │ │ └── UserPasswordSettingsEditModel.cs │ │ ├── Dashboard/ │ │ │ ├── AreaSeriesChart3DModel.cs │ │ │ ├── DoughnutChartPopulations.cs │ │ │ └── TopStatusItem.cs │ │ ├── DynamicProperty/ │ │ │ └── DynamicPropertyModel.cs │ │ ├── Edition/ │ │ │ ├── EditionCreateModel.cs │ │ │ ├── EditionListModel.cs │ │ │ └── FlatFeatureModel.cs │ │ ├── EntityObject.cs │ │ ├── Language/ │ │ │ ├── Language.cs │ │ │ ├── LanguageListModel.cs │ │ │ └── LanguageTextListModel.cs │ │ ├── Navigation/ │ │ │ └── NavigationItem.cs │ │ ├── Organizations/ │ │ │ ├── CreateOrganizationUnitModel.cs │ │ │ ├── OrganizationListModel.cs │ │ │ └── OrganizationUnitModel.cs │ │ ├── Roles/ │ │ │ ├── ChooseItem.cs │ │ │ ├── PermissionModel.cs │ │ │ ├── RoleEditModel.cs │ │ │ ├── RoleListModel.cs │ │ │ └── UserRoleModel.cs │ │ ├── SharedMapper.cs │ │ ├── Tenants/ │ │ │ └── TenantListModel.cs │ │ ├── Update/ │ │ │ └── VersionListModel.cs │ │ └── Users/ │ │ ├── UserCreateOrUpdateModel.cs │ │ ├── UserEditModel.cs │ │ ├── UserForEditModel.cs │ │ ├── UserListModel.cs │ │ └── UserLoginInfoModel.cs │ ├── Services/ │ │ ├── Account/ │ │ │ ├── AccountService.cs │ │ │ ├── AppConfigurationManager.cs │ │ │ ├── ApplicationService.cs │ │ │ ├── IAccountService.cs │ │ │ └── IApplicationService.cs │ │ ├── Datapager/ │ │ │ ├── DataPagerService.cs │ │ │ └── IDataPagerService.cs │ │ ├── Features/ │ │ │ ├── FeaturesService.cs │ │ │ └── IFeaturesService.cs │ │ ├── Friend/ │ │ │ ├── FriendChatService.cs │ │ │ └── IFriendChatService.cs │ │ ├── Localization/ │ │ │ ├── ILocaleCulture.cs │ │ │ ├── Local.cs │ │ │ ├── LocalizationSource.cs │ │ │ └── PlatformCulture.cs │ │ ├── Mapper/ │ │ │ └── AppMapper.cs │ │ ├── Messenger/ │ │ │ ├── AppMessengerKeys.cs │ │ │ ├── IMessenger.cs │ │ │ ├── IMessengerExtensions.cs │ │ │ ├── IWeakAction.cs │ │ │ ├── Messenger.cs │ │ │ ├── WeakAction.cs │ │ │ ├── WeakActionExtensions.cs │ │ │ └── WeakAction{T}.cs │ │ ├── Navigation/ │ │ │ ├── AppRegions.cs │ │ │ ├── INavigationMenuService.cs │ │ │ ├── IRegionNavigateService.cs │ │ │ ├── NavigationMenuService.cs │ │ │ └── RegionNavigateService.cs │ │ ├── Permission/ │ │ │ ├── AppPermissions.cs │ │ │ ├── IPermissionService.cs │ │ │ ├── IPermissionTreesService.cs │ │ │ ├── IPorxyCommandService.cs │ │ │ ├── PermissionHelper.cs │ │ │ ├── PermissionItem.cs │ │ │ ├── PermissionService.cs │ │ │ ├── PermissionTreesService.cs │ │ │ └── PorxyCommandService.cs │ │ ├── Session/ │ │ │ ├── DialogHelper.cs │ │ │ ├── IUserDialogService.cs │ │ │ └── UserDialogService.cs │ │ └── Storage/ │ │ ├── AccountStorageService.cs │ │ ├── DataStorageKey.cs │ │ ├── DataStorageService.cs │ │ ├── IAccountStorageService.cs │ │ ├── IDataStorageService.cs │ │ └── TypeHelperExtended.cs │ ├── SharedConsts.cs │ ├── Startup.cs │ ├── Themes/ │ │ ├── Controls/ │ │ │ ├── BorderlessEditor.cs │ │ │ ├── BorderlessEntry.cs │ │ │ ├── CalenderDatePicker.cs │ │ │ ├── ControlSetting.cs │ │ │ ├── CustomShadowFrame.cs │ │ │ ├── ExtendedDatePicker.cs │ │ │ ├── HideableToolbarItem.cs │ │ │ ├── ParallaxScrollView.cs │ │ │ └── XamlCard.cs │ │ ├── DarkTheme.xaml │ │ ├── DarkTheme.xaml.cs │ │ ├── LightTheme.xaml │ │ ├── LightTheme.xaml.cs │ │ └── Styles/ │ │ ├── AvatarViewStyles.xaml │ │ ├── AvatarViewStyles.xaml.cs │ │ ├── BorderStyles.xaml │ │ ├── BorderStyles.xaml.cs │ │ ├── BoxViewStyles.xaml │ │ ├── BoxViewStyles.xaml.cs │ │ ├── ButtonStyles.xaml │ │ ├── ButtonStyles.xaml.cs │ │ ├── CheckBoxStyles.xaml │ │ ├── CheckBoxStyles.xaml.cs │ │ ├── Colors.xaml │ │ ├── Colors.xaml.cs │ │ ├── ComboBoxStyles.xaml │ │ ├── ComboBoxStyles.xaml.cs │ │ ├── EditorStyles.xaml │ │ ├── EditorStyles.xaml.cs │ │ ├── EntryStyles.xaml │ │ ├── EntryStyles.xaml.cs │ │ ├── FontIcons.xaml │ │ ├── FontIcons.xaml.cs │ │ ├── FrameStyles.xaml │ │ ├── FrameStyles.xaml.cs │ │ ├── GradientViewStyles.xaml │ │ ├── GradientViewStyles.xaml.cs │ │ ├── LabelStyles.xaml │ │ ├── LabelStyles.xaml.cs │ │ ├── ListViewStyles.xaml │ │ ├── ListViewStyles.xaml.cs │ │ ├── RadioButtonStyles.xaml │ │ ├── RadioButtonStyles.xaml.cs │ │ ├── SegmentedControlStyles.xaml │ │ ├── SegmentedControlStyles.xaml.cs │ │ ├── TextInputLayoutStyles.xaml │ │ └── TextInputLayoutStyles.xaml.cs │ ├── Validations/ │ │ ├── EditionValidator.cs │ │ ├── GlobalValidator.cs │ │ ├── IGlobalValidator.cs │ │ ├── OrganizationUnitValidator.cs │ │ ├── SettingsValidator.cs │ │ ├── TenantValidator.cs │ │ ├── UserValidator.cs │ │ ├── ValidatorExtensions.cs │ │ └── VersionValidator.cs │ ├── ViewModels/ │ │ ├── Account/ │ │ │ ├── ChangePasswordViewModel.cs │ │ │ ├── EmailActivationViewModel.cs │ │ │ ├── ForgotPasswordViewModel.cs │ │ │ ├── MyProfileViewModel.cs │ │ │ ├── ProfilePictureViewModel.cs │ │ │ ├── SendTwoFactorCodeViewModel.cs │ │ │ └── SettingsViewModel.cs │ │ ├── Auditlogs/ │ │ │ └── AuditLogViewModel.cs │ │ ├── Chat/ │ │ │ ├── FriendsChatViewModel.cs │ │ │ └── FriendsViewModel.cs │ │ ├── Dashboard/ │ │ │ └── DashboardViewModel.cs │ │ ├── DynamicProperty/ │ │ │ ├── DynamicPropertyDetailsViewModel.cs │ │ │ └── DynamicPropertyViewModel.cs │ │ ├── Edition/ │ │ │ ├── EditionDetailsViewModel.cs │ │ │ └── EditionViewModel.cs │ │ ├── InitialScreenViewModel.cs │ │ ├── Language/ │ │ │ ├── LanguageDetailsViewModel.cs │ │ │ └── LanguageViewModel.cs │ │ ├── LoginViewModel.cs │ │ ├── MainViewModel.cs │ │ ├── MessageBoxViewModel.cs │ │ ├── Organizations/ │ │ │ ├── AddRolesViewModel.cs │ │ │ ├── AddUsersViewModel.cs │ │ │ ├── OrganizationDetailsViewModel.cs │ │ │ └── OrganizationViewModel.cs │ │ ├── Roles/ │ │ │ ├── RoleDetailsViewModel.cs │ │ │ └── RoleViewModel.cs │ │ ├── Shared/ │ │ │ ├── DialogViewModel.cs │ │ │ ├── NavigationDetailViewModel.cs │ │ │ ├── NavigationMasterViewModel.cs │ │ │ ├── NavigationViewModel.cs │ │ │ ├── RegionViewModel.cs │ │ │ └── ViewModelBase.cs │ │ ├── Tenants/ │ │ │ ├── TenantDetailsViewModel.cs │ │ │ └── TenantViewModel.cs │ │ └── User/ │ │ ├── UserDetailsViewModel.cs │ │ └── UserViewModel.cs │ └── Views/ │ ├── Account/ │ │ ├── ChangePasswordView.xaml │ │ ├── ChangePasswordView.xaml.cs │ │ ├── EmailActivationView.xaml │ │ ├── EmailActivationView.xaml.cs │ │ ├── ForgotPasswordView.xaml │ │ ├── ForgotPasswordView.xaml.cs │ │ ├── MyProfileView.xaml │ │ ├── MyProfileView.xaml.cs │ │ ├── ProfilePictureView.xaml │ │ ├── ProfilePictureView.xaml.cs │ │ ├── SendTwoFactorCodeView.xaml │ │ ├── SendTwoFactorCodeView.xaml.cs │ │ ├── SettingsView.xaml │ │ └── SettingsView.xaml.cs │ ├── AppViews.cs │ ├── Auditlog/ │ │ ├── AuditLogDetailsView.xaml │ │ ├── AuditLogDetailsView.xaml.cs │ │ ├── AuditLogView.xaml │ │ └── AuditLogView.xaml.cs │ ├── Chat/ │ │ ├── FriendsChatView.xaml │ │ ├── FriendsChatView.xaml.cs │ │ ├── FriendsView.xaml │ │ ├── FriendsView.xaml.cs │ │ ├── Selectors/ │ │ │ └── MessageDataTemplateSelector.cs │ │ └── Templates/ │ │ ├── ReceiverImageTemplate.xaml │ │ ├── ReceiverImageTemplate.xaml.cs │ │ ├── ReceiverTextTemplate.xaml │ │ ├── ReceiverTextTemplate.xaml.cs │ │ ├── SenderImageTemplate.xaml │ │ ├── SenderImageTemplate.xaml.cs │ │ ├── SenderTextTemplate.xaml │ │ └── SenderTextTemplate.xaml.cs │ ├── Dashboard/ │ │ ├── DashboardView.xaml │ │ └── DashboardView.xaml.cs │ ├── DynamicProperty/ │ │ ├── DynamicPropertyDetailsView.xaml │ │ ├── DynamicPropertyDetailsView.xaml.cs │ │ ├── DynamicPropertyView.xaml │ │ └── DynamicPropertyView.xaml.cs │ ├── Edition/ │ │ ├── EditionDetailsView.xaml │ │ ├── EditionDetailsView.xaml.cs │ │ ├── EditionView.xaml │ │ └── EditionView.xaml.cs │ ├── Language/ │ │ ├── LanguageDetailsView.xaml │ │ ├── LanguageDetailsView.xaml.cs │ │ ├── LanguageView.xaml │ │ └── LanguageView.xaml.cs │ ├── LoginView.xaml │ ├── LoginView.xaml.cs │ ├── MainView.xaml │ ├── MainView.xaml.cs │ ├── Organization/ │ │ ├── AddRolesView.xaml │ │ ├── AddRolesView.xaml.cs │ │ ├── AddUsersView.xaml │ │ ├── AddUsersView.xaml.cs │ │ ├── CreateOrganizationView.xaml │ │ ├── CreateOrganizationView.xaml.cs │ │ ├── OrganizationDetailsView.xaml │ │ ├── OrganizationDetailsView.xaml.cs │ │ ├── OrganizationView.xaml │ │ └── OrganizationView.xaml.cs │ ├── Role/ │ │ ├── RoleDetailsView.xaml │ │ ├── RoleDetailsView.xaml.cs │ │ ├── RoleView.xaml │ │ └── RoleView.xaml.cs │ ├── Shared/ │ │ ├── InitialScreenView.xaml │ │ ├── InitialScreenView.xaml.cs │ │ ├── MessageBoxView.xaml │ │ ├── MessageBoxView.xaml.cs │ │ ├── SkinView.xaml │ │ └── SkinView.xaml.cs │ ├── Tenant/ │ │ ├── TenantDetailsView.xaml │ │ ├── TenantDetailsView.xaml.cs │ │ ├── TenantView.xaml │ │ └── TenantView.xaml.cs │ └── User/ │ ├── SelectionUserOrRoleView.xaml │ ├── SelectionUserOrRoleView.xaml.cs │ ├── UserDetailsView.xaml │ ├── UserDetailsView.xaml.cs │ ├── UserView.xaml │ └── UserView.xaml.cs ├── AppFramework.Shared/ │ ├── AppFramework.Shared.csproj │ ├── Consts/ │ │ ├── AppLocalizationKeys.cs │ │ ├── AppRegions.cs │ │ ├── AppSharedConsts.cs │ │ └── AppViews.cs │ ├── Converters/ │ │ ├── BoolToBackgroundConverter.cs │ │ ├── BoolToVisibilityConverter.cs │ │ ├── BoolToYesNoStrConverter.cs │ │ ├── ByteToImageConverter.cs │ │ ├── DateTimeToStringConverter.cs │ │ ├── ImageConverter.cs │ │ ├── InverseBoolToBackgroundConverter.cs │ │ ├── InverseBoolToVisibilityConverter.cs │ │ ├── InverseBoolToYesNoStrConverter.cs │ │ ├── InverseBooleanConverter.cs │ │ ├── NotificationToMessageConverter.cs │ │ ├── StateToVisibilityConverter.cs │ │ ├── UnreadMessageCountToVisibilityConverter.cs │ │ └── UrlToImageConverter.cs │ ├── Extensions/ │ │ ├── AppLogs.cs │ │ ├── DateTimeExtensions.cs │ │ ├── DialogExtensions.cs │ │ ├── DialogHelper.cs │ │ ├── HasPermissionExtension.cs │ │ ├── IniFileHelper.cs │ │ ├── LocalTranslationHelper.cs │ │ ├── Threading/ │ │ │ ├── AsyncRuner.cs │ │ │ ├── ExceptionHandler.cs │ │ │ ├── WebRequest.cs │ │ │ └── WebRequestExtensions.cs │ │ └── TranslateExtension.cs │ ├── Models/ │ │ ├── Auth/ │ │ │ ├── AuthTokenPersistanceModel.cs │ │ │ ├── AuthenticateResultPersistanceModel.cs │ │ │ ├── CurrentLoginInformationPersistanceModel.cs │ │ │ ├── TenantInformationPersistanceModel.cs │ │ │ ├── TenantLoginInfoPersistanceModel.cs │ │ │ └── UserLoginInfoPersistanceModel.cs │ │ ├── Configuration/ │ │ │ ├── EmailSettingsEditModel.cs │ │ │ ├── ExternalLoginProviderSettingsEditModel.cs │ │ │ ├── GeneralSettingsEditModel.cs │ │ │ ├── HostBillingSettingsEditModel.cs │ │ │ ├── HostSettingsEditModel.cs │ │ │ ├── HostUserManagementSettingsEditModel.cs │ │ │ ├── OtherSettingsEditModel.cs │ │ │ ├── SecuritySettingsEditModel.cs │ │ │ ├── SessionTimeOutSettingsEditModel.cs │ │ │ ├── TenantManagementSettingsEditModel.cs │ │ │ ├── TwoFactorLoginSettingsEditModel.cs │ │ │ ├── UserLockOutSettingsEditModel.cs │ │ │ └── UserPasswordSettingsEditModel.cs │ │ ├── EntityObject.cs │ │ ├── Navigation/ │ │ │ └── NavigationItem.cs │ │ └── SharedModuleMapper.cs │ ├── Services/ │ │ ├── App/ │ │ │ ├── IAppMapper.cs │ │ │ ├── IAppStartService.cs │ │ │ ├── IAppTaskBar.cs │ │ │ └── IUpdateService.cs │ │ ├── Chat/ │ │ │ ├── ChatService.cs │ │ │ ├── Dtos/ │ │ │ │ ├── ChatMessageModel.cs │ │ │ │ └── FriendModel.cs │ │ │ └── IChatService.cs │ │ ├── Datapager/ │ │ │ ├── DataPagerService.cs │ │ │ └── IDataPagerService.cs │ │ ├── Localization/ │ │ │ ├── ILocaleCulture.cs │ │ │ ├── Local.cs │ │ │ ├── LocalizationSource.cs │ │ │ ├── PlatformCulture.cs │ │ │ └── UserLocalizationConfigDtoExtensions.cs │ │ ├── Permission/ │ │ │ ├── AppPermissions.cs │ │ │ ├── IPermissionPorxyService.cs │ │ │ ├── IPermissionService.cs │ │ │ └── PermissionItem.cs │ │ ├── Session/ │ │ │ ├── IHostDialogAware.cs │ │ │ └── IHostDialogService.cs │ │ ├── Storage/ │ │ │ ├── DataStorageKey.cs │ │ │ ├── DataStorageService.cs │ │ │ ├── IAccountStorageService.cs │ │ │ ├── IDataStorageService.cs │ │ │ └── TypeHelperExtended.cs │ │ └── Theme/ │ │ ├── IThemeService.cs │ │ └── ThemeItem.cs │ ├── SharedModuleExtensions.cs │ ├── Themes/ │ │ ├── FontIcons.xaml │ │ ├── Templates/ │ │ │ ├── FileTemplate.xaml │ │ │ ├── ImageTemplate.xaml │ │ │ └── TextTemplate.xaml │ │ └── generic.xaml │ ├── Validations/ │ │ ├── GlobalValidator.cs │ │ ├── IGlobalValidator.cs │ │ └── ValidatorExtensions.cs │ └── ViewModels/ │ ├── DialogViewModel.cs │ ├── HostDialogViewModel.cs │ ├── HostMessageViewModel.cs │ ├── MessageViewModel.cs │ ├── NavigationCurdViewModel.cs │ ├── NavigationViewModel.cs │ └── ViewModelBase.cs └── AppFramework.iOS/ ├── AppDelegate.cs ├── AppFramework.iOS.csproj ├── Assets.xcassets/ │ └── AppIcon.appiconset/ │ └── Contents.json ├── Entitlements.plist ├── Info.plist ├── Localization/ │ └── Locale.cs ├── Main.cs ├── Properties/ │ └── AssemblyInfo.cs └── Resources/ └── LaunchScreen.storyboard ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ ############################################################################### # Set default behavior to automatically normalize line endings. ############################################################################### * text=auto ############################################################################### # Set default behavior for command prompt diff. # # This is need for earlier builds of msysgit that does not have it on by # default for csharp files. # Note: This is only used by command line ############################################################################### #*.cs diff=csharp ############################################################################### # Set the merge driver for project and solution files # # Merging from the command prompt will add diff markers to the files if there # are conflicts (Merging from VS is not affected by the settings below, in VS # the diff markers are never inserted). Diff markers may cause the following # file extensions to fail to load in VS. An alternative would be to treat # these files as binary and thus will always conflict and require user # intervention with every merge. To do so, just uncomment the entries below ############################################################################### #*.sln merge=binary #*.csproj merge=binary #*.vbproj merge=binary #*.vcxproj merge=binary #*.vcproj merge=binary #*.dbproj merge=binary #*.fsproj merge=binary #*.lsproj merge=binary #*.wixproj merge=binary #*.modelproj merge=binary #*.sqlproj merge=binary #*.wwaproj merge=binary ############################################################################### # behavior for image files # # image files are treated as binary by default. ############################################################################### #*.jpg binary #*.png binary #*.gif binary ############################################################################### # diff behavior for common document formats # # Convert binary document formats to text before diffing them. This feature # is only available from the command line. Turn it on by uncommenting the # entries below. ############################################################################### #*.doc diff=astextplain #*.DOC diff=astextplain #*.docx diff=astextplain #*.DOCX diff=astextplain #*.dot diff=astextplain #*.DOT diff=astextplain #*.pdf diff=astextplain #*.PDF diff=astextplain #*.rtf diff=astextplain #*.RTF diff=astextplain ================================================ FILE: .gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. # User-specific files *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ build/ bld/ [Bb]in/ [Oo]bj/ # Visual Studio 2015 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUNIT *.VisualState.xml TestResult.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # DNX project.lock.json artifacts/ *_i.c *_p.c *_i.h *.ilk *.meta *.obj *.pch *.pdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opensdf *.sdf *.cachefile # Visual Studio profiler *.psess *.vsp *.vspx *.sap # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # JustCode is a .NET coding add-in .JustCode # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # TODO: Comment the next line if you want to checkin your web deploy settings # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj # NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore **/packages/* # except build/, which is used as an MSBuild target. !**/packages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/packages/repositories.config # Windows Azure Build Output csx/ *.build.csdef # Windows Azure Emulator efc/ rfc/ # Windows Store app package directory AppPackages/ # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !*.[Cc]ache/ # Others ClientBin/ [Ss]tyle[Cc]op.* ~$* *~ *.dbmdl *.dbproj.schemaview *.pfx *.publishsettings node_modules/ orleans.codegen.cs # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm # SQL Server files *.mdf *.ldf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings # Microsoft Fakes FakesAssemblies/ # GhostDoc plugin setting file *.GhostDoc.xml # Node.js Tools for Visual Studio .ntvs_analysis.dat # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions # Paket dependency manager .paket/paket.exe # FAKE - F# Make .fake/ *.binlog /.dotnet aspnet-core/AspNetZeroRadTool/ aspnet-core/src/AppFramework.Web.Host/wwwroot/app/version/ ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2020 henjigg 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. ================================================ FILE: README-en.md ================================================ ## Highlights This WPF framework supports multiple UI frameworks, including Syncfusion, HandyControl, and MaterialDesign. The functions of this framework include the following: - User and role management - Organization - Permission management - Multi-tenant - Instant messaging - Localize multilingual - Identity authentication and authorization - Audit logging - UI Theme - Exception handling - Data Dictionary - System settings ## Project instruction ABP officially does not officially provide a full version of the WPF framework, so this set of frameworks appeared to fill the gap in the market. If you are a developer using the ABP framework, then you can directly connect this set of systems to you without any effort. system business. And in the ABP commercial version, the Xamarin.Forms framework provided is also very simple, so this framework also includes the complete Xamarin.Forms version. ## (make a friend) - QQ:779149549 - Email: 779149549@qq.com ## Update History - [WPF ABP (2022-07)](https://www.cnblogs.com/zh7791/p/16510567.html) - [WPF ABP (2022-08)](https://www.cnblogs.com/zh7791/p/16655799.html) - [WPF ABP (2022-10)](https://www.cnblogs.com/zh7791/p/16839052.html) - [WPF ABP (2022-11)](https://www.cnblogs.com/zh7791/p/16930333.html) - [WPF ABP (2022-12)](https://www.cnblogs.com/zh7791/p/16984326.html) ## Screenshot #### WPF - Login Page ![](/img/wpf-login.png) - Home Page ![](./img/wpf-main.png) - User Page ![](./img/wpf-role.png) - Chat Page ![](./img/wpf-Chat.png) - Role Page ![](./img/wpf-user.png) ![](./img/wpf-roled.png) - Log Page ![](./img/wpf-log.png) ![](./img/wpf-logd.png) - Dynamic Properties ![](./img/wpf-dy.png) - multi-tenancy Page ![](./img/wpf-t.png) ![](./img/wpf-ta.png) - Version Page ![](./img/wpf-v.png) ![](./img/wpf-va.png) - Language Page ![](./img/wpf-lang.png) ![](./img/wpf-langd.png) ![](./img/wpf-lange.png) - Setting ![](./img/wpf-settimg.png) ![](./img/wpf-setting1.png) ![](./img/wpf-setting2.png) ![](./img/wpf-setting3.png) ![](./img/wpf-setting4.png) ![](./img/wpf-notify.png) - SKIN ![](./img/wpf-skin1.png) ![](./img/wpf-skin2.png) ![](./img/wpf-skin3.png) #### Xamarin.Forms - Login Page - Home Page - Function page - Organization - Role Page - User Page - Audit log page - Dynamic Property Page - multi-tenancy - Version - Language - Skin ================================================ FILE: README.md ================================================ 中文 | [English](./README-en.md) ## 亮点 本套WPF 框架支持多种UI框架, 包含: Syncfusion、HandyControl、MaterialDesign 。 本套框架基于ASP.NET Core Zero(ABP) 商业版进行开发,前端WPF部分开源。 ## 框架介绍 本套框架基于ABP商业版框架进行完整开发, 实现了ABP商业版中的功能, 并且提供了WPF以及Xamarin.Forms版本, 实现完整的跨平台应用开发。 功能包含如下: - 用户与角色管理 - 组织机构 - 权限管理 - 多租户 - 即时通讯 - 本地化多语言 - 身份认证及授权 - 审计日志记录 - UI主题 - 异常处理 - 数据字典 - 系统设置 ## 框架说明 ABP官方未正式提供完整版本WPF框架, 所以就出现了该套框架,来弥补市场的空白, 如果你是使用ABP框架的开发者, 那么你完全可以不费吹灰之力直接将本套系统接入到你们的系统业务当中。 并且ABP商业版中, 提供的Xamarin.Forms框架也是非常的简陋 , 所以本套框架也包含完整的Xamarin.Forms版本。 ## 联系方式 - QQ:779149549 - Email: 779149549@qq.com ## 视频与文档 关于实际的运行效果图可以参考视频: [WPF ABP框架演示](https://www.bilibili.com/video/BV1Av4y1w7ds?spm_id_from=333.999.0.0) 下面通过一些实际运行的截图来展示效果, 包含桌面端(WPF)以及移动端(Xamarin.Forms)效果图。 ## 框架截图(部分 新/旧) #### WPF - 登录页 ![](/img/wpf-login.png) - 首页 ![](./img/wpf-main.png) - 用户页 ![](./img/wpf-role.png) - 聊天页 ![](./img/wpf-Chat.png) - 角色页 ![](./img/wpf-user.png) ![](./img/wpf-roled.png) - 审计日志 ![](./img/wpf-log.png) ![](./img/wpf-logd.png) - 动态属性 ![](./img/wpf-dy.png) - 多租户 ![](./img/wpf-t.png) ![](./img/wpf-ta.png) - 版本列表 ![](./img/wpf-v.png) ![](./img/wpf-va.png) - 语言列表 ![](./img/wpf-lang.png) ![](./img/wpf-langd.png) ![](./img/wpf-lange.png) - 系统设置 ![](./img/wpf-settimg.png) ![](./img/wpf-setting1.png) ![](./img/wpf-setting2.png) ![](./img/wpf-setting3.png) ![](./img/wpf-setting4.png) ![](./img/wpf-notify.png) - 系统主题 ![](./img/wpf-skin1.png) ![](./img/wpf-skin2.png) ![](./img/wpf-skin3.png) #### Xamarin.Forms - 登录页 - 首页 - 功能页 - 组织机构 - 角色页 - 用户页 - 审计日志页 - 动态属性页 - 租户页 - 版本管理 - 语言列表 - 主题切换 ================================================ FILE: aspnet-core/.gitattributes ================================================ ############################################################################### # Set default behavior to automatically normalize line endings. ############################################################################### * text=auto ############################################################################### # Set default behavior for command prompt diff. # # This is need for earlier builds of msysgit that does not have it on by # default for csharp files. # Note: This is only used by command line ############################################################################### #*.cs diff=csharp ############################################################################### # Set the merge driver for project and solution files # # Merging from the command prompt will add diff markers to the files if there # are conflicts (Merging from VS is not affected by the settings below, in VS # the diff markers are never inserted). Diff markers may cause the following # file extensions to fail to load in VS. An alternative would be to treat # these files as binary and thus will always conflict and require user # intervention with every merge. To do so, just uncomment the entries below ############################################################################### #*.sln merge=binary #*.csproj merge=binary #*.vbproj merge=binary #*.vcxproj merge=binary #*.vcproj merge=binary #*.dbproj merge=binary #*.fsproj merge=binary #*.lsproj merge=binary #*.wixproj merge=binary #*.modelproj merge=binary #*.sqlproj merge=binary #*.wwaproj merge=binary ############################################################################### # behavior for image files # # image files are treated as binary by default. ############################################################################### #*.jpg binary #*.png binary #*.gif binary ############################################################################### # diff behavior for common document formats # # Convert binary document formats to text before diffing them. This feature # is only available from the command line. Turn it on by uncommenting the # entries below. ############################################################################### #*.doc diff=astextplain #*.DOC diff=astextplain #*.docx diff=astextplain #*.DOCX diff=astextplain #*.dot diff=astextplain #*.DOT diff=astextplain #*.pdf diff=astextplain #*.PDF diff=astextplain #*.rtf diff=astextplain #*.RTF diff=astextplain ================================================ FILE: aspnet-core/.gitignore ================================================ # Build Folders (you can keep bin if you'd like, to store dlls and pdbs) [Bb]in/ [Oo]bj/ # Logs Logs/ # Generated files project.lock.json .vs/ # mstest test results TestResults ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. # User-specific files *.suo *.user *.sln.docstates # Build results [Dd]ebug/ [Rr]elease/ x64/ *_i.c *_p.c *.ilk *.meta *.obj *.pch *.pdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.log *.vspscc *.vssscc .builds # Visual C++ cache files ipch/ *.aps *.ncb *.opensdf *.sdf # Visual Studio profiler *.psess *.vsp *.vspx # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper* # NCrunch *.ncrunch* .*crunch*.local.xml # Installshield output folder [Ee]xpress # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish # Publish Web Output *.Publish.xml # NuGet Packages Directory packages # Windows Azure Build Output csx *.build.csdef # Windows Store app package directory AppPackages/ # Others [Bb]in [Oo]bj sql TestResults [Tt]est[Rr]esult* *.Cache ClientBin [Ss]tyle[Cc]op.* ~$* *.dbmdl Generated_Code #added for RIA/Silverlight projects # Backup & report files from converting an old project file to a newer # Visual Studio version. Backup files are not needed, because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML src/.vs/config/applicationhost.config src/AppFrameworkDemo.Web.Host/wwwroot/Temp/Downloads src/AppFrameworkDemo.Web.Mvc/wwwroot/Temp/Downloads src/AppFrameworkDemo.Web.Mvc/Properties/PublishProfiles src/AppFrameworkDemo.Web.Mvc/node_modules src/AppFrameworkDemo.Web.Mvc/wwwroot/lib src/AppFrameworkDemo.Web.Mvc/wwwroot/dist src/AppFrameworkDemo.Web.Mvc/wwwroot/view-resources/Views/_Bundles src/AppFrameworkDemo.Web.Mvc/wwwroot/view-resources/Areas/App/Views/_Bundles src/AppFrameworkDemo.Web.Mvc/wwwroot/view-resources/**/*.min.* src/AppFrameworkDemo.Web.Mvc/wwwroot/Common/**/*.min.* src/AppFrameworkDemo.Web.Mvc/wwwroot/metronic/**/*.min.* src/AppFrameworkDemo.Web.Mvc/package-lock.json src/AppFrameworkDemo.Web.Public/wwwroot/lib src/AppFrameworkDemo.Web.Public/wwwroot/dist src/AppFrameworkDemo.Web.Public/wwwroot/Common/_Bundles src/AppFrameworkDemo.Web.Public/wwwroot/view-resources/Views/_Bundles src/AppFrameworkDemo.Web.Public/wwwroot/view-resources/**/*.min.* src/AppFrameworkDemo.Web.Public/wwwroot/Common/**/*.min.* src/AppFrameworkDemo.Web.Public/node_modules ================================================ FILE: aspnet-core/AppFramework.Mobile.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.2.32210.308 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D04D9608-9CEB-4E0A-B548-410F7475E9F1}" ProjectSection(SolutionItems) = preProject common.props = common.props EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppFramework.Application.Shared", "src\AppFramework.Application.Shared\AppFramework.Application.Shared.csproj", "{6143A90B-6C2A-4683-8A3A-4D48702770EA}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppFramework.Core.Shared", "src\AppFramework.Core.Shared\AppFramework.Core.Shared.csproj", "{4D6603C1-F7D6-4681-97F8-69B4BBBC0536}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppFramework.Android", "src\AppFramework.Android\AppFramework.Android.csproj", "{4F068C06-E551-4DD7-BFE6-00028846F2D0}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AppFramework.iOS", "src\AppFramework.iOS\AppFramework.iOS.csproj", "{AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppFramework.Application.Client", "src\AppFramework.Application.Client\AppFramework.Application.Client.csproj", "{572932C8-FC7F-472C-B466-0CC07F29FE7A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppFramework.Shared", "src\AppFramework.Mobile\AppFramework.Shared.csproj", "{CE474F44-B837-46A1-9154-0483D417D0F4}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Ad-Hoc|Any CPU = Ad-Hoc|Any CPU Ad-Hoc|iPhone = Ad-Hoc|iPhone Ad-Hoc|iPhoneSimulator = Ad-Hoc|iPhoneSimulator AppStore|Any CPU = AppStore|Any CPU AppStore|iPhone = AppStore|iPhone AppStore|iPhoneSimulator = AppStore|iPhoneSimulator Debug|Any CPU = Debug|Any CPU Debug|iPhone = Debug|iPhone Debug|iPhoneSimulator = Debug|iPhoneSimulator Release|Any CPU = Release|Any CPU Release|iPhone = Release|iPhone Release|iPhoneSimulator = Release|iPhoneSimulator EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {6143A90B-6C2A-4683-8A3A-4D48702770EA}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.AppStore|Any CPU.ActiveCfg = Release|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.AppStore|Any CPU.Build.0 = Release|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.AppStore|iPhone.ActiveCfg = Release|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.AppStore|iPhone.Build.0 = Release|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.Debug|Any CPU.Build.0 = Debug|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.Debug|iPhone.ActiveCfg = Debug|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.Debug|iPhone.Build.0 = Debug|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.Release|Any CPU.ActiveCfg = Release|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.Release|Any CPU.Build.0 = Release|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.Release|iPhone.ActiveCfg = Release|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.Release|iPhone.Build.0 = Release|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {6143A90B-6C2A-4683-8A3A-4D48702770EA}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.AppStore|Any CPU.ActiveCfg = Release|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.AppStore|Any CPU.Build.0 = Release|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.AppStore|iPhone.ActiveCfg = Release|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.AppStore|iPhone.Build.0 = Release|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Debug|Any CPU.Build.0 = Debug|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Debug|iPhone.ActiveCfg = Debug|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Debug|iPhone.Build.0 = Debug|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Release|Any CPU.ActiveCfg = Release|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Release|Any CPU.Build.0 = Release|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Release|iPhone.ActiveCfg = Release|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Release|iPhone.Build.0 = Release|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Ad-Hoc|Any CPU.Deploy.0 = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Ad-Hoc|iPhone.Deploy.0 = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Ad-Hoc|iPhoneSimulator.Deploy.0 = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.AppStore|Any CPU.Build.0 = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.AppStore|Any CPU.Deploy.0 = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.AppStore|iPhone.ActiveCfg = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.AppStore|iPhone.Build.0 = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.AppStore|iPhone.Deploy.0 = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.AppStore|iPhoneSimulator.Deploy.0 = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Debug|Any CPU.Build.0 = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Debug|Any CPU.Deploy.0 = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Debug|iPhone.ActiveCfg = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Debug|iPhone.Build.0 = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Debug|iPhone.Deploy.0 = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Debug|iPhoneSimulator.Deploy.0 = Debug|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Release|Any CPU.ActiveCfg = Release|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Release|Any CPU.Build.0 = Release|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Release|Any CPU.Deploy.0 = Release|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Release|iPhone.ActiveCfg = Release|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Release|iPhone.Build.0 = Release|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Release|iPhone.Deploy.0 = Release|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {4F068C06-E551-4DD7-BFE6-00028846F2D0}.Release|iPhoneSimulator.Deploy.0 = Release|Any CPU {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.Ad-Hoc|Any CPU.ActiveCfg = Debug|iPhoneSimulator {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.Ad-Hoc|Any CPU.Build.0 = Debug|iPhoneSimulator {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.Ad-Hoc|iPhone.ActiveCfg = Debug|iPhone {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.Ad-Hoc|iPhone.Build.0 = Debug|iPhone {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.AppStore|Any CPU.ActiveCfg = Debug|iPhoneSimulator {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.AppStore|Any CPU.Build.0 = Debug|iPhoneSimulator {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.AppStore|iPhone.ActiveCfg = Debug|iPhone {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.AppStore|iPhone.Build.0 = Debug|iPhone {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.AppStore|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.AppStore|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.Debug|Any CPU.ActiveCfg = Debug|iPhoneSimulator {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.Debug|Any CPU.Build.0 = Debug|iPhoneSimulator {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.Debug|iPhone.ActiveCfg = Debug|iPhone {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.Debug|iPhone.Build.0 = Debug|iPhone {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.Debug|iPhoneSimulator.ActiveCfg = Debug|iPhoneSimulator {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.Debug|iPhoneSimulator.Build.0 = Debug|iPhoneSimulator {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.Release|Any CPU.ActiveCfg = Release|iPhoneSimulator {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.Release|Any CPU.Build.0 = Release|iPhoneSimulator {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.Release|iPhone.ActiveCfg = Release|iPhone {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.Release|iPhone.Build.0 = Release|iPhone {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.Release|iPhoneSimulator.ActiveCfg = Release|iPhoneSimulator {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC}.Release|iPhoneSimulator.Build.0 = Release|iPhoneSimulator {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.AppStore|Any CPU.Build.0 = Debug|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.AppStore|iPhone.ActiveCfg = Debug|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.AppStore|iPhone.Build.0 = Debug|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Debug|Any CPU.Build.0 = Debug|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Debug|iPhone.ActiveCfg = Debug|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Debug|iPhone.Build.0 = Debug|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Release|Any CPU.ActiveCfg = Release|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Release|Any CPU.Build.0 = Release|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Release|iPhone.ActiveCfg = Release|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Release|iPhone.Build.0 = Release|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Release|iPhoneSimulator.Build.0 = Release|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.AppStore|Any CPU.Build.0 = Debug|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.AppStore|iPhone.ActiveCfg = Debug|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.AppStore|iPhone.Build.0 = Debug|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.Debug|Any CPU.Build.0 = Debug|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.Debug|iPhone.ActiveCfg = Debug|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.Debug|iPhone.Build.0 = Debug|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.Release|Any CPU.ActiveCfg = Release|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.Release|Any CPU.Build.0 = Release|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.Release|iPhone.ActiveCfg = Release|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.Release|iPhone.Build.0 = Release|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {CE474F44-B837-46A1-9154-0483D417D0F4}.Release|iPhoneSimulator.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {6143A90B-6C2A-4683-8A3A-4D48702770EA} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC} {4D6603C1-F7D6-4681-97F8-69B4BBBC0536} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC} {4F068C06-E551-4DD7-BFE6-00028846F2D0} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC} {AC99E6A5-A7AD-46D6-A75F-9B25D5272DBC} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC} {572932C8-FC7F-472C-B466-0CC07F29FE7A} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC} {CE474F44-B837-46A1-9154-0483D417D0F4} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {23CD4D4B-B131-473D-9ECB-5DD96E739671} EndGlobalSection EndGlobal ================================================ FILE: aspnet-core/AppFramework.Wpf.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.2.32210.308 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D04D9608-9CEB-4E0A-B548-410F7475E9F1}" ProjectSection(SolutionItems) = preProject common.props = common.props EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppFramework.Core.Shared", "src\AppFramework.Core.Shared\AppFramework.Core.Shared.csproj", "{4D6603C1-F7D6-4681-97F8-69B4BBBC0536}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppFramework.Application.Client", "src\AppFramework.Application.Client\AppFramework.Application.Client.csproj", "{572932C8-FC7F-472C-B466-0CC07F29FE7A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppFramework.Application.Shared", "src\AppFramework.Application.Shared\AppFramework.Application.Shared.csproj", "{67C10D05-BFBA-476E-B8E2-86961E1C24B7}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppFramework.Admin", "src\AppFramework.Admin\AppFramework.Admin.csproj", "{573187B5-ECAE-4DCA-8AE0-0934A38147AE}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppFramework.Shared", "src\AppFramework.Shared\AppFramework.Shared.csproj", "{74D7C22B-A950-48FE-990D-278A4F313543}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppFramework.Admin.MaterialUI", "src\AppFramework.Admin.MaterialUI\AppFramework.Admin.MaterialUI.csproj", "{B087FD4F-A0B1-404F-8588-F26C5EACA487}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppFramework.Admin.SyncUI", "src\AppFramework.Admin.SyncUI\AppFramework.Admin.SyncUI.csproj", "{46743A17-D920-4C79-8C0D-4353FA7CAE8D}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AppFramework.Admin.HandyUI", "src\AppFramework.Admin.HandyUI\AppFramework.Admin.HandyUI.csproj", "{AD9B572C-3225-4E78-87F9-C74BA35D8DD5}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Debug|Any CPU.Build.0 = Debug|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Release|Any CPU.ActiveCfg = Release|Any CPU {4D6603C1-F7D6-4681-97F8-69B4BBBC0536}.Release|Any CPU.Build.0 = Release|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Debug|Any CPU.Build.0 = Debug|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Release|Any CPU.ActiveCfg = Release|Any CPU {572932C8-FC7F-472C-B466-0CC07F29FE7A}.Release|Any CPU.Build.0 = Release|Any CPU {67C10D05-BFBA-476E-B8E2-86961E1C24B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {67C10D05-BFBA-476E-B8E2-86961E1C24B7}.Debug|Any CPU.Build.0 = Debug|Any CPU {67C10D05-BFBA-476E-B8E2-86961E1C24B7}.Release|Any CPU.ActiveCfg = Release|Any CPU {67C10D05-BFBA-476E-B8E2-86961E1C24B7}.Release|Any CPU.Build.0 = Release|Any CPU {573187B5-ECAE-4DCA-8AE0-0934A38147AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {573187B5-ECAE-4DCA-8AE0-0934A38147AE}.Debug|Any CPU.Build.0 = Debug|Any CPU {573187B5-ECAE-4DCA-8AE0-0934A38147AE}.Release|Any CPU.ActiveCfg = Release|Any CPU {573187B5-ECAE-4DCA-8AE0-0934A38147AE}.Release|Any CPU.Build.0 = Release|Any CPU {74D7C22B-A950-48FE-990D-278A4F313543}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {74D7C22B-A950-48FE-990D-278A4F313543}.Debug|Any CPU.Build.0 = Debug|Any CPU {74D7C22B-A950-48FE-990D-278A4F313543}.Release|Any CPU.ActiveCfg = Release|Any CPU {74D7C22B-A950-48FE-990D-278A4F313543}.Release|Any CPU.Build.0 = Release|Any CPU {B087FD4F-A0B1-404F-8588-F26C5EACA487}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B087FD4F-A0B1-404F-8588-F26C5EACA487}.Debug|Any CPU.Build.0 = Debug|Any CPU {B087FD4F-A0B1-404F-8588-F26C5EACA487}.Release|Any CPU.ActiveCfg = Release|Any CPU {B087FD4F-A0B1-404F-8588-F26C5EACA487}.Release|Any CPU.Build.0 = Release|Any CPU {46743A17-D920-4C79-8C0D-4353FA7CAE8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {46743A17-D920-4C79-8C0D-4353FA7CAE8D}.Debug|Any CPU.Build.0 = Debug|Any CPU {46743A17-D920-4C79-8C0D-4353FA7CAE8D}.Release|Any CPU.ActiveCfg = Release|Any CPU {46743A17-D920-4C79-8C0D-4353FA7CAE8D}.Release|Any CPU.Build.0 = Release|Any CPU {AD9B572C-3225-4E78-87F9-C74BA35D8DD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AD9B572C-3225-4E78-87F9-C74BA35D8DD5}.Debug|Any CPU.Build.0 = Debug|Any CPU {AD9B572C-3225-4E78-87F9-C74BA35D8DD5}.Release|Any CPU.ActiveCfg = Release|Any CPU {AD9B572C-3225-4E78-87F9-C74BA35D8DD5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {4D6603C1-F7D6-4681-97F8-69B4BBBC0536} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC} {572932C8-FC7F-472C-B466-0CC07F29FE7A} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC} {67C10D05-BFBA-476E-B8E2-86961E1C24B7} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC} {573187B5-ECAE-4DCA-8AE0-0934A38147AE} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC} {74D7C22B-A950-48FE-990D-278A4F313543} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC} {B087FD4F-A0B1-404F-8588-F26C5EACA487} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC} {46743A17-D920-4C79-8C0D-4353FA7CAE8D} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC} {AD9B572C-3225-4E78-87F9-C74BA35D8DD5} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {23CD4D4B-B131-473D-9ECB-5DD96E739671} EndGlobalSection EndGlobal ================================================ FILE: aspnet-core/Settings.XamlStyler ================================================ { // ==========[属性格式化]========== "AttributesTolerance": 2, // 单行最大属性数,2[默认],如果元素属性数不大于此数就不会换行 "KeepFirstAttributeOnSameLine": false, // 第一个属性是否与开始标记在同一行,false[默认] "MaxAttributeCharactersPerLine": 10, // 多个属性大于多少个字符就该换行,0[默认] "MaxAttributesPerLine": 3, // 大于几个属性就该换行,1[默认] // 无需换行的元素(比较短的),"RadialGradientBrush, GradientStop, LinearGradientBrush, ScaleTransform, SkewTransform, RotateTransform, TranslateTransform, Trigger, Condition, Setter"[默认] "NewlineExemptionElements": "RadialGradientBrush, GradientStop, LinearGradientBrush, ScaleTransform, SkewTransform, RotateTransform, TranslateTransform, Trigger, Condition, Setter", "AttributeIndentation": 0, // 属性缩进空格字符数(-1不缩进;0[默认]缩进4个空格;其它个数则指定) "AttributeIndentationStyle": 1, // 属性缩进风格(0混合,视情况使用制表符和空格;1[默认]使用空格) "RemoveDesignTimeReferences": false, // 是否移除自动添加的控件和设计时参考内容,false[默认] // // ==========[属性排序]========== "EnableAttributeReordering": true, // 是否启用属性的自动排序,true[默认] "SeparateByGroups": false, // 是否应该按照属性的分组进行分隔,false[默认] /* 属性排序和分组规则 "x:Class", "xmlns, xmlns:x", "xmlns:*", "x:Key, Key, x:Name, Name, x:Uid, Uid, Title", "Grid.Row, Grid.RowSpan, Grid.Column, Grid.ColumnSpan, Canvas.Left, Canvas.Top, Canvas.Right, Canvas.Bottom,Background,Style", "Width, Height, MinWidth, MinHeight, MaxWidth, MaxHeight", "Margin, Padding, HorizontalAlignment, VerticalAlignment, HorizontalContentAlignment, VerticalContentAlignment, Panel.ZIndex", "*:*, *", "PageSource, PageIndex, Offset, Color, TargetName, Property, Value, StartPoint, EndPoint", "mc:Ignorable, d:IsDataSource, d:LayoutOverrides, d:IsStaticText", "Storyboard.*, From, To, Duration" */ "AttributeOrderingRuleGroups": [ "x:Class", "xmlns, xmlns:x", "xmlns:*", "x:Key, Key, x:Name, Name, x:Uid, Uid, Title", "Grid.Row, Grid.RowSpan, Grid.Column, Grid.ColumnSpan, Canvas.Left, Canvas.Top, Canvas.Right, Canvas.Bottom", "Content,Text,IsChecked", "Command,CommandParameter", "Width, Height, MinWidth, MinHeight, MaxWidth, MaxHeight,MaxLength", "TextWrapping,Margin, Padding, HorizontalAlignment, VerticalAlignment, HorizontalContentAlignment, VerticalContentAlignment, Panel.ZIndex", "*:*, *", "PageSource, PageIndex, Offset, Color, TargetName, Property, Value, StartPoint, EndPoint", "mc:Ignorable, d:IsDataSource, d:LayoutOverrides, d:IsStaticText", "Storyboard.*, From, To, Duration" ], "FirstLineAttributes": "x:Name,Grid.Row,Grid.Column", // 应该在第一行的属性,例如Name、x:Name和x:Uid等等,None[默认] "OrderAttributesByName": false, // 是否按照属性名称进行排序 // // ==========[元素格式化]========== "PutEndingBracketOnNewLine": false, // 结束括号是否独占一行,false[默认] "RemoveEndingTagOfEmptyElement": true, // 是否移除空元素的结束标签,true[默认] "SpaceBeforeClosingSlash": true, // 自闭合元素的末尾斜杠前是否要有空格,true[默认] "RootElementLineBreakRule": 0, // 是否将根元素的属性分成多行(0[默认]默认;1始终;2从不) // // ==========[元素排序]========== "ReorderVSM": 2, // 是否重新排序Visual State Manager(0未定义;1[默认]移到最后;2移到最前) "ReorderGridChildren": false, // 是否重新排序Grid的子元素,false[默认] "ReorderCanvasChildren": false, // 是否重新排序Canvas的子元素,false[默认] "ReorderSetters": 0, // 是否重新排序Setter(0[默认]不排序;1按属性名;2按目标名;3先按目标名再按属性名) // // ==========[标记扩展]========== "FormatMarkupExtension": true, // 是否格式化标记扩展的属性,true[默认] // 始终放在一行上的标记扩展,"x:Bind, Binding"[默认] "NoNewLineMarkupExtensions": "x:Bind, Binding", // // ==========[属性排序]========== "ThicknessSeparator": 2, // Thickness类型的属性应该用哪种分隔符(0不格式化;1空格;2[默认]逗号) // 被认定为Thickness的元素应该是哪些,"Margin, Padding, BorderThickness, ThumbnailClipMargin"[默认] "ThicknessAttributes": "Margin, Padding, BorderThickness, ThumbnailClipMargin", // // ==========[杂项]========== "FormatOnSave": true, // 是否在保存时进行格式化,true[默认] "CommentPadding": 2, // 注释的间距应该是几个空格,2[默认] // // ==========[覆盖VS配置]========== "IndentSize": 4, // 缩进空格数,4[VS默认] "IndentWithTabs": false // 是否使用制表符进行缩进,false[VS默认] } ================================================ FILE: aspnet-core/common.props ================================================ 11.2.1 ================================================ FILE: aspnet-core/src/AppFramework.Admin/AdminModuleExtensions.cs ================================================ using Prism.Ioc; namespace AppFramework.Admin { public static class AdminModuleExtensions { public static void AddAdminsServices(this IContainerRegistry services) { services.AddValidators(); services.AddServices(); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/AppFramework.Admin.csproj ================================================  Library net6.0-windows enable true Code Code Code Code Code Code Code Code Code Code Code Code $(DefaultXamlRuntime) Designer $(DefaultXamlRuntime) $(DefaultXamlRuntime) Designer $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) Designer $(DefaultXamlRuntime) $(DefaultXamlRuntime) Designer $(DefaultXamlRuntime) $(DefaultXamlRuntime) Designer $(DefaultXamlRuntime) Designer $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) Designer $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) Designer $(DefaultXamlRuntime) Designer $(DefaultXamlRuntime) $(DefaultXamlRuntime) Designer $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) Designer $(DefaultXamlRuntime) Designer $(DefaultXamlRuntime) Designer ================================================ FILE: aspnet-core/src/AppFramework.Admin/Behaviors/ChatMessageListViewBehavior.cs ================================================ using Microsoft.Xaml.Behaviors; using System.ComponentModel; using System.Windows.Controls; using System.Windows.Data; namespace AppFramework.Admin.Behaviors { public class ChatMessageListBoxGroupBehavior : Behavior { protected override void OnAttached() { base.OnAttached(); ((ICollectionView)AssociatedObject.Items).GroupDescriptions.Add(new PropertyGroupDescription("CreationTime")); } protected override void OnDetaching() { base.OnDetaching(); ((ICollectionView)AssociatedObject.Items).GroupDescriptions.Remove(new PropertyGroupDescription("CreationTime")); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Behaviors/PasswordBehavior.cs ================================================ using Microsoft.Xaml.Behaviors; using System.Windows; using System.Windows.Controls; namespace AppFramework.Admin.Behaviors { public class PasswordBehavior : Behavior { protected override void OnAttached() { AssociatedObject.PasswordChanged += AssociatedObject_PasswordChanged; base.OnAttached(); } protected override void OnDetaching() { AssociatedObject.PasswordChanged -= AssociatedObject_PasswordChanged; base.OnDetaching(); } private void AssociatedObject_PasswordChanged(object sender, RoutedEventArgs e) { var passwordBox = sender as PasswordBox; string password = PasswordExtensions.GetPassword(passwordBox); if (passwordBox != null && password != passwordBox.Password) PasswordExtensions.SetPassword(passwordBox, passwordBox.Password); } } public class PasswordExtensions { public static string GetPassword(DependencyObject obj) { return (string)obj.GetValue(PasswordProperty); } public static void SetPassword(DependencyObject obj, string value) { obj.SetValue(PasswordProperty, value); } public static readonly DependencyProperty PasswordProperty = DependencyProperty.RegisterAttached("Password", typeof(string), typeof(PasswordExtensions), new PropertyMetadata(null, PropertyChangedCallback)); public static void PropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args) { var passwordBox = sender as PasswordBox; string password = (string)args.NewValue; if (passwordBox != null && passwordBox.Password != password) passwordBox.Password = password; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Extensions/EnumerableExtensions.cs ================================================ using System.Collections.Generic; namespace AppFramework.Admin { public static class EnumerableExtensions { public static int IndexOf(this IEnumerable source, T value) { int num = 0; EqualityComparer @default = EqualityComparer.Default; foreach (T item in source) { if (@default.Equals(item, value)) return num; num++; } return -1; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/AdminModuleMapper.cs ================================================ using AppFramework.ApiClient; using AppFramework.ApiClient.Models; using AppFramework.Auditing.Dto; using AppFramework.Authorization.Permissions.Dto; using AppFramework.Authorization.Roles.Dto; using AppFramework.Authorization.Users.Dto; using AppFramework.DynamicEntityProperties.Dto; using AppFramework.Editions.Dto; using AppFramework.Friendships.Dto; using AppFramework.Localization.Dto; using AppFramework.MultiTenancy.Dto; using AppFramework.Organizations.Dto; using AppFramework.Sessions.Dto; using AppFramework.Shared.Models; using AppFramework.Shared.Models.Chat; using AppFramework.Version.Dtos; using AutoMapper; namespace AppFramework.Admin.Models { public class AdminModuleMapper : Profile { public AdminModuleMapper() { CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); //系统模块中实体映射关系 CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); CreateMap().ReverseMap(); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Auditlogs/AuditLogListModel.cs ================================================ using AppFramework.Shared.Models; using System; namespace AppFramework.Admin.Models { public class AuditLogListModel : EntityObject { public long? UserId { get; set; } public string UserName { get; set; } public int? ImpersonatorTenantId { get; set; } public long? ImpersonatorUserId { get; set; } public string ServiceName { get; set; } public string MethodName { get; set; } public string Parameters { get; set; } public DateTime ExecutionTime { get; set; } public int ExecutionDuration { get; set; } public string ClientIpAddress { get; set; } public string ClientName { get; set; } public string BrowserInfo { get; set; } public string Exception { get; set; } public string CustomData { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Auditlogs/GetAuditLogsFilter.cs ================================================ using CommunityToolkit.Mvvm.ComponentModel; using System; namespace AppFramework.Admin.Models { public partial class GetAuditLogsFilter : PagedAndSortedFilter { [ObservableProperty] public DateTime? startDate; [ObservableProperty] public DateTime? endDate; [ObservableProperty] private string userName; [ObservableProperty] private string serviceName; [ObservableProperty] private string methodName; [ObservableProperty] private string browserInfo; [ObservableProperty] private bool? hasException; [ObservableProperty] private int? minExecutionDuration; [ObservableProperty] private int? maxExecutionDuration; } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Auditlogs/GetEntityChangeFilter.cs ================================================ using CommunityToolkit.Mvvm.ComponentModel; using System; namespace AppFramework.Admin.Models { public partial class GetEntityChangeFilter : PagedAndSortedFilter { [ObservableProperty] public DateTime startDate; [ObservableProperty] public DateTime endDate; [ObservableProperty] public string userName; [ObservableProperty] public string entityTypeFullName; } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Dashboard/AreaSeriesChart3DModel.cs ================================================ using System; namespace AppFramework.Admin.Models { public class AreaSeriesChart3DModel { public decimal Amount { get; set; } public DateTime Date { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Dashboard/DoughnutChartPopulations.cs ================================================ using System; namespace AppFramework.Admin.Models { public class DoughnutChartPopulations { public string Continent { get; set; } public string Countries { get; set; } public string States { get; set; } public double PopulationinStates { get; set; } public double PopulationinCountries { get; set; } public double PopulationinContinents { get; set; } public string Category { get; set; } public double Expenditure { get; set; } public Uri Image { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Dashboard/TopStatusItem.cs ================================================ namespace AppFramework.Admin.Models { public class TopStatusItem { public string Logo { get; set; } public string Title { get; set; } public decimal Amount { get; set; } public string Foreground { get; set; } public string BackgroundGradientStart { get; set; } public string BackgroundGradientEnd { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/DynamicProperty/DynamicPropertyModel.cs ================================================ using AppFramework.Shared.Models; using CommunityToolkit.Mvvm.ComponentModel; namespace AppFramework.Admin.Models { public partial class DynamicPropertyModel : EntityObject { [ObservableProperty] private string propertyName; [ObservableProperty] private string displayName; [ObservableProperty] private string inputType; [ObservableProperty] private string permission; public int? TenantId { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Edition/EditionCreateModel.cs ================================================ using CommunityToolkit.Mvvm.ComponentModel; namespace AppFramework.Admin.Models { [INotifyPropertyChanged] public partial class EditionCreateModel { [ObservableProperty] public string displayName; [ObservableProperty] public decimal? dailyPrice; [ObservableProperty] public decimal? weeklyPrice; [ObservableProperty] public decimal? monthlyPrice; [ObservableProperty] public decimal? annualPrice; [ObservableProperty] public int? trialDayCount; [ObservableProperty] public int? waitingDayAfterExpire; [ObservableProperty] public int? expiringEditionId; public int? Id { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Edition/EditionListModel.cs ================================================ namespace AppFramework.Admin.Models { public class EditionListModel { public int Id { get; set; } public string Name { get; set; } public string DisplayName { get; set; } public decimal? DailyPrice { get; set; } public decimal? WeeklyPrice { get; set; } public decimal? MonthlyPrice { get; set; } public decimal? AnnualPrice { get; set; } public int? WaitingDayAfterExpire { get; set; } public int? TrialDayCount { get; set; } public string ExpiringEditionDisplayName { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Edition/FlatFeatureModel.cs ================================================ using AppFramework.Editions.Dto; using CommunityToolkit.Mvvm.ComponentModel; using System.Collections.ObjectModel; namespace AppFramework.Admin.Models { [INotifyPropertyChanged] public partial class FlatFeatureModel { [ObservableProperty] public bool isChecked; public string ParentName { get; set; } public string Name { get; set; } public string DisplayName { get; set; } public string Description { get; set; } public string DefaultValue { get; set; } public FeatureInputTypeDto InputType { get; set; } [ObservableProperty] public ObservableCollection items; } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Filters/PagedAndSortedFilter.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AppFramework.Admin.Models { public class PagedAndSortedFilter : PagedFilter { public string Sorting { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Filters/PagedFilter.cs ================================================ using CommunityToolkit.Mvvm.ComponentModel; namespace AppFramework.Admin.Models { [INotifyPropertyChanged] public partial class PagedFilter { public PagedFilter() { MaxResultCount = AppConsts.DefaultPageSize; } public int MaxResultCount { get; set; } public int SkipCount { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Language/Language.cs ================================================ namespace AppFramework.Admin.Models { public struct LanguageStruct { public LanguageStruct(string icon, string name, string displayName) { Icon = icon; Name = name; DisplayName = displayName; } public string Icon { get; } public string Name { get; } public string DisplayName { get; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Language/LanguageListModel.cs ================================================ using Prism.Mvvm; using System; namespace AppFramework.Admin.Models { public class LanguageListModel { public int Id { get; set; } public int? TenantId { get; set; } public string Name { get; set; } public string DisplayName { get; set; } public string Icon { get; set; } public bool IsDisabled { get; set; } public DateTime CreationTime { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Language/LanguageTextListModel.cs ================================================ namespace AppFramework.Admin.Models { public class LanguageTextListModel { public string Key { get; set; } public string BaseValue { get; set; } public string TargetValue { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Organizations/CreateOrganizationUnitModel.cs ================================================ using CommunityToolkit.Mvvm.ComponentModel; using Prism.Mvvm; namespace AppFramework.Admin.Models { [INotifyPropertyChanged] public partial class CreateOrganizationUnitModel { [ObservableProperty] private string displayName; public long? ParentId { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Organizations/OrganizationListModel.cs ================================================ using CommunityToolkit.Mvvm.ComponentModel; using Prism.Mvvm; using System.Collections.ObjectModel; namespace AppFramework.Admin.Models { [INotifyPropertyChanged] public partial class OrganizationListModel { [ObservableProperty] private bool isChecked; [ObservableProperty] private string displayName; [ObservableProperty] private int memberCount; [ObservableProperty] private int roleCount; [ObservableProperty] private ObservableCollection items = new ObservableCollection(); public long Id { get; set; } public long? ParentId { get; set; } public string Code { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Organizations/OrganizationUnitModel.cs ================================================ using AppFramework.Organizations.Dto; namespace AppFramework.Admin.Models { public class OrganizationUnitModel : OrganizationUnitDto { public bool IsAssigned { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Permission/PermissionHelper.cs ================================================ using AppFramework.Admin.Models; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; namespace AppFramework { public static class PermissionHelper { /// /// 创建权限节点目录树 /// /// /// /// public static ObservableCollection CreateTrees(this List flats, PermissionModel? model) { var trees = new ObservableCollection(); var nodes = flats.Where(q => q.ParentName == model?.Name).ToArray(); foreach (var node in nodes) { node.Items = CreateTrees(flats, node); node.Parent = model; trees.Add(node); } return trees; } /// /// 获取选中节点列表 /// /// /// /// public static ObservableCollection GetSelectedItems(this ObservableCollection nodes, List GrantedPermissionNames) { var permItems = new ObservableCollection(); foreach (var item in GrantedPermissionNames) { var permItem = GetSelectedItems(nodes, item); if (permItem != null) permItems.Add(permItem); } return permItems; PermissionModel GetSelectedItems(ObservableCollection nodes, string key) { PermissionModel model = null; foreach (var flat in nodes) { if (flat.Name.Equals(key))//&& flat.Items.Count == 0) { model = flat; break; } model = GetSelectedItems(flat.Items, key); if (model != null) break; } return model; } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Permission/PermissionModel.cs ================================================ using CommunityToolkit.Mvvm.ComponentModel; using System.Collections.Generic; using System.Collections.ObjectModel; namespace AppFramework.Admin.Models { [INotifyPropertyChanged] public partial class PermissionModel { public PermissionModel? Parent { get; set; } public string ParentName { get; set; } public string Name { get; set; } public string DisplayName { get; set; } public string Description { get; set; } public bool IsGrantedByDefault { get; set; } [ObservableProperty] private bool isChecked; [ObservableProperty] public ObservableCollection items; private void SetIsChecked(bool value, bool checkedChildren, bool checkedParent) { if (isChecked == value) return; isChecked = value; if (checkedChildren && Items != null) { for (int i = 0; i < Items.Count; i++) Items[i].SetIsChecked(value, true, false); } if (checkedParent && this.Parent != null) this.Parent.CheckParentIsCheckedState(); OnPropertyChanged(nameof(IsChecked)); } private void CheckParentIsCheckedState() { List checkedItems = new List(); string checkedNames = string.Empty; bool currentState = this.IsChecked; bool firstState = false; for (int i = 0; i < this.Items.Count; i++) { bool childrenState = this.Items[i].IsChecked; if (i == 0) firstState = childrenState; else if (firstState != childrenState) firstState = false; } if (!firstState) currentState = firstState; SetIsChecked(firstState, false, true); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Roles/ChooseItem.cs ================================================ using Abp.Application.Services.Dto; using CommunityToolkit.Mvvm.ComponentModel; namespace AppFramework.Admin.Models { [INotifyPropertyChanged] public partial class ChooseItem { public ChooseItem(NameValueDto nameValue) { value = nameValue; } [ObservableProperty] private bool isSelected; private NameValueDto value; public NameValueDto Value { get { return value; } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Roles/RoleEditModel.cs ================================================ using CommunityToolkit.Mvvm.ComponentModel; namespace AppFramework.Admin.Models { [INotifyPropertyChanged] public partial class RoleEditModel { [ObservableProperty] private string displayName; [ObservableProperty] private bool isDefault; public long? Id { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Roles/RoleListModel.cs ================================================ using AppFramework.Shared.Models; using System; namespace AppFramework.Admin.Models { public class RoleListModel : EntityObject { public string Name { get; set; } public string DisplayName { get; set; } public bool IsStatic { get; set; } public bool IsDefault { get; set; } public DateTime CreationTime { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Roles/UserRoleModel.cs ================================================ using CommunityToolkit.Mvvm.ComponentModel; using Prism.Mvvm; namespace AppFramework.Admin.Models { [INotifyPropertyChanged] public partial class UserRoleModel { [ObservableProperty] private bool isChecked; public int RoleId { get; set; } public string RoleName { get; set; } public string RoleDisplayName { get; set; } public bool IsAssigned { get; set; } public bool InheritedFromOrganizationUnit { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Tenants/GetTenantsFilter.cs ================================================ using CommunityToolkit.Mvvm.ComponentModel; using System; namespace AppFramework.Admin.Models { public partial class GetTenantsFilter : PagedAndSortedFilter { [ObservableProperty] private DateTime? subscriptionEndDateStart; [ObservableProperty] private DateTime? subscriptionEndDateEnd; [ObservableProperty] private DateTime? creationDateStart; [ObservableProperty] private DateTime? creationDateEnd; [ObservableProperty] public string filter; [ObservableProperty] private int? editionId; public bool EditionIdSpecified { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Tenants/TenantListModel.cs ================================================ using AppFramework.Shared.Models; using CommunityToolkit.Mvvm.ComponentModel; using System; namespace AppFramework.Admin.Models { public partial class TenantListModel : EntityObject { [ObservableProperty] private string name; [ObservableProperty] private string tenancyName; [ObservableProperty] private string connectionString; [ObservableProperty] private bool isActive; [ObservableProperty] private DateTime? subscriptionEndDateUtc; [ObservableProperty] private bool isInTrialPeriod; [ObservableProperty] private string adminEmailAddress; [ObservableProperty] private bool sendActivationEmail; [ObservableProperty] private bool shouldChangePasswordOnNextLogin; public string EditionDisplayName { get; set; } public DateTime CreationTime { get; set; } public int? EditionId { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Update/VersionListModel.cs ================================================ using AppFramework.Shared.Models; using CommunityToolkit.Mvvm.ComponentModel; namespace AppFramework.Admin.Models { public partial class VersionListModel : EntityObject { [ObservableProperty] public string name; [ObservableProperty] public string version; [ObservableProperty] public bool isEnable; [ObservableProperty] public bool isForced; [ObservableProperty] public string minimumVersion; public string DownloadUrl { get; set; } public string ChangelogUrl { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Users/UserCreateOrUpdateModel.cs ================================================ using CommunityToolkit.Mvvm.ComponentModel; using Prism.Mvvm; using System.Collections.Generic; namespace AppFramework.Admin.Models { [INotifyPropertyChanged] public partial class UserCreateOrUpdateModel { [ObservableProperty] private bool sendActivationEmail; [ObservableProperty] private bool setRandomPassword; public UserEditModel User { get; set; } public string[] AssignedRoleNames { get; set; } public List OrganizationUnits { get; set; } public UserCreateOrUpdateModel() { OrganizationUnits = new List(); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Users/UserEditModel.cs ================================================ using CommunityToolkit.Mvvm.ComponentModel; namespace AppFramework.Admin.Models { [INotifyPropertyChanged] public partial class UserEditModel { [ObservableProperty] private string phoneNumber; [ObservableProperty] private string userName; [ObservableProperty] private string password; [ObservableProperty] private string name; [ObservableProperty] private string surname; [ObservableProperty] private string emailAddress; [ObservableProperty] private bool isActive; [ObservableProperty] private bool shouldChangePasswordOnNextLogin; [ObservableProperty] private bool isTwoFactorEnabled; [ObservableProperty] private bool isLockoutEnabled; public long? Id { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Users/UserForEditModel.cs ================================================ using AppFramework.Authorization.Users.Dto; using AppFramework.Organizations.Dto; using CommunityToolkit.Mvvm.ComponentModel; using Prism.Mvvm; using System; using System.Collections.Generic; using System.Linq; namespace AppFramework.Admin.Models { [INotifyPropertyChanged] public partial class UserForEditModel { public Guid? ProfilePictureId { get; set; } [ObservableProperty] private UserEditModel user; public UserRoleDto[] Roles { get; set; } public List AllOrganizationUnits { get; set; } public List MemberedOrganizationUnits { get; set; } private byte[] _photo; private List _organizationUnits; public string FullName => User == null ? string.Empty : User.Name + " " + User.Surname; public DateTime CreationTime { get; set; } public bool IsEmailConfirmed { get; set; } public byte[] Photo { get => _photo; set { _photo = value; OnPropertyChanged(); } } public List OrganizationUnits { get => _organizationUnits; set { _organizationUnits = value?.OrderBy(o => o.Code).ToList(); SetAsAssignedForMemberedOrganizationUnits(); OnPropertyChanged(); } } private void SetAsAssignedForMemberedOrganizationUnits() { if (_organizationUnits != null) { MemberedOrganizationUnits?.ForEach(memberedOrgUnitCode => { _organizationUnits .Single(o => o.Code == memberedOrgUnitCode) .IsAssigned = true; }); } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Users/UserListModel.cs ================================================ using AppFramework.Authorization.Users.Dto; using AppFramework.Shared.Models; using CommunityToolkit.Mvvm.ComponentModel; using System; using System.Collections.Generic; namespace AppFramework.Admin.Models { public partial class UserListModel : EntityObject { [ObservableProperty] private byte[] photo; public string FullName => Name + " " + Surname; public string Name { get; set; } public string Surname { get; set; } public string UserName { get; set; } public string EmailAddress { get; set; } public string PhoneNumber { get; set; } public Guid? ProfilePictureId { get; set; } public bool IsEmailConfirmed { get; set; } public List Roles { get; set; } public bool IsActive { get; set; } public DateTime CreationTime { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Models/Users/UserLoginInfoModel.cs ================================================ using CommunityToolkit.Mvvm.ComponentModel; namespace AppFramework.Admin.Models { [INotifyPropertyChanged] public partial class UserLoginInfoModel { [ObservableProperty] private string name; [ObservableProperty] private string surname; [ObservableProperty] private string userName; [ObservableProperty] private string emailAddress; public string ProfilePictureId { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Services/Account/AccountService.cs ================================================ using AppFramework.ApiClient; using AppFramework.ApiClient.Models; using AppFramework.Shared.Services; using AppFramework.Sessions; using AppFramework.Sessions.Dto; using Prism.Mvvm; using Prism.Services.Dialogs; using System.Threading.Tasks; using AppFramework.Shared; using AppFramework.Shared.Services.App; using AppFramework.Admin.Models; namespace AppFramework.Admin.Services.Account { public class AccountService : BindableBase, IAccountService { private readonly IHostDialogService dialog; private readonly IAppStartService appStart; private readonly IChatService chatService; public readonly IAccountStorageService dataStorageService; public readonly IApplicationContext applicationContext; public readonly ISessionAppService sessionAppService; public readonly IAccessTokenManager accessTokenManager; public AccountService( IHostDialogService dialog, IAppStartService appStart, IChatService chatService, IApplicationContext applicationContext, ISessionAppService sessionAppService, IAccessTokenManager accessTokenManager, IAccountStorageService dataStorageService, AbpAuthenticateModel authenticateModel) { this.dialog = dialog; this.appStart = appStart; this.chatService=chatService; this.applicationContext = applicationContext; this.sessionAppService = sessionAppService; this.accessTokenManager = accessTokenManager; this.dataStorageService = dataStorageService; this.AuthenticateModel = authenticateModel; } public AbpAuthenticateModel AuthenticateModel { get; set; } public AbpAuthenticateResultModel AuthenticateResultModel { get; set; } public async Task LoginUserAsync() { var result = await accessTokenManager.LoginAsync(); await AuthenticateSucceed(result); } public async Task LoginCurrentUserAsync(UserListModel user) { accessTokenManager.Logout(); applicationContext.ClearLoginInfo(); dataStorageService.ClearSessionPersistance(); await GoToLoginPageAsync(); } public async Task LogoutAsync() { accessTokenManager.Logout(); applicationContext.ClearLoginInfo(); dataStorageService.ClearSessionPersistance(); await GoToLoginPageAsync(); } private async Task GoToLoginPageAsync() { await chatService.CloseAsync(); appStart.Logout(); } private async Task AuthenticateSucceed(AbpAuthenticateResultModel result) { AuthenticateResultModel = result; if (AuthenticateResultModel.ShouldResetPassword) { DialogParameters param = new DialogParameters(); param.Add("Value", result); var pwdResult = await dialog.ShowDialogAsync(AppViews.FirstChangedPwd, param, AppSharedConsts.LoginIdentifier); if (pwdResult.Result != ButtonResult.OK) return; } if (AuthenticateResultModel.RequiresTwoFactorVerification) { DialogParameters param = new DialogParameters(); param.Add("Value", AuthenticateResultModel); await dialog.ShowDialogAsync(AppViews.SendTwoFactorCode, param, AppSharedConsts.LoginIdentifier); } if (!AuthenticateModel.IsTwoFactorVerification) { await dataStorageService.StoreAuthenticateResultAsync(AuthenticateResultModel); } await SetCurrentUserInfoAsync(); await UserConfigurationManager.GetAsync(); } public async Task SetCurrentUserInfoAsync() { await WebRequest.Execute(() => sessionAppService.GetCurrentLoginInformations(), GetCurrentUserInfoExecuted); } public async Task GetCurrentUserInfoExecuted(GetCurrentLoginInformationsOutput result) { applicationContext.SetLoginInfo(result); await dataStorageService.StoreLoginInformationAsync(applicationContext.LoginInfo); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Services/Account/AccountStorageService.cs ================================================ using AppFramework.ApiClient; using AppFramework.ApiClient.Models; using AppFramework.Shared.Models; using AppFramework.Shared.Services; using AppFramework.Sessions.Dto; using System.Threading.Tasks; using AppFramework.Shared.Services.Mapper; namespace AppFramework.Admin.Services.Account { public class AccountStorageService : IAccountStorageService { private readonly IDataStorageService _dataStorageManager; private readonly IAppMapper mapper; public AccountStorageService( IDataStorageService dataStorageManager, IAppMapper mapper) { _dataStorageManager = dataStorageManager; this.mapper = mapper; } public async Task StoreAccessTokenAsync(string newAccessToken) { var authenticateResult = _dataStorageManager.GetValue(DataStorageKey.CurrentSession_TokenInfo); authenticateResult.AccessToken = newAccessToken; _dataStorageManager.SetValue(DataStorageKey.CurrentSession_TokenInfo, authenticateResult); await Task.CompletedTask; } public AbpAuthenticateResultModel RetrieveAuthenticateResult() { return mapper.Map( _dataStorageManager.GetValue( DataStorageKey.CurrentSession_TokenInfo)); } public async Task StoreAuthenticateResultAsync(AbpAuthenticateResultModel authenticateResultModel) { _dataStorageManager.SetValue( DataStorageKey.CurrentSession_TokenInfo, mapper.Map(authenticateResultModel) ); await Task.CompletedTask; } public TenantInformation RetrieveTenantInfo() { return mapper.Map( _dataStorageManager.GetValue( DataStorageKey.CurrentSession_TenantInfo ) ); } public async Task StoreTenantInfoAsync(TenantInformation tenantInfo) { _dataStorageManager.SetValue( DataStorageKey.CurrentSession_TenantInfo, mapper.Map(tenantInfo) ); await Task.CompletedTask; } public GetCurrentLoginInformationsOutput RetrieveLoginInfo() { return mapper.Map( _dataStorageManager.GetValue( DataStorageKey.CurrentSession_LoginInfo ) ); } public async Task StoreLoginInformationAsync(GetCurrentLoginInformationsOutput loginInfo) { var value = mapper .Map(loginInfo); _dataStorageManager.SetValue( DataStorageKey.CurrentSession_LoginInfo, value); await Task.CompletedTask; } public void ClearSessionPersistance() { _dataStorageManager.Remove(DataStorageKey.CurrentSession_TokenInfo); _dataStorageManager.Remove(DataStorageKey.CurrentSession_TenantInfo); _dataStorageManager.Remove(DataStorageKey.CurrentSession_LoginInfo); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Services/Account/ApplicationService.cs ================================================ using AppFramework.ApiClient; using AppFramework.Authorization.Users.Profile; using AppFramework.Authorization.Users.Profile.Dto; using AppFramework.Shared.Models; using AppFramework.Shared.Services.Permission; using AppFramework.Admin.Services.Notification; using Prism.Regions; using Prism.Services.Dialogs; using System; using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using AppFramework.Shared; using AppFramework.Shared.Services; namespace AppFramework.Admin.Services.Account { public class ApplicationService : ViewModelBase, IApplicationService { public ApplicationService( IHostDialogService dialog, IDialogService dialogService, IRegionManager regionManager, IAccountService accountService, INavigationMenuService navigationItemService, IProfileAppService profileAppService, IApplicationContext applicationContext, NavigationService navigationService, NotificationService notificationService) { this.dialog = dialog; this.accountService = accountService; this.applicationContext = applicationContext; this.navigationService = navigationService; this.notificationService = notificationService; this.dialogService = dialogService; this.navigationItemService = navigationItemService; this.regionManager = regionManager; this.profileAppService = profileAppService; navigationItems = new ObservableCollection(); } #region 字段/属性 private readonly IApplicationContext applicationContext; private readonly NavigationService navigationService; private readonly NotificationService notificationService; private readonly IDialogService dialogService; private readonly IHostDialogService dialog; private readonly INavigationMenuService navigationItemService; private readonly IRegionManager regionManager; private readonly IAccountService accountService; private readonly IProfileAppService profileAppService; private byte[] photo; private byte[] profilePictureBytes; private string userNameAndSurname; private string emailAddress; private string applicationInfo; private string applicationName; public string ApplicationName { get { return applicationName; } set { applicationName = value; OnPropertyChanged(); } } public byte[] Photo { get => photo; set { photo = value; OnPropertyChanged(); } } public string UserNameAndSurname { get => userNameAndSurname; set { userNameAndSurname = value; OnPropertyChanged(); } } public string EmailAddress { get => emailAddress; set { emailAddress = value; OnPropertyChanged(); } } public string ApplicationInfo { get => applicationInfo; set { applicationInfo = value; OnPropertyChanged(); } } private ObservableCollection navigationItems; public ObservableCollection NavigationItems { get { return navigationItems; } set { navigationItems = value; OnPropertyChanged(); } } private ObservableCollection userMenuItems; public ObservableCollection UserMenuItems { get { return userMenuItems; } set { userMenuItems = value; OnPropertyChanged(); } } #endregion #region 用户方法 public async Task ShowMyProfile() { dialogService.Show(AppViews.MyProfile); await Task.CompletedTask; } protected async Task GetUserPhoto() { await WebRequest.Execute(() => profileAppService.GetProfilePictureByUser(applicationContext.LoginInfo.User.Id), GetProfilePictureByUserSuccessed); } private async Task GetProfilePictureByUserSuccessed(GetProfilePictureOutput output) { if (output != null) Photo = Convert.FromBase64String(output.ProfilePicture); await Task.CompletedTask; } public async Task ShowProfilePhoto() { if (profilePictureBytes == null) return; NavigationParameters param = new NavigationParameters(); param.Add("Value", profilePictureBytes); regionManager.Regions[AppRegions.Main].RequestNavigate(AppViews.ProfilePicture, param); await Task.CompletedTask; } #endregion #region 用户菜单方法 private int selectedIndex = -1; public int SelectedIndex { get { return selectedIndex; } set { selectedIndex = value; OnPropertyChanged(); } } public async Task GetApplicationInfo() { await GetUserPhoto(); ApplicationName = Local.Localize("EmailActivation_Title"); UserNameAndSurname = applicationContext.LoginInfo.User.Name; EmailAddress = applicationContext.LoginInfo.User.EmailAddress; RefreshAuthMenus(); ApplicationInfo = $"{ApplicationName}\n" + $"v{applicationContext.LoginInfo.Application.Version} " + $"[{applicationContext.LoginInfo.Application.ReleaseDate:yyyyMMdd}]"; } public void RefreshAuthMenus() { var permissions = applicationContext.Configuration.Auth.GrantedPermissions; NavigationItems = navigationItemService.GetAuthMenus(permissions); UserMenuItems = new ObservableCollection() { new PermissionItem("accounts",Local.Localize("ManageLinkedAccounts"), "",ManageLinkedAccounts), new PermissionItem("manageuser",Local.Localize("ManageUserDelegations"),"",ManageUserDelegations), new PermissionItem("password",Local.Localize("ChangePassword"),"",ChangePassword), new PermissionItem("loginattempts",Local.Localize("LoginAttempts"),"",LoginAttempts), new PermissionItem("picture",Local.Localize("ChangeProfilePicture"),"",ChangeProfilePicture), new PermissionItem("mysettings",Local.Localize("MySettings"),"",MySettings), new PermissionItem("download",Local.Localize("Download"),"",Download), new PermissionItem("logout",Local.Localize("Logout"),"",LogOut), }; } public void ExecuteUserAction(string key) { var item = UserMenuItems.FirstOrDefault(t => t.Key.Equals(key)); if (item != null) item.Action?.Invoke(); } private async void LogOut() { if (await dialog.Question(Local.Localize("AreYouSure"))) { regionManager.Regions[AppRegions.Main].RemoveAll(); await accountService.LogoutAsync(); } await ResetClickIndex(); } private void ManageLinkedAccounts() { ShowPage(AppViews.ManageLinkedAccounts); } private void ManageUserDelegations() { ShowPage(AppViews.ManageUserDelegations); } private void ChangePassword() { ShowPage(AppViews.ChangePassword); } private void LoginAttempts() { navigationService.Navigate(AppViews.LoginAttempts); } private void MySettings() { ShowPage(AppViews.MyProfile); } private async void ShowPage(string pageName) { await dialog.ShowDialogAsync(pageName); await ResetClickIndex(); } private async void Download() { await profileAppService.PrepareCollectedData().WebAsync(async () => { await notificationService.GetNotifications(); await ResetClickIndex(); DialogHelper.Info(Local.Localize("Notifications"), Local.Localize("GdprDataPreparedNotificationMessage")); }); } private async void ChangeProfilePicture() { var dialogResult = await dialog.ShowDialogAsync(AppViews.ChangeAvatar); if (dialogResult.Result == ButtonResult.OK) { Photo = dialogResult.Parameters.GetValue("Value"); await ResetClickIndex(); } } private async Task ResetClickIndex() { SelectedIndex = -1; await Task.Delay(200); } #endregion } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Services/Account/IAccountService.cs ================================================ using AppFramework.ApiClient.Models; using AppFramework.Admin.Models; using System.Threading.Tasks; namespace AppFramework.Admin.Services { public interface IAccountService { AbpAuthenticateModel AuthenticateModel { get; set; } AbpAuthenticateResultModel AuthenticateResultModel { get; set; } Task LoginUserAsync(); Task LoginCurrentUserAsync(UserListModel user); Task LogoutAsync(); } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Services/Account/IApplicationService.cs ================================================ using System.Threading.Tasks; namespace AppFramework.Admin.Services { /// /// 应用程序服务 /// public interface IApplicationService { /// /// 头像 /// byte[] Photo { get; set; } /// /// 用户名和姓氏 /// string UserNameAndSurname { get; set; } /// /// 邮箱地址 /// string EmailAddress { get; set; } /// /// 应用程序信息 /// string ApplicationInfo { get; set; } /// /// 应用程序名称 /// string ApplicationName { get; set; } /// /// 显示个人资料照片 /// /// Task ShowProfilePhoto(); /// /// 显示个人信息 /// /// Task ShowMyProfile(); /// /// 设置应用程序信息 /// 备注: 用户名、头像、权限、应用程序名称版本等 /// Task GetApplicationInfo(); /// /// 刷新菜单 /// void RefreshAuthMenus(); /// /// 执行用户功能请求 /// /// void ExecuteUserAction(string key); } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Services/Account/UserConfigurationManager.cs ================================================ using AppFramework.ApiClient; using AppFramework.Shared; using AppFramework.Configuration; using AppFramework.MultiTenancy; using Prism.Ioc; using System; using System.Globalization; using System.Linq; using System.Threading.Tasks; using Abp.Web.Models.AbpUserConfiguration; using AppFramework.Authorization.Users.Profile; using AppFramework.Shared.Services; using System.Diagnostics; namespace AppFramework.Admin.Services.Account { public class UserConfigurationManager { private static readonly Lazy appContext = new Lazy( ContainerLocator.Container.Resolve); private static IAccessTokenManager AccessTokenManager => ContainerLocator.Container.Resolve(); public static async Task GetIfNeedsAsync(Func failCallback = null) { if (appContext.Value.Configuration != null) return; await GetAsync(failCallback); } public static async Task GetAsync(Func failCallback = null) { var userConfigurationService = ContainerLocator.Container.Resolve(); await WebRequest.Execute(() => userConfigurationService.GetAsync(AccessTokenManager.IsUserLoggedIn), GetConfigurationSuccessed, failCallback); } private static async Task GetConfigurationSuccessed(AbpUserConfigurationDto result) { appContext.Value.Configuration = result; SetCurrentCulture(); if (!result.MultiTenancy.IsEnabled) appContext.Value.SetAsTenant(TenantConsts.DefaultTenantName, TenantConsts.DefaultTenantId); if (AccessTokenManager.IsUserLoggedIn) { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); var chatService = ContainerLocator.Container.Resolve(); await chatService.ConnectAsync(); stopWatch.Stop(); } var profileAppService = ContainerLocator.Container.Resolve(); var currentLanguage = appContext.Value.CurrentLanguage; if (currentLanguage != null && currentLanguage.Name != result.Localization.CurrentLanguage.Name) { if (AccessTokenManager.IsUserLoggedIn) { //如果授权成功后, 当前客户端选择的语言和后端的不一致,那么修改默认语言 await profileAppService.ChangeLanguage(new Authorization.Users.Dto.ChangeUserLanguageDto() { LanguageName = currentLanguage.Name }); await GetAsync(); } } else { appContext.Value.CurrentLanguage = result.Localization.CurrentLanguage; } WarnIfUserHasNoPermission(); } private static void WarnIfUserHasNoPermission() { if (!AccessTokenManager.IsUserLoggedIn) { return; } var hasAnyPermission = appContext.Value.Configuration.Auth.GrantedPermissions != null && appContext.Value.Configuration.Auth.GrantedPermissions.Any(); if (!hasAnyPermission) { //UserDialogHelper.Warn("NoPermission"); } } /// /// 设置应用的区域化配置 /// private static void SetCurrentCulture() { var locale = ContainerLocator.Container.Resolve(); var userCulture = GetUserCulture(locale); locale.SetLocale(userCulture); } /// /// 获取用户的区域化信息 /// /// /// private static CultureInfo GetUserCulture(ILocaleCulture locale) { if (appContext.Value.Configuration.Localization.CurrentCulture.Name == null) return locale.GetCurrentCultureInfo(); try { return new CultureInfo(appContext.Value.Configuration.Localization.CurrentCulture.Name); } catch (CultureNotFoundException) { return locale.GetCurrentCultureInfo(); } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Services/Features/FeaturesService.cs ================================================ using Abp.Application.Services.Dto; using AppFramework.Editions.Dto; using AppFramework.Admin.Models; using AppFramework.Shared.Services.Mapper; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using CommunityToolkit.Mvvm.ComponentModel; namespace AppFramework.Admin.Services { [INotifyPropertyChanged] public partial class FeaturesService : IFeaturesService { private readonly IAppMapper mapper; public FeaturesService(IAppMapper mapper) { this.mapper = mapper; } private ObservableCollection features; public ObservableCollection Features { get { return features; } set { features = value; OnPropertyChanged(); } } private ObservableCollection selectedItems; public ObservableCollection SelectedItems { get { return selectedItems; } set { selectedItems = value; OnPropertyChanged(); } } public void CreateFeatures(List features, List featureValues) { if (features == null) throw new NullReferenceException(nameof(features)); if (featureValues == null) throw new NullReferenceException(nameof(featureValues)); var flats = mapper.Map>(features); Features = CreateFeatureTrees(flats, null); SelectedItems = GetSelectedItems(Features, featureValues); } public List GetSelectedItems() { List items = new List(); GetFeatures(Features, ref items); foreach (FlatFeatureModel model in SelectedItems) { var item = items.FirstOrDefault(t => t.Name.Equals(model.Name)); if (item != null) item.Value = "true"; } return items; } /// /// 获取选中的功能节点 /// /// /// private void GetFeatures(ObservableCollection flatFeatures, ref List featureValues) { foreach (var item in flatFeatures) { if (bool.TryParse(item.DefaultValue, out bool result)) featureValues.Add(new NameValueDto(item.Name, "false")); else featureValues.Add(new NameValueDto(item.Name, item.DefaultValue)); GetFeatures(item.Items, ref featureValues); } } /// /// 创建功能结点目录树 /// /// /// /// private ObservableCollection CreateFeatureTrees(List flatFeatureModels, string parentName) { var trees = new ObservableCollection(); var nodes = flatFeatureModels.Where(q => q.ParentName == parentName).ToArray(); foreach (var node in nodes) { node.Items = CreateFeatureTrees(flatFeatureModels, node.Name); trees.Add(node); } return trees; } private ObservableCollection GetSelectedItems(ObservableCollection features, List featureValues) { var items = new ObservableCollection(); foreach (var f in featureValues) { var item = GetSelectedItems(features, f); if (item != null) { item.IsChecked = true; items.Add(item); } } return items; } FlatFeatureModel GetSelectedItems(ObservableCollection flatFeatures, NameValueDto nameValue) { FlatFeatureModel model = null; foreach (var flat in flatFeatures) { if (flat.Name.Equals(nameValue.Name) && flat.Items.Count == 0) { bool isAdd = false; if (bool.TryParse(nameValue.Value, out bool result)) isAdd = result; else isAdd = true; if (isAdd) { model = flat; break; } } model = GetSelectedItems(flat.Items, nameValue); if (model != null) break; } return model; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Services/Features/IFeaturesService.cs ================================================ using Abp.Application.Services.Dto; using AppFramework.Editions.Dto; using System.Collections.Generic; namespace AppFramework.Admin.Services { public interface IFeaturesService { void CreateFeatures(List features, List featureValues); List GetSelectedItems(); } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Services/Mapper/AppMapper.cs ================================================ using AppFramework.Shared.Services.Mapper; using AutoMapper; using System; namespace AppFramework.Admin.Mapper { public class AppMapper : IAppMapper { public AppMapper() { var configuration = new MapperConfiguration(configure => { var assemblys = AppDomain.CurrentDomain.GetAssemblies(); configure.AddMaps(assemblys); }); Current = configuration.CreateMapper(); } public IMapper Current { get; } public TDestination Map(object source) => Current.Map(source); } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Services/Navigation/INavigationMenuService.cs ================================================ using AppFramework.Shared.Models; using System.Collections.Generic; using System.Collections.ObjectModel; namespace AppFramework.Admin.Services { public interface INavigationMenuService { ObservableCollection GetAuthMenus(Dictionary permissions); } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Services/Navigation/NavigationMenuService.cs ================================================ using AppFramework.Shared.Models; using System.Collections.Generic; using System.Collections.ObjectModel; using AppFramework.Shared; namespace AppFramework.Admin.Services { public class NavigationMenuService : INavigationMenuService { private ObservableCollection GetMenuItems() { return new ObservableCollection() { new NavigationItem("home","Administration","",AppPermissions.Administration,new ObservableCollection() { new NavigationItem("dashboard","Dashboard", AppViews.Dashboard, AppPermissions.HostDashboard), new NavigationItem("organization","OrganizationUnits",AppViews.Organization,AppPermissions.OrganizationUnits), new NavigationItem("role","Roles",AppViews.Role,AppPermissions.Roles), new NavigationItem("user","Users",AppViews.User,AppPermissions.Users), new NavigationItem("auditlog","AuditLogs",AppViews.AuditLog,AppPermissions.AuditLogs), new NavigationItem("property","DynamicProperties",AppViews.DynamicProperty,AppPermissions.DynamicProperties), new NavigationItem("language","Languages",AppViews.Language,AppPermissions.Languages), new NavigationItem("version", "VersionManager", AppViews.Version, AppPermissions.Versions), new NavigationItem("edition","Editions",AppViews.Edition,AppPermissions.Editions), }), new NavigationItem("tenant","Tenants",AppViews.Tenant,AppPermissions.Tenants), new NavigationItem("visual", "VisualSettings", AppViews.Visual, AppPermissions.Administration), new NavigationItem("setting", "Settings", AppViews.Setting, AppPermissions.HostSettings), new NavigationItem("demo","Demos",AppViews.Demo,AppPermissions.AbpDemos), new NavigationItem("demo","UiComponents",AppViews.UiComponents,AppPermissions.DemoUiComponents) }; } /// /// 获取权限菜单 /// /// /// public ObservableCollection GetAuthMenus(Dictionary permissions) { var navigationItems = GetMenuItems(); var authorizedMenuItems = new ObservableCollection(); foreach (var item in navigationItems) { //转换特定地区语言的标题 item.Title = Local.Localize(item.Title); if (CheckPressions(item.RequiredPermissionName)) { if (item.Items != null) { var subItems = new ObservableCollection(); foreach (var submenuItem in item.Items) { if (CheckPressions(submenuItem.RequiredPermissionName)) { submenuItem.Title = Local.Localize(submenuItem.Title); subItems.Add(submenuItem); } } item.Items = subItems; } authorizedMenuItems.Add(item); } } return authorizedMenuItems; bool CheckPressions(string requiredPermissionName) { if (string.IsNullOrWhiteSpace(requiredPermissionName) || (permissions != null && permissions.ContainsKey(requiredPermissionName))) { return true; } return false; } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Services/Navigation/NavigationService.cs ================================================ using AppFramework.Admin; using AppFramework.Shared; using CommunityToolkit.Mvvm.ComponentModel; using Prism.Regions; using System.Linq; using System.Windows.Controls; namespace AppFramework.Admin.Services { [INotifyPropertyChanged] public partial class NavigationService { private readonly IRegionManager regionManager; private IRegion NavigationRegion => regionManager.Regions[AppRegions.Main]; private int selectedIndex; public int SelectedIndex { get { return selectedIndex; } set { selectedIndex = value; OnPropertyChanged(); } } public NavigationService(IRegionManager regionManager) { this.regionManager = regionManager; } public void Navigate(string pageName, NavigationParameters navigationParameters = null) { if (string.IsNullOrWhiteSpace(pageName)) return; var view = NavigationRegion.Views.FirstOrDefault(q => q.GetType().Name.Equals(pageName)); if (view == null) { NavigationRegion.RequestNavigate(pageName, NavigateionCallBack, navigationParameters); } else { SelectedIndex = NavigationRegion.Views.IndexOf(view); } } public void RemoveView(object view) { if (NavigationRegion.Views.Contains(view)) { /* * 关闭Tab后调用OnNavigatedFrom,如需手动释放资源请在 OnNavigatedFrom 中处理 */ if (view is UserControl viewControl && viewControl.DataContext is INavigationAware navigationAware) navigationAware.OnNavigatedFrom(null); NavigationRegion.Remove(view); } } public void RemoveView(string pageName) { var view = NavigationRegion.Views.FirstOrDefault(q => q.GetType().Name.Equals(pageName)); if (view != null) { /* * 关闭Tab后调用OnNavigatedFrom,如需手动释放资源请在 OnNavigatedFrom 中处理 */ if (view is UserControl viewControl && viewControl.DataContext is INavigationAware navigationAware) navigationAware.OnNavigatedFrom(null); NavigationRegion.Remove(view); } } private void NavigateionCallBack(NavigationResult navigationResult) { if (navigationResult.Result != null && !(bool)navigationResult.Result) { #if DEBUG System.Diagnostics.Debug.WriteLine(navigationResult.Error.Message); #endif AppLogs.Error(navigationResult.Error); } else { SelectedIndex = NavigationRegion.Views.Count() - 1; } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Services/Navigation/NavigationSingleMenuService.cs ================================================ using AppFramework.Shared.Models; using System.Collections.Generic; using System.Collections.ObjectModel; using AppFramework.Shared; namespace AppFramework.Admin.Services { public class NavigationSingleMenuService : INavigationMenuService { private ObservableCollection GetMenuItems() { return new ObservableCollection() { new NavigationItem("dashboard","Dashboard", AppViews.Dashboard, AppPermissions.HostDashboard), new NavigationItem("organization","OrganizationUnits",AppViews.Organization,AppPermissions.OrganizationUnits), new NavigationItem("role","Roles",AppViews.Role,AppPermissions.Roles), new NavigationItem("user","Users",AppViews.User,AppPermissions.Users), new NavigationItem("auditlog","AuditLogs",AppViews.AuditLog,AppPermissions.AuditLogs), new NavigationItem("property","DynamicProperties",AppViews.DynamicProperty,AppPermissions.DynamicProperties), new NavigationItem("language","Languages",AppViews.Language,AppPermissions.Languages), new NavigationItem("version", "VersionManager", AppViews.Version, AppPermissions.Versions), new NavigationItem("edition","Editions",AppViews.Edition,AppPermissions.Editions), new NavigationItem("tenant","Tenants",AppViews.Tenant,AppPermissions.Tenants), new NavigationItem("visual", "VisualSettings", AppViews.Visual, AppPermissions.Administration), new NavigationItem("setting", "Settings", AppViews.Setting, AppPermissions.HostSettings), new NavigationItem("demo","DemoUiComponents",AppViews.Demo,AppPermissions.DemoUiComponents) }; } /// /// 获取权限菜单 /// /// /// public ObservableCollection GetAuthMenus(Dictionary permissions) { var navigationItems = GetMenuItems(); var authorizedMenuItems = new ObservableCollection(); foreach (var item in navigationItems) { //转换特定地区语言的标题 item.Title = Local.Localize(item.Title); if (CheckPressions(item.RequiredPermissionName)) { if (item.Items != null) { var subItems = new ObservableCollection(); foreach (var submenuItem in item.Items) { if (CheckPressions(submenuItem.RequiredPermissionName)) { submenuItem.Title = Local.Localize(submenuItem.Title); subItems.Add(submenuItem); } } item.Items = subItems; } authorizedMenuItems.Add(item); } } return authorizedMenuItems; bool CheckPressions(string requiredPermissionName) { if (string.IsNullOrWhiteSpace(requiredPermissionName) || (permissions != null && permissions.ContainsKey(requiredPermissionName))) { return true; } return false; } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Services/Notification/NotificationService.cs ================================================ using Abp.Notifications; using AppFramework.Shared; using AppFramework.Notifications; using AppFramework.Notifications.Dto; using Prism.Mvvm; using System.Collections.ObjectModel; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; namespace AppFramework.Admin.Services.Notification { [INotifyPropertyChanged] public partial class NotificationService { public NotificationService(INotificationAppService appService, NavigationService navigationService) { this.appService = appService; this.navigationService = navigationService; items = new ObservableCollection(); input = new GetUserNotificationsInput() { MaxResultCount = 4, State = UserNotificationState.Unread }; } private readonly INotificationAppService appService; private readonly NavigationService navigationService; private ObservableCollection items; public ObservableCollection Items { get { return items; } set { items = value; OnPropertyChanged(); } } public GetUserNotificationsInput input; private bool isunRead; public bool IsUnRead { get { return isunRead; } set { isunRead = value; OnPropertyChanged(); } } public async Task GetNotifications() { UpdateDisplayContent(); await WebRequest.Execute(() => appService.GetUserNotifications(input), async output => { Items.Clear(); IsUnRead = output.UnreadCount > 0 ? true : false; foreach (var item in output.Items) Items.Add(item); await Task.CompletedTask; }); } public void Settings() { } public void SeeAllNotificationsPage() { navigationService.Navigate(AppViews.Notification); } public async void SetAllNotificationsAsRead() { await appService.SetAllNotificationsAsRead().WebAsync(GetNotifications); } public void SetNotificationAsRead() { } #region Display private string title; private string setAllAsRead; private string seeAllNotifications; public string Title { get { return title; } set { title = value; OnPropertyChanged(); } } public string SetAllAsRead { get { return setAllAsRead; } set { setAllAsRead = value; OnPropertyChanged(); } } public string SeeAllNotifications { get { return seeAllNotifications; } set { seeAllNotifications = value; OnPropertyChanged(); } } private void UpdateDisplayContent() { Title = Local.Localize("Notifications"); SetAllAsRead = Local.Localize("SetAllAsRead"); SeeAllNotifications = Local.Localize("SeeAllNotifications"); } #endregion } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Services/Permission/IPermissionTreesService.cs ================================================ using AppFramework.Authorization.Permissions.Dto; using System; using System.Collections.Generic; using System.Collections.ObjectModel; namespace AppFramework.Admin.Services { /// /// 权限树生成接口 /// public interface IPermissionTreesService { void CreatePermissionTrees(List permissions, List grantedPermissionNames); List GetSelectedItems(); ObservableCollection SelectedItems { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Services/Permission/PermissionPorxyService.cs ================================================ using AppFramework.Shared; using AppFramework.Shared.Services.Permission; using Prism.Mvvm; using System; using System.Collections.ObjectModel; using System.Linq; namespace AppFramework.Admin.Services { public class PermissionPorxyService : BindableBase, IPermissionPorxyService { public PermissionPorxyService(IPermissionService permissionService) { permissions = new ObservableCollection(); this.permissionService = permissionService; } private ObservableCollection permissions; private readonly IPermissionService permissionService; public ObservableCollection Permissions { get { return permissions; } } public void Execute(string key) { var item = Permissions.FirstOrDefault(t => t.Key.Equals(key)); if (item != null) item.Action?.Invoke(); } public void Generate(PermissionItem[] items) { if (items == null) throw new ArgumentNullException("items"); Permissions.Clear(); foreach (var item in items) { if (permissionService.HasPermission(item.Key)) Permissions.Add(item); } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Services/Permission/PermissionService.cs ================================================ using AppFramework.ApiClient; using AppFramework.Shared; using System; namespace AppFramework.Admin.Services { public class PermissionService : IPermissionService { private readonly IApplicationContext appContext; public PermissionService(IApplicationContext appContext) { this.appContext = appContext; } public bool HasPermission(string key) { if (appContext.Configuration.Auth.GrantedPermissions.TryGetValue(key, out var permissionValue)) return string.Equals(permissionValue, "true", StringComparison.OrdinalIgnoreCase); return false; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Services/Permission/PermissionTreesService.cs ================================================ using AppFramework.Authorization.Permissions.Dto; using AppFramework.Admin.Models; using AppFramework.Shared.Services.Mapper; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using CommunityToolkit.Mvvm.ComponentModel; namespace AppFramework.Admin.Services { [INotifyPropertyChanged] public partial class PermissionTreesService : IPermissionTreesService { private readonly IAppMapper mapper; public PermissionTreesService(IAppMapper mapper) { this.mapper = mapper; } private ObservableCollection permissions; public ObservableCollection Permissions { get { return permissions; } set { permissions = value; OnPropertyChanged(); } } private ObservableCollection selectedItems; public ObservableCollection SelectedItems { get { return selectedItems; } set { selectedItems = value; OnPropertyChanged(); } } public void CreatePermissionTrees(List permissions, List grantedPermissionNames) { if (permissions == null) throw new NullReferenceException(nameof(permissions)); if (grantedPermissionNames == null) throw new NullReferenceException(nameof(grantedPermissionNames)); var flats = mapper.Map>(permissions); Permissions = flats.CreateTrees(null); SelectedItems = Permissions.GetSelectedItems(grantedPermissionNames); } public List GetSelectedItems() { if (SelectedItems == null && SelectedItems.Count == 0) return null; return SelectedItems.Select(t => (t as PermissionModel)?.Name).ToList(); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Services/ServiceExtensions.cs ================================================ using Prism.Ioc; using AppFramework.Admin.Services; using AppFramework.Admin.Services.Account; using AppFramework.Admin.Services.Notification; using AppFramework.ApiClient; using AppFramework.Shared; using AppFramework.Shared.Services; using AppFramework.Shared.Services.Mapper; using AppFramework.Shared.Services.App; using AppFramework.Admin.Mapper; using AppFramework.Admin.Update; namespace AppFramework.Admin { public static class ServiceExtensions { public static void AddServices(this IContainerRegistry services) { services.RegisterSingleton(); services.RegisterSingleton(); services.RegisterSingleton(); services.RegisterSingleton(); services.RegisterSingleton(); services.RegisterSingleton(); services.RegisterSingleton(); services.RegisterScoped(); services.Register(); services.RegisterScoped(); services.RegisterSingleton(); services.RegisterSingleton(); services.RegisterSingleton(); services.RegisterSingleton(); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Services/Update/UpdateService.cs ================================================ using AppFramework.ApiClient; using AppFramework.Shared; using AppFramework.Shared.Services.App; using AppFramework.Version; using AppFramework.Version.Dtos; using AutoUpdaterDotNET; using System; using System.Reflection; using System.Threading.Tasks; namespace AppFramework.Admin.Update { public class UpdateService : IUpdateService { private readonly IAbpVersionsAppService appService; private readonly string CurrentVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString(); public UpdateService(IAbpVersionsAppService appService) { this.appService = appService; } public async Task CheckVersion() { await WebRequest.Execute(() => appService.CheckVersion(new AppFramework.Version.Dtos.CheckVersionInput() { Version = CurrentVersion, ApplicationName = AppSharedConsts.AppName }), CheckVersionFinish); } private async Task CheckVersionFinish(UpdateFileOutput output) { if (output == null || !output.IsNewVersion) return; AutoUpdater.ShowSkipButton = false; AutoUpdater.ShowRemindLaterButton = false; AutoUpdater.LetUserSelectRemindLater = false; AutoUpdater.InstallationPath = Environment.CurrentDirectory; AutoUpdater.ReportErrors = true; AutoUpdater.ShowUpdateForm(new UpdateInfoEventArgs() { ChangelogURL = output.ChangelogURL, InstalledVersion = new System.Version(CurrentVersion), CurrentVersion = $"{AppSharedConsts.AppName} {output.Version}", DownloadURL = ApiUrlConfig.BaseUrl + output.DownloadURL, Mandatory = new Mandatory { Value = output.IsForced, MinimumVersion = output.MinimumVersion, }, CheckSum = new CheckSum() { Value = output.AlgorithmValue, HashingAlgorithm = output.HashingAlgorithm, } }); await Task.CompletedTask; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Validations/AdminValidatorExtensions.cs ================================================ using AppFramework.Admin.Models; using AppFramework.MultiTenancy.Dto; using AppFramework.Shared.Models.Configuration; using AppFramework.Admin.Validations; using FluentValidation; using Prism.Ioc; namespace AppFramework.Admin { public static class AdminValidatorExtensions { public static void AddValidators(this IContainerRegistry services) { services.RegisterScoped, UserCreateOrUpdateValidator>(); services.RegisterScoped, OrganizationUnitValidator>(); services.RegisterScoped, CreateTenantValidator>(); services.RegisterScoped, UpdateTenantValidator>(); services.RegisterScoped, CreateEditionValidator>(); services.RegisterScoped, SettingsValidator>(); services.RegisterScoped, VersionValidator>(); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Validations/EditionValidator.cs ================================================ using AppFramework.Admin.Models; using AppFramework.Shared.Validations; using FluentValidation; namespace AppFramework.Admin.Validations { public class CreateEditionValidator : AbstractValidator { public CreateEditionValidator() { RuleFor(x => x.DisplayName).IsRequired(); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Validations/OrganizationUnitValidator.cs ================================================ using Abp.Organizations; using AppFramework.Admin.Models; using AppFramework.Shared.Validations; using FluentValidation; namespace AppFramework.Admin.Validations { public class OrganizationUnitValidator : AbstractValidator { public OrganizationUnitValidator() { RuleFor(x => x.DisplayName).IsRequired().MaxLength(OrganizationUnit.MaxDisplayNameLength); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Validations/SettingsValidator.cs ================================================ using AppFramework.Shared.Models.Configuration; using FluentValidation; namespace AppFramework.Admin.Validations { public class SettingsValidator : AbstractValidator { public SettingsValidator() { //默认邮箱地址格式 RuleFor(x => x.Email.DefaultFromAddress).EmailAddress(); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Validations/TenantValidator.cs ================================================ using Abp.Authorization.Users; using Abp.MultiTenancy; using AppFramework.MultiTenancy; using AppFramework.MultiTenancy.Dto; using AppFramework.Shared.Validations; using FluentValidation; namespace AppFramework.Admin.Validations { public class CreateTenantValidator : AbstractValidator { public CreateTenantValidator() { RuleFor(x => x.TenancyName).IsRequired().Regular(TenantConsts.TenancyNameRegex).MaxLength(AbpTenantBase.MaxTenancyNameLength); RuleFor(x => x.Name).IsRequired().MaxLength(AbpTenantBase.MaxNameLength); RuleFor(x => x.AdminEmailAddress).IsRequired().Email().MaxLength(AbpUserBase.MaxEmailAddressLength); RuleFor(x => x.AdminPassword).MaxLength(AbpUserBase.MaxPasswordLength); RuleFor(x => x.ConnectionString).MaxLength(AbpTenantBase.MaxConnectionStringLength); } } public class UpdateTenantValidator : AbstractValidator { public UpdateTenantValidator() { RuleFor(x => x.TenancyName).IsRequired().Regular(TenantConsts.TenancyNameRegex).MaxLength(AbpTenantBase.MaxTenancyNameLength); RuleFor(x => x.Name).IsRequired().MaxLength(AbpTenantBase.MaxNameLength); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Validations/UserValidator.cs ================================================ using Abp.Authorization.Users; using AppFramework.Admin.Models; using AppFramework.Authorization.Users; using FluentValidation; using AppFramework.Shared.Validations; namespace AppFramework.Admin.Validations { public class UserCreateOrUpdateValidator : AbstractValidator { public UserCreateOrUpdateValidator() { RuleFor(x => x.User.Name).IsRequired().MaxLength(AbpUserBase.MaxNameLength); RuleFor(x => x.User.Surname).IsRequired().MaxLength(AbpUserBase.MaxSurnameLength); RuleFor(x => x.User.UserName).IsRequired().MaxLength(AbpUserBase.MaxUserNameLength); RuleFor(x => x.User.EmailAddress).IsRequired().Email().MaxLength(AbpUserBase.MaxEmailAddressLength); RuleFor(x => x.User.PhoneNumber).MaxLength(UserConsts.MaxPhoneNumberLength); RuleFor(x => x.User.Password).MaxLength(AbpUserBase.MaxPlainPasswordLength); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/Validations/VersionValidator.cs ================================================ using AppFramework.Admin.Models; using AppFramework.Shared.Validations; using FluentValidation; namespace AppFramework.Admin.Validations { public class VersionValidator : AbstractValidator { public VersionValidator() { RuleFor(x => x.Name).IsRequired(); RuleFor(x => x.Version).IsRequired(); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Account/ChangeAvatarViewModel.cs ================================================ using AppFramework.Authorization.Users.Profile; using AppFramework.Authorization.Users.Profile.Dto; using AppFramework.Dto; using AppFramework.Shared; using Microsoft.Win32; using Prism.Commands; using Prism.Services.Dialogs; using System; using System.IO; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels { public class ChangeAvatarViewModel : HostDialogViewModel { public ChangeAvatarViewModel(IProfileAppService profileAppService, ProxyProfileControllerService profileControllerService) { SelectedFileCommand = new DelegateCommand(SelectedFile); this.profileAppService = profileAppService; this.profileControllerService = profileControllerService; } private string imageFilePath; private readonly IProfileAppService profileAppService; private readonly ProxyProfileControllerService profileControllerService; public string IamgeFilePath { get { return imageFilePath; } set { imageFilePath = value; OnPropertyChanged(); } } private void SelectedFile() { OpenFileDialog fileDialog = new OpenFileDialog(); fileDialog.Filter = "图片文件(*.jpg;*.jpeg;*.png)|*.jpg;*.jpeg;*.png"; var dialogResult = (bool)fileDialog.ShowDialog(); if (dialogResult) { IamgeFilePath = fileDialog.FileName; } } public override async Task Save() { if (!string.IsNullOrEmpty(IamgeFilePath)) { string fileName = "ProfilePicture"; var photoAsBytes = File.ReadAllBytes(IamgeFilePath); await SetBusyAsync(async () => { await UpdateProfilePhoto(photoAsBytes, fileName).WebAsync(() => { base.Save(photoAsBytes); return Task.CompletedTask; }); }); } } private async Task UpdateProfilePhoto(byte[] photoAsBytes, string fileName) { var fileToken = Guid.NewGuid().ToString(); using (Stream photoStream = new MemoryStream(photoAsBytes)) { await profileControllerService.UploadProfilePicture(content => { content.AddFile("file", photoStream, fileName); content.AddString(nameof(FileDto.FileToken), fileToken); content.AddString(nameof(FileDto.FileName), fileName); }).ContinueWith(uploadResult => { if (uploadResult == null) return; profileAppService.UpdateProfilePicture(new UpdateProfilePictureInput { FileToken = fileToken }); }); } } public DelegateCommand SelectedFileCommand { get; private set; } public override void OnDialogOpened(IDialogParameters parameters) { } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Account/ChangePasswordViewModel.cs ================================================ using AppFramework.Authorization.Users.Profile; using AppFramework.Authorization.Users.Profile.Dto; using AppFramework.Shared; using Prism.Commands; using Prism.Services.Dialogs; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels { public class ChangePasswordViewModel : HostDialogViewModel { public DelegateCommand SendChangePasswordCommand { get; private set; } private readonly IProfileAppService profileAppService; private bool _isChangePasswordEnabled; public ChangePasswordViewModel(IProfileAppService profileAppService) { this.profileAppService = profileAppService; SendChangePasswordCommand = new DelegateCommand(SendChangePasswordAsync); } private string _currentPassword; public string CurrentPassword { get => _currentPassword; set { _currentPassword = value; SetChangePasswordButtonEnabled(); OnPropertyChanged(); } } private string _newPassword; public string NewPassword { get => _newPassword; set { _newPassword = value; SetChangePasswordButtonEnabled(); OnPropertyChanged(); } } private string _newPasswordRepeat; public string NewPasswordRepeat { get => _newPasswordRepeat; set { _newPasswordRepeat = value; SetChangePasswordButtonEnabled(); OnPropertyChanged(); } } public bool IsChangePasswordEnabled { get => _isChangePasswordEnabled; set { _isChangePasswordEnabled = value; OnPropertyChanged(); } } public void SetChangePasswordButtonEnabled() { IsChangePasswordEnabled = !string.IsNullOrWhiteSpace(CurrentPassword) && !string.IsNullOrWhiteSpace(NewPassword) && !string.IsNullOrWhiteSpace(NewPasswordRepeat); } private async void SendChangePasswordAsync() { if (NewPassword != NewPasswordRepeat) { DialogHelper.Info("", Local.Localize(AppLocalizationKeys.PasswordsDontMatch)); } else { await SetBusyAsync(async () => { await profileAppService.ChangePassword(new ChangePasswordInput { CurrentPassword = CurrentPassword, NewPassword = NewPassword }) .WebAsync(PasswordChangedAsync); }); } } private async Task PasswordChangedAsync() { DialogHelper.Info(Local.Localize(AppLocalizationKeys.YourPasswordHasChangedSuccessfully), Local.Localize(AppLocalizationKeys.ChangePassword)); await Task.CompletedTask; } public override void OnDialogOpened(IDialogParameters parameters) { } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Account/CreateLinkedAccountViewModel.cs ================================================ using AppFramework.Authorization.Users; using AppFramework.Shared; using Prism.Services.Dialogs; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels { public class CreateLinkedAccountViewModel : HostDialogViewModel { public CreateLinkedAccountViewModel(IUserLinkAppService appService) { this.appService = appService; } private string userName; public string UserName { get { return userName; } set { userName = value; OnPropertyChanged(); } } private string tenancyName; public string TenancyName { get { return tenancyName; } set { tenancyName = value; OnPropertyChanged(); } } private string password; private readonly IUserLinkAppService appService; public string Password { get { return password; } set { password = value; OnPropertyChanged(); } } public override async Task Save() { await appService.LinkToUser(new Authorization.Users.Dto.LinkToUserInput() { TenancyName = TenancyName, UsernameOrEmailAddress = UserName, Password = Password }).WebAsync(base.Save); } public override void OnDialogOpened(IDialogParameters parameters) { } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Account/EmailActivationViewModel.cs ================================================ using AppFramework.Authorization.Accounts; using AppFramework.Authorization.Accounts.Dto; using AppFramework.Shared; using AppFramework.Admin.ViewModels.Shared; using Prism.Commands; using Prism.Services.Dialogs; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels { public class EmailActivationViewModel : HostDialogViewModel { public DelegateCommand SendEmailActivationCommand { get; private set; } private readonly IAccountAppService accountAppService; private bool _isEmailActivationEnabled; public EmailActivationViewModel(IAccountAppService accountAppService) { this.accountAppService = accountAppService; SendEmailActivationCommand = new DelegateCommand(SendEmailActivationAsync); } private string _emailAddress; public string EmailAddress { get => _emailAddress; set { _emailAddress = value; SetEmailActivationButtonEnabled(); OnPropertyChanged(); } } public bool IsEmailActivationEnabled { get => _isEmailActivationEnabled; set { _isEmailActivationEnabled = value; OnPropertyChanged(); } } public void SetEmailActivationButtonEnabled() { IsEmailActivationEnabled = !string.IsNullOrWhiteSpace(EmailAddress); } private async void SendEmailActivationAsync() { await SetBusyAsync(async () => { await accountAppService.SendEmailActivationLink(new SendEmailActivationLinkInput { EmailAddress = EmailAddress }).WebAsync(PasswordResetMailSentAsync); }); } private async Task PasswordResetMailSentAsync() { DialogHelper.Info(Local.Localize(AppLocalizationKeys.ActivationMailSentMessage), Local.Localize(AppLocalizationKeys.MailSent)); await Task.CompletedTask; } public override void OnDialogOpened(IDialogParameters parameters) { } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Account/ForgotPasswordViewModel.cs ================================================ using AppFramework.Authorization.Accounts; using AppFramework.Authorization.Accounts.Dto; using AppFramework.Shared; using AppFramework.Admin.ViewModels.Shared; using Prism.Commands; using Prism.Services.Dialogs; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels { public class ForgotPasswordViewModel : HostDialogViewModel { public DelegateCommand SendForgotPasswordCommand { get; private set; } private readonly IAccountAppService accountAppService; private bool _isForgotPasswordEnabled; public ForgotPasswordViewModel(IAccountAppService accountAppService) { this.accountAppService = accountAppService; SendForgotPasswordCommand = new DelegateCommand(SendForgotPasswordAsync); } private string _emailAddress; public string EmailAddress { get => _emailAddress; set { _emailAddress = value; SetEmailActivationButtonEnabled(); OnPropertyChanged(); } } public bool IsForgotPasswordEnabled { get => _isForgotPasswordEnabled; set { _isForgotPasswordEnabled = value; OnPropertyChanged(); } } public void SetEmailActivationButtonEnabled() { IsForgotPasswordEnabled = !string.IsNullOrWhiteSpace(EmailAddress); } private async void SendForgotPasswordAsync() { await SetBusyAsync(async () => { await accountAppService.SendPasswordResetCode(new SendPasswordResetCodeInput { EmailAddress = EmailAddress }).WebAsync(PasswordResetMailSentAsync); }); } private async Task PasswordResetMailSentAsync() { DialogHelper.Info(Local.Localize(AppLocalizationKeys.PasswordResetMailSentMessage), Local.Localize(AppLocalizationKeys.MailSent)); await base.Save(); } public override void OnDialogOpened(IDialogParameters parameters) { } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Account/LoginAttemptsViewModel.cs ================================================ using AppFramework.Authorization.Users; using AppFramework.Authorization.Users.Dto; using AppFramework.Shared; using AppFramework.Shared.Services; using AppFramework.Admin.ViewModels.Shared; using Prism.Commands; using Prism.Regions; using System; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels { public class LoginAttemptsViewModel : NavigationCurdViewModel { private readonly IUserLoginAppService appService; private GetLoginAttemptsInput input; public DelegateCommand SearchCommand { get; private set; } public DateTime? StartDate { get { return input.StartDate; } set { input.StartDate = value; OnPropertyChanged(); } } public DateTime? EndDate { get { return input.EndDate; } set { input.EndDate = value; OnPropertyChanged(); } } public string FilterText { get { return input.Filter; } set { input.Filter = value; OnPropertyChanged(); Search(); } } public LoginAttemptsViewModel(IUserLoginAppService appService) { this.appService = appService; Title = Local.Localize("LoginAttempts"); input = new GetLoginAttemptsInput() { Filter = "", MaxResultCount = AppConsts.DefaultPageSize, SkipCount = 0 }; StartDate=DateTime.Now.AddDays(-3); EndDate=DateTime.Now; SearchCommand = new DelegateCommand(Search); dataPager.OnPageIndexChangedEventhandler += UsersOnPageIndexChangedEventhandler; } private void Search() { dataPager.PageIndex = 0; } private async void UsersOnPageIndexChangedEventhandler(object sender, PageIndexChangedEventArgs e) { input.StartDate = StartDate.GetFirstDate(); input.EndDate = EndDate.GetLastDate(); input.SkipCount = e.SkipCount; input.MaxResultCount = e.PageSize; await GetUserLogins(input); } private async Task GetUserLogins(GetLoginAttemptsInput filter) { await SetBusyAsync(async () => { await appService.GetUserLoginAttempts(filter).WebAsync(dataPager.SetList); }); } public override async Task OnNavigatedToAsync(NavigationContext navigationContext = null) { await GetUserLogins(input); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Account/ManageLinkedAccountsViewModel.cs ================================================ using AppFramework.Authorization.Users; using AppFramework.Authorization.Users.Dto; using AppFramework.Shared; using AppFramework.Admin.Services; using Prism.Commands; using Prism.Services.Dialogs; using System.Threading.Tasks; using AppFramework.Shared.Services; namespace AppFramework.Admin.ViewModels { public class ManageLinkedAccountsViewModel : HostDialogViewModel { private readonly IUserLinkAppService appService; private readonly IHostDialogService dialog; public IDataPagerService dataPager { get; private set; } public GetLinkedUsersInput input; public DelegateCommand AddCommand { get; private set; } public DelegateCommand DeleteCommand { get; private set; } public DelegateCommand LoginUserCommand { get; private set; } public ManageLinkedAccountsViewModel(IUserLinkAppService appService, IDataPagerService dataPager, IHostDialogService dialog) { this.appService = appService; this.dataPager = dataPager; this.dialog = dialog; input = new GetLinkedUsersInput() { MaxResultCount = 10, }; AddCommand = new DelegateCommand(Add); DeleteCommand = new DelegateCommand(Delete); LoginUserCommand = new DelegateCommand(LoginUser); dataPager.OnPageIndexChangedEventhandler += DataPager_OnPageIndexChangedEventhandler; } private void LoginUser(LinkedUserDto obj) { //.. } private async void Delete(LinkedUserDto obj) { if (await dialog.Question( Local.Localize("LinkedUserDeleteWarningMessage", obj.Username), "ManageLinkedAccounts")) { await appService.UnlinkUser(new UnlinkUserInput() { TenantId = obj.TenantId, UserId = obj.Id }) .WebAsync(async () => await GetRecentlyUsedLinkedUsers(input)); } } private async void DataPager_OnPageIndexChangedEventhandler(object sender, PageIndexChangedEventArgs e) { input.SkipCount = e.SkipCount; input.MaxResultCount = e.PageSize; await GetRecentlyUsedLinkedUsers(input); } private async void Add() { var dialogResult = await dialog.ShowDialogAsync( AppViews.CreateLinkedAccount, null, "ManageLinkedAccounts"); if (dialogResult.Result == ButtonResult.OK) { await GetRecentlyUsedLinkedUsers(input); } } private async Task GetRecentlyUsedLinkedUsers(GetLinkedUsersInput filter) { await SetBusyAsync(async () => { await appService.GetLinkedUsers(filter).WebAsync(dataPager.SetList); }); } public override async void OnDialogOpened(IDialogParameters parameters) { await GetRecentlyUsedLinkedUsers(input); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Account/ManageNewUserViewModel.cs ================================================ using Abp.Application.Services.Dto; using AppFramework.Authorization.Users.Delegation; using AppFramework.Shared; using AppFramework.Common.Dto; using Prism.Commands; using Prism.Services.Dialogs; using System; using System.Threading.Tasks; using AppFramework.Common; using AppFramework.Shared.Services; namespace AppFramework.Admin.ViewModels { public class ManageNewUserViewModel : HostDialogViewModel { private readonly ICommonLookupAppService lookupAppService; private readonly IHostDialogService dialog; private readonly IUserDelegationAppService appService; public FindUsersInput input; public ManageNewUserViewModel(ICommonLookupAppService lookupAppService, IDataPagerService dataPager, IHostDialogService dialog, IUserDelegationAppService appService) { this.lookupAppService = lookupAppService; this.dataPager = dataPager; this.dialog = dialog; this.appService = appService; QueryCommand = new DelegateCommand(Query); ChooseCommand = new DelegateCommand(ChooseUser); input = new FindUsersInput() { MaxResultCount = 10, ExcludeCurrentUser = true }; dataPager.OnPageIndexChangedEventhandler += DataPager_OnPageIndexChangedEventhandler; ; } private async void DataPager_OnPageIndexChangedEventhandler(object sender, PageIndexChangedEventArgs e) { input.SkipCount = e.SkipCount; input.MaxResultCount = e.PageSize; await SetBusyAsync(async () => { await FindUsers(input); }); } public DelegateCommand ChooseCommand { get; private set; } public DelegateCommand QueryCommand { get; private set; } public IDataPagerService dataPager { get; private set; } public string Filter { get { return input.Filter; } set { input.Filter = value; OnPropertyChanged(); } } private void Query() { dataPager.PageIndex = 0; } private async void ChooseUser(NameValueDto obj) { var dialogResult = await dialog.ShowDialogAsync(AppViews.SelectDate, null, "ManageNewUser"); if (dialogResult.Result == ButtonResult.OK) { var startDate = dialogResult.Parameters.GetValue("StartDate"); var endDate = dialogResult.Parameters.GetValue("EndDate"); await appService.DelegateNewUser(new Authorization.Users.Delegation.Dto.CreateUserDelegationDto() { TargetUserId = Convert.ToInt64(obj.Value), StartTime = startDate.GetFirstDate(), EndTime = endDate.GetLastDate() }).WebAsync(base.Save); } } public override async void OnDialogOpened(IDialogParameters parameters) { await SetBusyAsync(async () => { await FindUsers(input); }); } private async Task FindUsers(FindUsersInput input) { await lookupAppService.FindUsers(input).WebAsync(dataPager.SetList); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Account/ManageUserDelegationsViewModel.cs ================================================ using Abp.Application.Services.Dto; using AppFramework.Authorization.Users.Delegation; using AppFramework.Authorization.Users.Delegation.Dto; using AppFramework.Shared; using Prism.Commands; using Prism.Services.Dialogs; using System.Threading.Tasks; using AppFramework.Shared.Services; namespace AppFramework.Admin.ViewModels { public class ManageUserDelegationsViewModel : HostDialogViewModel { private readonly IUserDelegationAppService appService; private readonly IHostDialogService dialog; public IDataPagerService dataPager { get; private set; } public DelegateCommand AddCommand { get; private set; } public DelegateCommand DeleteCommand { get; private set; } public GetUserDelegationsInput input; public ManageUserDelegationsViewModel( IUserDelegationAppService appService, IDataPagerService dataPager, IHostDialogService dialog) { this.appService = appService; this.dataPager = dataPager; this.dialog = dialog; AddCommand = new DelegateCommand(Add); DeleteCommand = new DelegateCommand(Delete); input = new GetUserDelegationsInput() { MaxResultCount = 10, }; } private async void Delete(UserDelegationDto obj) { if (await dialog.Question(Local.Localize("UserDelegationDeleteWarningMessage", obj.Username), "ManageUserDelegationsView")) { await appService.RemoveDelegation(new EntityDto(obj.Id)).WebAsync(GetDelegatedUsers); } } private async void Add() { var dialogResilt = await dialog.ShowDialogAsync(AppViews.ManageNewUser, null, "ManageUserDelegationsView"); if (dialogResilt.Result == ButtonResult.OK) { await GetDelegatedUsers(); } } private async Task GetDelegatedUsers() { await SetBusyAsync(async () => { await appService.GetDelegatedUsers(input).WebAsync(dataPager.SetList); }); } public override async void OnDialogOpened(IDialogParameters parameters) { await GetDelegatedUsers(); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Account/MyProfileViewModel.cs ================================================ using AppFramework.ApiClient; using AppFramework.Shared; using AppFramework.Admin.Models; using AppFramework.Admin.ViewModels.Shared; using Prism.Services.Dialogs; namespace AppFramework.Admin.ViewModels { public class MyProfileViewModel : HostDialogViewModel { private readonly IApplicationContext applicationContext; public MyProfileViewModel(IApplicationContext applicationContext) { this.applicationContext = applicationContext; } private UserLoginInfoModel userInfo; public UserLoginInfoModel UserInfo { get { return userInfo; } set { userInfo = value; OnPropertyChanged(); } } public override void OnDialogOpened(IDialogParameters parameters) { UserInfo = Map(applicationContext.LoginInfo.User); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Account/MySettingsViewModel.cs ================================================ using AppFramework.Shared; using Prism.Services.Dialogs; namespace AppFramework.Admin.ViewModels { public class MySettingsViewModel : HostDialogViewModel { public override void OnDialogOpened(IDialogParameters parameters) { } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Account/NotificationViewModel.cs ================================================ using Abp.Notifications; using AppFramework.Shared; using AppFramework.Notifications; using AppFramework.Notifications.Dto; using AppFramework.Admin.Services.Notification; using AppFramework.Admin.ViewModels.Shared; using Prism.Commands; using Prism.Regions; using System; using System.Threading.Tasks; using AppFramework.Shared.Services; namespace AppFramework.Admin.ViewModels { public class NotificationViewModel : NavigationCurdViewModel { private readonly INotificationAppService appService; private readonly NotificationService notificationService; public GetUserNotificationsInput input; public DelegateCommand SetNotificationAsReadCommand { get; private set; } public DelegateCommand SetAllNotificationsAsReadCommand { get; private set; } public DelegateCommand DeleteNotificationCommand { get; private set; } public DelegateCommand DeleteAllUserNotificationsCommand { get; private set; } public DateTime? StartDate { get { return input.StartDate; } set { input.StartDate = value; OnPropertyChanged(); } } public DateTime? EndDate { get { return input.EndDate; } set { input.EndDate = value; OnPropertyChanged(); } } private int selectedIndex; public int SelectedIndex { get { return selectedIndex; } set { selectedIndex = value; input.State = value == 0 ? null : UserNotificationState.Unread; OnPropertyChanged(); } } public NotificationViewModel(INotificationAppService appService, NotificationService notificationService) { Title = Local.Localize("Notifications"); this.appService = appService; this.notificationService = notificationService; var year = DateTime.Now.Year; var month = DateTime.Now.Month; var day = DateTime.Now.Day; input = new GetUserNotificationsInput() { StartDate = new DateTime(year, month, day - 7, 0, 0, 0), EndDate = new DateTime(year, month, day, 23, 59, 59), MaxResultCount = 10, }; dataPager.OnPageIndexChangedEventhandler += DataPager_OnPageIndexChangedEventhandler; DeleteAllUserNotificationsCommand = new DelegateCommand(DeleteAllUserNotifications); DeleteNotificationCommand = new DelegateCommand(DeleteNotification); SetNotificationAsReadCommand = new DelegateCommand(SetNotificationAsRead); SetAllNotificationsAsReadCommand = new DelegateCommand(notificationService.SetAllNotificationsAsRead); } private async void DeleteAllUserNotifications() { if (await dialog.Question(Local.Localize("DeleteListedNotificationsWarningMessage"))) { await appService.DeleteAllUserNotifications(new DeleteAllUserNotificationsInput() { StartDate = input.StartDate, EndDate = input.EndDate, State = input.State }).WebAsync(async () => await OnNavigatedToAsync()); } } private async void SetNotificationAsRead(UserNotification obj) { await appService.SetNotificationAsRead(new Abp.Application.Services.Dto.EntityDto() { Id = obj.Id }) .WebAsync(async () => await OnNavigatedToAsync()); } private async void DeleteNotification(UserNotification obj) { if (await dialog.Question(Local.Localize("NotificationDeleteWarningMessage"))) { await appService.DeleteNotification(new Abp.Application.Services.Dto.EntityDto() { Id = obj.Id }) .WebAsync(async () => await OnNavigatedToAsync()); } } private async void DataPager_OnPageIndexChangedEventhandler(object sender, PageIndexChangedEventArgs e) { input.StartDate = StartDate.GetFirstDate(); input.EndDate = EndDate.GetLastDate(); input.SkipCount = e.SkipCount; input.MaxResultCount = e.PageSize; await SetBusyAsync(async () => { await GetUserNotifications(input); }); } private async Task GetUserNotifications(GetUserNotificationsInput filter) { await appService.GetUserNotifications(filter).WebAsync(dataPager.SetList); } public override async Task OnNavigatedToAsync(NavigationContext navigationContext = null) { dataPager.PageIndex = 0; await Task.CompletedTask; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Account/SelectDateRangeViewModel.cs ================================================ using AppFramework.Shared; using Prism.Services.Dialogs; using System; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels { public class SelectDateRangeViewModel : HostDialogViewModel { private DateTime? startDate; public DateTime? StartDate { get { return startDate; } set { startDate = value; OnPropertyChanged(); } } private DateTime? endDate; public DateTime? EndDate { get { return endDate; } set { endDate = value; OnPropertyChanged(); } } public override async Task Save() { if (StartDate == null || EndDate == null) return; DialogParameters param = new DialogParameters(); param.Add("StartDate", StartDate); param.Add("EndDate", EndDate); base.Save(param); await Task.CompletedTask; } public override void OnDialogOpened(IDialogParameters parameters) { } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Account/SendTwoFactorCodeViewModel.cs ================================================ using AppFramework.ApiClient.Models; using AppFramework.Authorization.Accounts; using AppFramework.Admin.Services; using Prism.Commands; using Prism.Services.Dialogs; using System.Collections.Generic; using System.Linq; using AppFramework.Shared; using AppFramework.Shared.Services; namespace AppFramework.Admin.ViewModels { public class SendTwoFactorCodeViewModel : HostDialogViewModel { private readonly IHostDialogService dialog; private readonly ProxyTokenAuthControllerService proxyTokenAuthControllerService; private readonly IAccountService accountService; public DelegateCommand SendSecurityCodeCommand { get; private set; } public SendTwoFactorCodeViewModel(IHostDialogService dialog, ProxyTokenAuthControllerService proxyTokenAuthControllerService, IAccountService accountService) { this.dialog = dialog; this.proxyTokenAuthControllerService = proxyTokenAuthControllerService; this.accountService = accountService; twoFactorAuthProviders = new List(); SendSecurityCodeCommand = new DelegateCommand(SendSecurityCodeAsync); } private List twoFactorAuthProviders; public List TwoFactorAuthProviders { get => twoFactorAuthProviders; set { twoFactorAuthProviders = value; OnPropertyChanged(); } } private string selectedProvider; public string SelectedProvider { get => selectedProvider; set { selectedProvider = value; OnPropertyChanged(); } } public override void OnDialogOpened(IDialogParameters parameters) { accountService.AuthenticateResultModel = parameters .GetValue("Value"); TwoFactorAuthProviders = accountService .AuthenticateResultModel.TwoFactorAuthProviders.ToList(); SelectedProvider = TwoFactorAuthProviders.FirstOrDefault()??""; } private async void SendSecurityCodeAsync() { await SetBusyAsync(async () => { await proxyTokenAuthControllerService.SendTwoFactorAuthCode( accountService.AuthenticateResultModel.UserId, selectedProvider ); }); var promptResult = await dialog.ShowDialogAsync(""); if (promptResult.Result == ButtonResult.OK) { var twoFactorVerificationCode = promptResult.Parameters.GetValue("Value"); if (!string.IsNullOrEmpty(twoFactorVerificationCode)) { accountService.AuthenticateModel.TwoFactorVerificationCode = twoFactorVerificationCode; accountService.AuthenticateModel.RememberClient = true; await SetBusyAsync(async () => { await accountService.LoginUserAsync(); }); } } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Auditlogs/AuditLogsDetailsViewModel.cs ================================================ using AppFramework.Auditing.Dto; using AppFramework.Shared; using Prism.Services.Dialogs; namespace AppFramework.Admin.ViewModels { public class AuditLogsDetailsViewModel : HostDialogViewModel { private AuditLogListDto auditLog; public AuditLogListDto AuditLog { get { return auditLog; } set { auditLog = value; OnPropertyChanged(); } } public override void OnDialogOpened(IDialogParameters parameters) { if (parameters.ContainsKey("Value")) { AuditLog = parameters.GetValue("Value"); } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Auditlogs/AuditLogsViewModel.cs ================================================ using AppFramework.Auditing; using AppFramework.Auditing.Dto; using AppFramework.Shared; using Prism.Services.Dialogs; using System; using System.Threading.Tasks; using Prism.Ioc; using Prism.Regions; using AppFramework.Shared.Services; using AppFramework.Admin.Models; using CommunityToolkit.Mvvm.Input; namespace AppFramework.Admin.ViewModels { public partial class AuditLogsViewModel : NavigationCurdViewModel { public AuditLogsViewModel(IAuditLogAppService appService) { Title = Local.Localize("AuditLogs"); IsAdvancedFilter = false; filter = new GetAuditLogsFilter() { StartDate = DateTime.Now.AddDays(-30), EndDate = DateTime.Now, //MaxResultCount = AppConsts.DefaultPageSize }; entityChangeFilter = new GetEntityChangeFilter() { StartDate = DateTime.Now.AddDays(-30), EndDate = DateTime.Now, MaxResultCount = AppConsts.DefaultPageSize }; this.appService = appService; logsdataPager = ContainerLocator.Container.Resolve(); //绑定分页组件索引改变事件 logsdataPager.OnPageIndexChangedEventhandler += EntityChangesOnPageIndexChangedEventhandler; dataPager.OnPageIndexChangedEventhandler += AuditLogsOnPageIndexChangedEventhandler; } #region 字段/属性 public IDataPagerService logsdataPager { get; private set; } private readonly IAuditLogAppService appService; private string filterTitle = string.Empty; private bool isAdvancedFilter; private GetAuditLogsFilter filter; private GetEntityChangeFilter entityChangeFilter; private int selectedIndex; /// /// 错误状态选项: 全部/错误 /// public int SelectedIndex { get { return selectedIndex; } set { selectedIndex = value; if (selectedIndex == 0) filter.HasException = null; else if (selectedIndex == 1) filter.HasException = false; else filter.HasException = true; OnPropertyChanged(); } } /// /// 当前筛选标题 [展开/收缩] /// public string FilerTitle { get { return filterTitle; } set { filterTitle = value; OnPropertyChanged(); } } /// /// 高级筛选 /// public bool IsAdvancedFilter { get { return isAdvancedFilter; } set { isAdvancedFilter = value; FilerTitle = value ? "△ " + Local.Localize("HideAdvancedFilters") : "▽ " + Local.Localize("ShowAdvancedFilters"); OnPropertyChanged(); } } /// /// 审计日志筛选条件 /// public GetAuditLogsFilter Filter { get { return filter; } set { filter = value; OnPropertyChanged(); } } /// /// 更改日志筛选条件 /// public GetEntityChangeFilter EntityChangeFilter { get { return entityChangeFilter; } set { entityChangeFilter = value; OnPropertyChanged(); } } #endregion #region 审计日期 [RelayCommand] private void Advanced() { IsAdvancedFilter = !IsAdvancedFilter; } /// /// 查看操作日志详情 /// [RelayCommand] private void ViewLog() { DialogParameters param = new DialogParameters(); param.Add("Value", dataPager.SelectedItem); dialog.ShowDialogAsync(AppViews.AuditLogDetails, param); } /// /// 搜索操作日志 /// [RelayCommand] private void Search() { /* * 搜索结果的时候,只需要重置页索引为0即可,因为页索引变化会触发搜索事件 * 相关搜索条件则通过绑定的方式自动更新到筛选条件上. * * 说明: 这里一般验证筛选条件合法性即可. */ dataPager.PageIndex = 0; } /// /// 获取审计日期数据 /// /// private async Task GetAuditLogs(GetAuditLogsFilter input) { input.StartDate=input.StartDate.GetFirstDate(); input.EndDate=input.EndDate.GetLastDate(); await SetBusyAsync(async () => { await appService.GetAuditLogs(Map(input)).WebAsync(dataPager.SetList); }); } private async void AuditLogsOnPageIndexChangedEventhandler(object sender, PageIndexChangedEventArgs e) { filter.SkipCount = e.SkipCount; filter.MaxResultCount = e.PageSize; await GetAuditLogs(filter); } #endregion #region 更改日志 /// /// 搜索更改日志 /// [RelayCommand] private void SearchChanged() { dataPager.PageIndex = 0; } /// /// 获取更改日志 /// /// private async Task GetEntityChanges(GetEntityChangeFilter input) { await appService.GetEntityChanges(Map(input)).WebAsync(logsdataPager.SetList); } /// /// 查看更改日志详情 /// [RelayCommand] private void ViewChangedLog() { } private async void EntityChangesOnPageIndexChangedEventhandler(object sender, PageIndexChangedEventArgs e) { entityChangeFilter.SkipCount = e.SkipCount; entityChangeFilter.MaxResultCount = e.PageSize; await GetEntityChanges(entityChangeFilter); } #endregion /// /// 刷新数据 /// /// public override async Task OnNavigatedToAsync(NavigationContext navigationContext = null) { await SetBusyAsync(async () => { await GetAuditLogs(filter); await GetEntityChanges(entityChangeFilter); }); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Chat/FriendsChatViewModel.cs ================================================ using Abp.Runtime.Security; using AppFramework.ApiClient; using AppFramework.Authorization.Users.Profile; using AppFramework.Chat; using AppFramework.Chat.Dto; using AppFramework.Dto; using AppFramework.Shared; using AppFramework.Shared.Models.Chat; using Microsoft.Win32; using Newtonsoft.Json; using Prism.Commands; using Prism.Services.Dialogs; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Threading.Tasks; using MimeMapping; using Abp.Application.Services.Dto; using AppFramework.Shared.Services; namespace AppFramework.Admin.ViewModels { public class FriendsChatViewModel : HostDialogViewModel { public FriendsChatViewModel(IApplicationContext context, IChatAppService chatApp, IChatService chatService, IProfileAppService profileAppService, IAccessTokenManager tokenManager, ProxyChatControllerService proxyChatService) { this.context = context; this.chatApp = chatApp; this.chatService = chatService; this.profileAppService = profileAppService; this.tokenManager = tokenManager; this.proxyChatService = proxyChatService; chatService.OnChatMessageHandler += ChatService_OnChatMessageHandler; messages = new ObservableCollection(); SendCommand = new DelegateCommand(Send); PickFileCommand = new DelegateCommand(PickFile); PickImageCommand = new DelegateCommand(PickImage); OpenFolderCommand = new DelegateCommand(OpenFolder); } #region 字段/属性 private string userName; private string message; private FriendModel friend; private readonly IApplicationContext context; private readonly IChatAppService chatApp; private readonly IChatService chatService; private readonly IProfileAppService profileAppService; private readonly IAccessTokenManager tokenManager; private readonly ProxyChatControllerService proxyChatService; private ObservableCollection messages; public string Message { get { return message; } set { message = value; OnPropertyChanged(); } } public FriendModel Friend { get { return friend; } set { friend = value; OnPropertyChanged(); } } public ObservableCollection Messages { get { return messages; } set { messages = value; OnPropertyChanged(); } } public DelegateCommand SendCommand { get; private set; } public DelegateCommand PickImageCommand { get; private set; } public DelegateCommand PickFileCommand { get; private set; } public DelegateCommand OpenFolderCommand { get; private set; } #endregion #region 消息处理 /// /// 加载用户的聊天记录 /// /// /// private async Task GetUserChatMessagesByUser(long userId) { await chatApp.GetUserChatMessages(new GetUserChatMessagesInput() { UserId = userId }) .WebAsync(GetUserChatMessagesSuccessed); } /// /// 处理消息数据格式 /// /// /// private async Task GetUserChatMessagesSuccessed(ListResultDto result) { if (!result.Items.Any()) return; var list = Map>(result.Items); var userId = list.First().TargetUserId; userName = chatService.Friends.First(t => t.FriendUserId.Equals(userId)).FriendUserName; foreach (var item in list) { await UpdateMessageInfo(item); UpdateMessageGroup(item); Messages.Add(item); } await MarkAllUnreadMessages(); } /// /// 更新消息格式 /// /// private async Task UpdateMessageInfo(ChatMessageModel model) { if (model.Side == ChatSide.Sender) { model.Color = "#009933"; model.UserName = context.LoginInfo.User.Name; } else model.UserName = userName; if (model.Message.StartsWith("[image]")) { model.MessageType = "image"; await SaveCacheFile(model, model.Message.Replace("[image]", "")); } else if (model.Message.StartsWith("[file]")) { model.MessageType = "file"; await SaveCacheFile(model, model.Message.Replace("[file]", "")); } else if (model.Message.StartsWith("[link]")) { model.MessageType = "text"; var msg = model.Message.Replace("[link]", ""); model.Message = JsonConvert.DeserializeObject(msg).message; } else { model.MessageType = "text"; } } /// /// 更新消息分组 /// 小于10分钟以内的消息归一组 /// /// private void UpdateMessageGroup(ChatMessageModel chatMessage) { var lastMessage = Messages.LastOrDefault(); if (lastMessage != null) { var timeSpan = chatMessage.CreationTime - lastMessage.CreationTime; if (timeSpan.TotalMinutes < 10) chatMessage.CreationTime = lastMessage.CreationTime; } } /// /// 接受消息 /// /// private async void ChatService_OnChatMessageHandler(ChatMessageDto chatMessage) { var message = Messages.FirstOrDefault(t => t.Id.Equals(chatMessage.Id)); if (message == null) { var msg = Map(chatMessage); await UpdateMessageInfo(msg); UpdateMessageGroup(msg); Messages.Add(msg); await MarkAllUnreadMessages(); } } /// /// 标记消息已读 /// /// private async Task MarkAllUnreadMessages() { await chatApp.MarkAllUnreadMessagesOfUserAsRead(new MarkAllUnreadMessagesOfUserAsReadInput() { UserId = Friend.FriendUserId }).WebAsync(); } #endregion #region 发送图片/文件 private async Task SaveCacheFile(ChatMessageModel model, string msg) { var accessToken = tokenManager.GetAccessToken(); var code = SimpleStringCipher.Instance.Encrypt(accessToken, AppConsts.DefaultPassPhrase); var output = JsonConvert.DeserializeObject(msg); model.Message = output.Name; //显示文件名 var downloadUrl = ApiUrlConfig.BaseUrl + $"Chat/GetUploadedObject?fileId={output.Id}" + $"&fileName={output.Name}" + $"&contentType={output.ContentType}" + $"&enc_auth_token={code}"; await DownloadAsync(downloadUrl, AppConsts.DocumentPath, output.Name); } private async Task DownloadAsync(string url, string localFolderPath, string fileName) { if (File.Exists($"{localFolderPath}{fileName}")) { await Task.CompletedTask; } else { await proxyChatService.DownloadAsync(url, localFolderPath, fileName); } } private void OpenFolder(ChatMessageModel msg) { if (Directory.Exists(AppConsts.DocumentPath)) System.Diagnostics.Process.Start("explorer.exe", AppConsts.DocumentPath); } private async void PickFile() { OpenFileDialog fileDialog = new OpenFileDialog(); fileDialog.Filter = "所有文件(*.*)|*.*"; var dialogResult = fileDialog.ShowDialog(); if (dialogResult != null && (bool)dialogResult) { string fileName = fileDialog.SafeFileName; string contentType = MimeUtility.GetMimeMapping(fileName); var fileAsBytes = File.ReadAllBytes(fileDialog.FileName); await SetBusyAsync(async () => { await UploadFile(fileAsBytes, fileName, contentType).WebAsync(async output => { string message = $"[file]{{\"id\":\"{output.Id}\", " + $"\"name\":\"{output.Name}\", " + $"\"contentType\":\"{output.ContentType}\"}}"; await chatService.SendMessage(new SendChatMessageInput() { UserId = Friend.FriendUserId, Message = message, UserName = context.LoginInfo.User.Name }); }); }); } } private async void PickImage() { OpenFileDialog fileDialog = new OpenFileDialog(); fileDialog.Filter = "图片文件(*.jpg;*.jpeg;*.png)|*.jpg;*.jpeg;*.png"; var dialogResult = fileDialog.ShowDialog(); if ((bool)dialogResult) { string fileName = fileDialog.SafeFileName; string contentType = MimeUtility.GetMimeMapping(fileName); var photoAsBytes = File.ReadAllBytes(fileDialog.FileName); await SetBusyAsync(async () => { await UploadFile(photoAsBytes, fileName, contentType).WebAsync(async output => { string message = $"[image]{{\"id\":\"{output.Id}\", " + $"\"name\":\"{output.Name}\", " + $"\"contentType\":\"{output.ContentType}\"}}"; await chatService.SendMessage(new SendChatMessageInput() { UserId = Friend.FriendUserId, Message = message, UserName = context.LoginInfo.User.Name }); }); }); } } private async Task UploadFile(byte[] photoAsBytes, string fileName, string contentType) { using (Stream photoStream = new MemoryStream(photoAsBytes)) { return await proxyChatService.UploadFile(content => { content.AddFile("file", photoStream, fileName, contentType); content.AddString(nameof(FileDto.FileName), fileName); }); } } #endregion /// /// 关闭窗口 /// public override void Cancel() { chatService.OnChatMessageHandler -= ChatService_OnChatMessageHandler; base.Cancel(); } /// /// 发送消息 /// public async void Send() { if (string.IsNullOrWhiteSpace(Message)) return; await chatService.SendMessage(new SendChatMessageInput() { UserId = Friend.FriendUserId, Message = Message, UserName = context.LoginInfo.User.Name }).WebAsync(); Message = string.Empty; //发完消息就清除输入内容 } public override async void OnDialogOpened(IDialogParameters parameters) { if (parameters.ContainsKey("Value")) { Friend = parameters.GetValue("Value"); await GetUserChatMessagesByUser(Friend.FriendUserId); } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Chat/FriendsViewModel.cs ================================================ using AppFramework.ApiClient; using AppFramework.Friendships; using AppFramework.Shared; using AppFramework.Shared.Models.Chat; using AppFramework.Shared.Services; using Prism.Commands; using Prism.Regions; using Prism.Services.Dialogs; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels.Chat { public class FriendsViewModel : NavigationViewModel { private readonly IFriendshipAppService friendshipAppService; public IChatService chatService { get; private set; } private readonly IApplicationContext context; public DelegateCommand AddUserCommand { get; private set; } public DelegateCommand ClickChatCommand { get; private set; } public FriendsViewModel(IApplicationContext context, IFriendshipAppService friendshipAppService, IChatService chatService) { this.context = context; this.chatService = chatService; this.friendshipAppService = friendshipAppService; AddUserCommand = new DelegateCommand(AddUser); ClickChatCommand = new DelegateCommand(ClickChat); } private async void ClickChat(FriendModel obj) { DialogParameters param = new DialogParameters(); param.Add("Value", obj); await dialog.ShowDialogAsync(AppViews.FriendsChat, param); obj.UnreadMessageCount = 0; } private async void AddUser() { var result = await dialog.ShowDialogAsync(AppViews.SelectedUser); if (result.Result == ButtonResult.OK) { var userId = result.Parameters.GetValue("Value"); await friendshipAppService.CreateFriendshipRequest( new Friendships.Dto.CreateFriendshipRequestInput() { UserId = userId, TenantId = context.CurrentTenant?.TenantId }).WebAsync(async result => { await chatService.GetUserChatFriendsAsync(); }); ; } } public override bool IsNavigationTarget(NavigationContext navigationContext) { return true; } public override async Task OnNavigatedToAsync(NavigationContext navigationContext = null) { await chatService.GetUserChatFriendsAsync(); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Dashboard/DashboardViewModel.cs ================================================ using AppFramework.Shared; using AppFramework.Admin.Models; using AppFramework.MultiTenancy.HostDashboard; using AppFramework.MultiTenancy.HostDashboard.Dto; using Prism.Regions; using System; using System.Collections.ObjectModel; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels { public class DashboardViewModel : NavigationViewModel { public DashboardViewModel(IHostDashboardAppService appService) { Title = Local.Localize("Dashboard"); this.appService = appService; EditionStatistics = new ObservableCollection(); IncomeStatistics = new ObservableCollection(); } #region 字段/属性 private DateTime startDate = DateTime.Now.AddDays(-30); private DateTime endDate = DateTime.Now; private bool isDaily = true, isWeekly, isMonthly; private string timeInterval; private readonly IHostDashboardAppService appService; private ObservableCollection topDashBoards; private ObservableCollection editionStatistics; private ObservableCollection incomeStatistics; public bool IsDaily { get { return isDaily; } set { isDaily = value; if (value) AsyncRunner.Run(GetIncomeStatistics(ChartDateInterval.Daily)); OnPropertyChanged(); } } public bool IsWeekly { get { return isWeekly; } set { isWeekly = value; if (value) AsyncRunner.Run(GetIncomeStatistics(ChartDateInterval.Weekly)); OnPropertyChanged(); } } public bool IsMonthly { get { return isMonthly; } set { isMonthly = value; if (value) AsyncRunner.Run(GetIncomeStatistics(ChartDateInterval.Monthly)); OnPropertyChanged(); } } public string TimeInterval { get { return timeInterval; } set { timeInterval = value; OnPropertyChanged(); } } /// /// 版本信息 /// public ObservableCollection EditionStatistics { get { return editionStatistics; } set { editionStatistics = value; OnPropertyChanged(); } } /// /// 收入统计 /// public ObservableCollection IncomeStatistics { get { return incomeStatistics; } set { incomeStatistics = value; OnPropertyChanged(); } } /// /// 统计面板 /// public ObservableCollection TopDashBoards { get { return topDashBoards; } set { topDashBoards = value; OnPropertyChanged(); } } #endregion 字段/属性 #region 统计方法 /// /// 获取统计面板数据 /// /// private async Task GetWorkbenchSummary() { IsDaily = true; TimeInterval = $"{startDate.ToString("yyyy-MM-dd")}~{endDate.ToString("yyyy-MM-dd")}"; await GetTopStatsData(); await GetEditionTenantStatistics(); } /// /// 获取最近一个月的统计数据 (新租户、新订阅金额、样例1、样例2) /// /// private async Task GetTopStatsData() { await appService.GetTopStatsData(new GetTopStatsInput() { StartDate = startDate, EndDate = endDate }).WebAsync(GetTopStatsDataSuccessed); } /// /// 获取版本信息 /// /// private async Task GetEditionTenantStatistics() { await appService.GetEditionTenantStatistics(new GetEditionTenantStatisticsInput() { StartDate = startDate, EndDate = endDate }).WebAsync(GetEditionTenantStatisticsSuccessed); } /// /// 获取收入统计信息 /// /// /// /// private async Task GetIncomeStatistics(ChartDateInterval interval) { await appService.GetIncomeStatistics(new GetIncomeStatisticsDataInput() { IncomeStatisticsDateInterval = interval, StartDate = startDate, EndDate = endDate }).WebAsync(GetIncomeStatisticsSuccessed); } private async Task GetTopStatsDataSuccessed(TopStatsData topStatsData) { if (topStatsData != null) { TopDashBoards = new ObservableCollection() { new TopStatusItem() { Title=Local.Localize(AppLocalizationKeys.NewSubscriptionAmount), Logo=$"/Assets/Images/{AppLocalizationKeys.NewSubscriptionAmount}.png", Amount=topStatsData.NewSubscriptionAmount, BackgroundGradientStart = "#f59083", BackgroundGradientEnd = "#fae188", }, new TopStatusItem() { Title=Local.Localize(AppLocalizationKeys.NewTenants), Logo=$"/Assets/Images/{AppLocalizationKeys.NewTenants}.png", Amount=topStatsData.NewTenantsCount, BackgroundGradientStart = "#ff7272", BackgroundGradientEnd = "#f650c5", }, new TopStatusItem() { Title=Local.Localize(AppLocalizationKeys.DashboardSampleStatistics), Logo=$"/Assets/Images/{AppLocalizationKeys.DashboardSampleStatistics}.png", Amount=topStatsData.DashboardPlaceholder1, BackgroundGradientStart = "#5e7cea", BackgroundGradientEnd = "#1dcce3", }, new TopStatusItem() { Title=Local.Localize(AppLocalizationKeys.DashboardSampleStatistics), Logo="/Assets/Images/DashboardSampleStatistics2.png", Amount=topStatsData.DashboardPlaceholder2, BackgroundGradientStart = "#255ea6", BackgroundGradientEnd = "#b350d1", }, }; } await Task.CompletedTask; } private async Task GetIncomeStatisticsSuccessed(GetIncomeStatisticsDataOutput output) { IncomeStatistics.Clear(); foreach (var item in output?.IncomeStatistics) { IncomeStatistics.Add(new AreaSeriesChart3DModel() { Date = item.Date, Amount = item.Amount }); } await Task.CompletedTask; } private async Task GetEditionTenantStatisticsSuccessed(GetEditionTenantStatisticsOutput output) { EditionStatistics.Clear(); foreach (var edition in output?.EditionStatistics) { EditionStatistics.Add(new DoughnutChartPopulations() { Category = edition.Label, Expenditure = edition.Value, }); } await Task.CompletedTask; } #endregion #region INavigationAware 接口实现 public override async Task OnNavigatedToAsync(NavigationContext navigationContext) { await SetBusyAsync(async () => { await GetWorkbenchSummary(); }); } #endregion } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Demo/DemoViewModel.cs ================================================ using AppFramework.Demo; using AppFramework.Demo.Dtos; using AppFramework.Shared; using AppFramework.Shared.Services; using Prism.Regions; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels { public class DemoViewModel: NavigationCurdViewModel { private readonly IAbpDemoAppService appService; public GetAllAbpDemoInput input; public DemoViewModel(IAbpDemoAppService appService) { Title = Local.Localize("DemoManager"); this.appService = appService; input = new GetAllAbpDemoInput() { MaxResultCount = 10 }; dataPager.OnPageIndexChangedEventhandler += DataPager_OnPageIndexChangedEventhandler; } private void DataPager_OnPageIndexChangedEventhandler(object sender, PageIndexChangedEventArgs e) { } public override async Task OnNavigatedToAsync(NavigationContext navigationContext = null) { await SetBusyAsync(async () => { await GetAbpDemos(input); }); } private async Task GetAbpDemos(GetAllAbpDemoInput filter) { await WebRequest.Execute(() => appService.GetAll(filter), dataPager.SetList); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/DynamicProperty/DynamicAddEntityViewModel.cs ================================================ using AppFramework.DynamicEntityProperties; using AppFramework.Shared; using Prism.Services.Dialogs; using System.Collections.ObjectModel; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels { public class DynamicAddEntityViewModel : HostDialogViewModel { public DynamicAddEntityViewModel(IDynamicEntityPropertyDefinitionAppService appService) { model = new ObservableCollection(); this.appService = appService; } private ObservableCollection model; public ObservableCollection Models { get { return model; } set { model = value; OnPropertyChanged(); } } private string selectedItem; private readonly IDynamicEntityPropertyDefinitionAppService appService; public string SelectedItem { get { return selectedItem; } set { selectedItem = value; OnPropertyChanged(); } } public override async Task Save() { if (string.IsNullOrWhiteSpace(SelectedItem)) return; base.Save(SelectedItem); await Task.CompletedTask; } private async Task GetAllEntities() { await appService.GetAllEntities() .WebAsync(async result => { foreach (var item in result) Models.Add(item); await Task.CompletedTask; }); } public override async void OnDialogOpened(IDialogParameters parameters) { await SetBusyAsync(GetAllEntities); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/DynamicProperty/DynamicEditValuesViewModel.cs ================================================ using AppFramework.Shared; using AppFramework.DynamicEntityProperties; using AppFramework.DynamicEntityProperties.Dto; using Prism.Commands; using Prism.Services.Dialogs; using System.Threading.Tasks; using Abp.Application.Services.Dto; using AppFramework.ApiClient; using AppFramework.Shared.Services; namespace AppFramework.Admin.ViewModels { /// /// 编辑值视图模型 /// public class DynamicEditValuesViewModel : HostDialogViewModel { private readonly IDynamicPropertyValueAppService appService; private readonly IApplicationContext context; public IDataPagerService dataPager { get; private set; } private readonly IHostDialogService dialog; private int Id; private bool isAdd; public bool IsAdd { get { return isAdd; } set { isAdd = value; OnPropertyChanged(); } } private string inputValue; public string InputValue { get { return inputValue; } set { inputValue = value; OnPropertyChanged(); } } public DelegateCommand ShowAddCommand { get; private set; } public DelegateCommand RefreshCommand { get; private set; } public DelegateCommand AddValueCommand { get; private set; } public DelegateCommand EditCommand { get; private set; } public DelegateCommand DeleteCommand { get; private set; } public DynamicEditValuesViewModel( IDynamicPropertyValueAppService appService, IApplicationContext context, IDataPagerService dataPager, IHostDialogService dialog) { this.appService = appService; this.context = context; this.dataPager = dataPager; this.dialog = dialog; RefreshCommand = new DelegateCommand(Refresh); ShowAddCommand = new DelegateCommand(() => IsAdd = true); AddValueCommand = new DelegateCommand(AddValue); EditCommand = new DelegateCommand(Edit); DeleteCommand = new DelegateCommand(Delete); } /// /// 删除值 /// /// private async void Delete(DynamicPropertyValueDto obj) { if (await dialog.Question(Local.Localize("DeleteDynamicPropertyValueMessage"), AppSharedConsts.DialogIdentifier)) { await SetBusyAsync(async () => { await appService.Delete(obj.Id).WebAsync(GetAllValuesOfDynamicProperty); }); } } /// /// 编辑值 /// /// private void Edit(DynamicPropertyValueDto obj) { InputValue = obj.Value; } /// /// 刷新列表 /// private async void Refresh() { await GetAllValuesOfDynamicProperty(); } /// /// 添加值 /// private async void AddValue() { if (string.IsNullOrWhiteSpace(InputValue)) return; await SetBusyAsync(async () => { await appService.Add(new DynamicPropertyValueDto() { DynamicPropertyId = Id, TenantId = context.CurrentTenant?.TenantId, Value = InputValue }).WebAsync(GetAllValuesOfDynamicProperty); }); } /// /// 获取动态属性的所有值 /// /// public async Task GetAllValuesOfDynamicProperty() { IsAdd = false; InputValue = string.Empty; await appService.GetAllValuesOfDynamicProperty(new EntityDto(Id)).WebAsync(dataPager.SetList); } public override async void OnDialogOpened(IDialogParameters parameters) { if (parameters.ContainsKey("Value")) { Id = parameters.GetValue("Value").Id; await SetBusyAsync(GetAllValuesOfDynamicProperty); } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/DynamicProperty/DynamicEntityDetailsViewModel.cs ================================================ using AppFramework.Shared; using AppFramework.DynamicEntityProperties; using AppFramework.DynamicEntityProperties.Dto; using Prism.Commands; using Prism.Services.Dialogs; using System.Threading.Tasks; using Abp.Application.Services.Dto; using AppFramework.ApiClient; using AppFramework.Admin.Services; using System.Collections.ObjectModel; using System.Linq; using AppFramework.Shared.Services; namespace AppFramework.Admin.ViewModels { /// /// 动态实体属性详情 /// public class DynamicEntityDetailsViewModel : HostDialogViewModel { private readonly IDynamicPropertyAppService propertyAppService; private readonly IDynamicEntityPropertyAppService appService; private readonly IApplicationContext context; public IDataPagerService dataPager { get; } private readonly IHostDialogService dialog; private DynamicPropertyDto selectedItem; private ObservableCollection items; private string EntityFullName; private bool isAdd; public bool IsAdd { get { return isAdd; } set { isAdd = value; OnPropertyChanged(); } } public DelegateCommand ShowAddCommand { get; private set; } public DelegateCommand RefreshCommand { get; private set; } public DelegateCommand AddValueCommand { get; private set; } public DelegateCommand DeleteCommand { get; private set; } public ObservableCollection Items { get { return items; } set { items = value; OnPropertyChanged(); } } /// /// 选中的实体属性 /// public DynamicPropertyDto SelectedItem { get { return selectedItem; } set { selectedItem = value; OnPropertyChanged(); } } public DynamicEntityDetailsViewModel( IDynamicPropertyAppService propertyAppService, IDynamicEntityPropertyAppService appService, IApplicationContext context, IDataPagerService dataPager, IHostDialogService dialog) { this.dialog = dialog; this.context = context; this.dataPager = dataPager; this.appService = appService; this.propertyAppService = propertyAppService; items = new ObservableCollection(); RefreshCommand = new DelegateCommand(Refresh); ShowAddCommand = new DelegateCommand(ShowAdd); AddValueCommand = new DelegateCommand(AddValue); DeleteCommand = new DelegateCommand(Delete); } /// /// 添加实体属性 /// private async void ShowAdd() { IsAdd = true; await SetBusyAsync(async () => { await propertyAppService.GetAll().WebAsync(async result => { Items.Clear(); foreach (var item in result.Items) Items.Add(item); foreach (var item in dataPager.GridModelList) { var dynamicEntity = item as DynamicEntityPropertyDto; if (dynamicEntity != null) { var t = Items.FirstOrDefault(t => t.Id.Equals(dynamicEntity.DynamicPropertyId)); if (t != null) Items.Remove(t); } } await Task.CompletedTask; }); }); } /// /// 删除值 /// /// private async void Delete(DynamicEntityPropertyDto obj) { if (await dialog.Question(Local.Localize("DeleteDynamicPropertyMessage"), AppSharedConsts.DialogIdentifier)) { await SetBusyAsync(async () => { await appService.Delete(obj.Id).WebAsync(GetAllPropertiesOfAnEntity); }); } } /// /// 刷新列表 /// private async void Refresh() { await GetAllPropertiesOfAnEntity(); } /// /// 添加值 /// private async void AddValue() { if (SelectedItem == null) return; await SetBusyAsync(async () => { await appService.Add(new DynamicEntityPropertyDto() { TenantId = context.CurrentTenant?.TenantId, EntityFullName = EntityFullName, DynamicPropertyId = SelectedItem.Id }) .WebAsync(GetAllPropertiesOfAnEntity); }); } public async Task GetAllPropertiesOfAnEntity() { IsAdd = false; await SetBusyAsync(async () => { await appService.GetAllPropertiesOfAnEntity(new DynamicEntityPropertyGetAllInput() { EntityFullName = EntityFullName }).WebAsync(dataPager.SetList); }); } public override async void OnDialogOpened(IDialogParameters parameters) { if (parameters.ContainsKey("Name")) { EntityFullName = parameters.GetValue("Name"); await GetAllPropertiesOfAnEntity(); } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/DynamicProperty/DynamicPropertyDetailsViewModel.cs ================================================ using AppFramework.Shared; using AppFramework.Admin.Models; using AppFramework.DynamicEntityProperties; using AppFramework.DynamicEntityProperties.Dto; using Prism.Services.Dialogs; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels { public class DynamicPropertyDetailsViewModel : HostDialogViewModel { private DynamicPropertyModel model; private readonly IDynamicPropertyAppService appService; public DynamicPropertyModel Model { get { return model; } set { model = value; OnPropertyChanged(); } } public DynamicPropertyDetailsViewModel(IDynamicPropertyAppService appService) { model = new DynamicPropertyModel(); this.appService = appService; } public override async Task Save() { await SetBusyAsync(async () => { var input = Map(Model); await WebRequest.Execute(async () => { if (input.Id > 0) await appService.Update(input); else await appService.Add(input); }, base.Save); }); } public override void OnDialogOpened(IDialogParameters parameters) { if (parameters.ContainsKey("Value")) { var dynamicProperty = parameters.GetValue("Value"); Model = Map(dynamicProperty); } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/DynamicProperty/DynamicPropertyViewModel.cs ================================================ using Abp.Application.Services.Dto; using AppFramework.Shared; using AppFramework.Shared.Services.Permission; using AppFramework.DynamicEntityProperties; using AppFramework.DynamicEntityProperties.Dto; using Prism.Services.Dialogs; using System.Threading.Tasks; using Prism.Ioc; using Prism.Regions; using AppFramework.Shared.Services; using CommunityToolkit.Mvvm.Input; namespace AppFramework.Admin.ViewModels { public partial class DynamicPropertyViewModel : NavigationCurdViewModel { public IDataPagerService entitydataPager { get; private set; } private readonly IDynamicPropertyAppService appService; private readonly IDynamicEntityPropertyAppService entityPropertyAppService; public DynamicPropertyViewModel( IDynamicPropertyAppService appService, IDynamicEntityPropertyAppService entityPropertyAppService) { Title = Local.Localize("DynamicPropertyManagement"); this.appService = appService; this.entityPropertyAppService = entityPropertyAppService; entitydataPager = ContainerLocator.Container.Resolve(); } [RelayCommand] private async void AddEntityProperty() { var r = await dialog.ShowDialogAsync(AppViews.DynamicAddEntity); if (r.Result == ButtonResult.OK) { var EntityFullName = r.Parameters.GetValue("Value"); Detail(new GetAllEntitiesHasDynamicPropertyOutput() { EntityFullName = EntityFullName, }); } } /// /// 动态实体属性详情 /// /// [RelayCommand] private async void Detail(GetAllEntitiesHasDynamicPropertyOutput output) { DialogParameters param = new DialogParameters(); param.Add("Name", output.EntityFullName); await dialog.ShowDialogAsync(AppViews.DynamicEntityDetails, param); await SetBusyAsync(GetAllEntitiesHasDynamicProperty); } /// /// 删除动态属性 /// private async void Delete() { if (dataPager.SelectedItem is DynamicPropertyDto item) { if (await dialog.Question(Local.Localize("DeleteDynamicPropertyMessage", item.DisplayName))) { await SetBusyAsync(async () => { await appService.Delete(new EntityDto(item.Id)).WebAsync(async () => await OnNavigatedToAsync()); }); } } } /// /// 编辑值 /// private async void EditValues() { DialogParameters param = new DialogParameters(); param.Add("Value", dataPager.SelectedItem); var dialogResult = await dialog.ShowDialogAsync(AppViews.DynamicEditValues, param); } /// /// 获取动态属性 /// /// private async Task GetDynamicPropertyAll() { await appService.GetAll().WebAsync(dataPager.SetList); } /// /// 获取动态实体属性 /// /// private async Task GetAllEntitiesHasDynamicProperty() { await entityPropertyAppService.GetAllEntitiesHasDynamicProperty().WebAsync(entitydataPager.SetList); } /// /// 刷新动态属性模块 /// /// public override async Task OnNavigatedToAsync(NavigationContext navigationContext = null) { await SetBusyAsync(async () => { await GetDynamicPropertyAll(); await GetAllEntitiesHasDynamicProperty(); }); } public override PermissionItem[] CreatePermissionItems() { return new PermissionItem[] { new PermissionItem(AppPermissions.LanguageEdit, Local.Localize("Change"),Edit), new PermissionItem(AppPermissions.LanguageDelete, Local.Localize("Delete"),Delete), new PermissionItem(AppPermissions.LanguageChangeTexts, Local.Localize("EditValues"),EditValues), }; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Edition/EditionDetailsViewModel.cs ================================================ using Abp.Application.Services.Dto; using AppFramework.Shared; using AppFramework.Admin.Models; using AppFramework.Editions; using AppFramework.Editions.Dto; using Prism.Services.Dialogs; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using AppFramework.Common; using Prism.Mvvm; namespace AppFramework.Admin.ViewModels { public class EditionDetailsViewModel : HostDialogViewModel { #region 字段/属性 private readonly IEditionAppService appService; private readonly ICommonLookupAppService commonLookupAppService; private bool isPaid, isTrialActive, isWaitingDayAfter, isAssignToAnotherEdition; private EditionCreateModel model; private ObservableCollection features; //是否付费 public bool IsPaid { get { return isPaid; } set { isPaid = value; OnPropertyChanged(); } } //是否试用 public bool IsTrialActive { get { return isTrialActive; } set { isTrialActive = value; OnPropertyChanged(); } } //订阅到期后 public bool IsWaitingDayAfter { get { return isWaitingDayAfter; } set { isWaitingDayAfter = value; OnPropertyChanged(); } } //订阅到期后是否指定版本 public bool IsAssignToAnotherEdition { get { return isAssignToAnotherEdition; } set { isAssignToAnotherEdition = value; OnPropertyChanged(); } } /// /// 当前新增或编辑的版本信息 /// public EditionCreateModel Model { get { return model; } set { model = value; OnPropertyChanged(); } } /// /// 功能列表 /// public ObservableCollection Features { get { return features; } set { features = value; OnPropertyChanged(); } } #endregion 字段/属性 public EditionDetailsViewModel( IEditionAppService appService, ICommonLookupAppService commonLookupAppService) { this.appService = appService; this.commonLookupAppService = commonLookupAppService; Model = new EditionCreateModel(); Features = new ObservableCollection(); Editions = new ObservableCollection(); } public override async Task Save() { //刷新界面设置的选项内容值 RefreshInputInformation(); if (!Verify(Model).IsValid) return; await SetBusyAsync(async () => { List featureValues = new List(); GetSelectedNodes(Features, ref featureValues); CreateOrUpdateEditionDto editionDto = new CreateOrUpdateEditionDto(); editionDto.Edition = Map(Model); editionDto.FeatureValues = featureValues; await appService.CreateOrUpdate(editionDto).WebAsync(base.Save); }); } public override async void OnDialogOpened(IDialogParameters parameters) { await SetBusyAsync(async () => { int? id = null; if (parameters.ContainsKey("Value")) id = parameters.GetValue("Value").Id; await appService.GetEditionForEdit(new NullableIdDto(id)).WebAsync(async result => { Model = Map(result.Edition); var flats = Map>(result.Features); Features = CreateFeatureTrees(flats, null); UpdateSelectedNodes(Features, result.FeatureValues); await PopulateEditionsCombobox(() => { SetSelectedEdition(Model.Id); }); }); }); } private void RefreshInputInformation() { //指定免费版时 if (!IsPaid) { Model.DailyPrice = null; Model.WeeklyPrice = null; Model.MonthlyPrice = null; Model.AnnualPrice = null; } //如果试用到期 if (!IsTrialActive) Model.TrialDayCount = null; //订阅到期后不设置等待期 if (!IsWaitingDayAfter) Model.WaitingDayAfterExpire = null; //订阅到期后不切换指定版本 if (!IsAssignToAnotherEdition) Model.ExpiringEditionId = null; } #region 租户选项 private const string NotAssignedValue = "0"; private SubscribableEditionComboboxItemDto? selectedEdition; /// /// 选中版本 /// public SubscribableEditionComboboxItemDto? SelectedEdition { get => selectedEdition; set { selectedEdition = value; if (selectedEdition != null) { //更新选中版本项刷新绑定的版本ID if (int.TryParse(selectedEdition.Value, out int result)) { model.ExpiringEditionId = result; } } OnPropertyChanged(); } } public ObservableCollection editions; /// /// 版本列表 /// public ObservableCollection Editions { get => editions; set { editions = value; OnPropertyChanged(); } } /// /// 获取及绑定可选的版本列表 /// /// /// private async Task PopulateEditionsCombobox(Action editionsPopulated) { await commonLookupAppService.GetEditionsForCombobox().WebAsync(async result => { Editions.Clear(); AddNotAssignedItem(); foreach (var item in result.Items) Editions.Add(item); await Task.CompletedTask; }); editionsPopulated(); } private void AddNotAssignedItem() { Editions.Add(new SubscribableEditionComboboxItemDto(NotAssignedValue, string.Format("- {0} -", Local.Localize(AppLocalizationKeys.NotAssigned)), null)); } private void SetSelectedEdition(int? editionId) { SelectedEdition = editionId.HasValue ? Editions.FirstOrDefault(e => e.Value == editionId.Value.ToString()) : Editions.FirstOrDefault(e => e.Value == NotAssignedValue); } #endregion 租户选项 #region 功能列表 /// /// 创建功能结点目录树 /// /// /// /// private ObservableCollection CreateFeatureTrees(List flatFeatureModels, string parentName) { var trees = new ObservableCollection(); var nodes = flatFeatureModels.Where(q => q.ParentName == parentName).ToArray(); foreach (var node in nodes) { node.Items = CreateFeatureTrees(flatFeatureModels, node.Name); trees.Add(node); } return trees; } /// /// 获取选中的功能节点 /// /// /// private void GetSelectedNodes(ObservableCollection nodes, ref List featureValues) { foreach (var item in nodes) { if (bool.TryParse(item.DefaultValue, out bool result)) featureValues.Add(new NameValueDto(item.Name, item.IsChecked.ToString())); else featureValues.Add(new NameValueDto(item.Name, item.DefaultValue)); GetSelectedNodes(item.Items, ref featureValues); } } /// /// 更新选中功能节点 /// /// private void UpdateSelectedNodes(ObservableCollection flatFeatureModels, List nameValues) { nameValues.ForEach(item => { UpdateSelected(flatFeatureModels, item); }); } /// /// 设置选中功能节点 /// /// /// private void UpdateSelected(ObservableCollection flats, NameValueDto item) { foreach (var flat in flats) { if (flat.Name.Equals(item.Name)) { if (bool.TryParse(item.Value, out bool result)) { flat.IsChecked = result; return; } else flat.IsChecked = true; } UpdateSelected(flat.Items, item); } } #endregion 功能列表 } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Edition/EditionViewModel.cs ================================================ using Abp.Application.Services.Dto; using AppFramework.Editions; using AppFramework.Editions.Dto; using AppFramework.Shared; using AppFramework.Shared.Services.Permission; using AppFramework.Admin.ViewModels.Shared; using Prism.Regions; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels { public class EditionViewModel : NavigationCurdViewModel { private readonly IEditionAppService appService; public EditionViewModel(IEditionAppService appService) { Title = Local.Localize("Editions"); this.appService = appService; } /// /// 删除版本信息 /// private async void Delete() { if (dataPager.SelectedItem is EditionListDto item) { if (await dialog.Question(Local.Localize("EditionDeleteWarningMessage", item.DisplayName))) { await SetBusyAsync(async () => { await appService.DeleteEdition(new EntityDto(item.Id)).WebAsync(async () => await OnNavigatedToAsync()); }); } } } /// /// 获取版本列表 /// /// private async Task GetEditions() { await SetBusyAsync(async () => { await appService.GetEditions().WebAsync(dataPager.SetList); }); } /// /// 刷新版本模块 /// /// public override async Task OnNavigatedToAsync(NavigationContext navigationContext = null) { await GetEditions(); } public override PermissionItem[] CreatePermissionItems() { return new PermissionItem[] { new PermissionItem(AppPermissions.EditionEdit, Local.Localize("EditEdition"),Edit), new PermissionItem(AppPermissions.EditionDelete, Local.Localize("Delete"),Delete), }; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Language/LanguageDetailsViewModel.cs ================================================ using AppFramework.Localization; using Prism.Services.Dialogs; using System.Threading.Tasks; using Abp.Application.Services.Dto; using AppFramework.Localization.Dto; using System.Collections.ObjectModel; using System.Linq; using AppFramework.Shared; namespace AppFramework.Admin.ViewModels { public class LanguageDetailsViewModel : HostDialogViewModel { #region 字段/属性 private readonly ILanguageAppService appService; private ApplicationLanguageEditDto language; private ComboboxItemDto selectedFlag; private ComboboxItemDto selectedLanguage; private ObservableCollection flags; private ObservableCollection languageNames; /// /// 可选语言列表 /// public ObservableCollection LanguageNames { get { return languageNames; } set { languageNames = value; OnPropertyChanged(); } } /// /// 图标 /// public ObservableCollection Flags { get { return flags; } set { flags = value; OnPropertyChanged(); } } //选中语言 public ComboboxItemDto SelectedLanguage { get { return selectedLanguage; } set { selectedLanguage = value; if (selectedLanguage != null) { language.Name = value.Value; } OnPropertyChanged(); } } //选中图标 public ComboboxItemDto SelectedFlag { get { return selectedFlag; } set { selectedFlag = value; if (selectedLanguage != null) { language.Icon = value.Value; } OnPropertyChanged(); } } //是否启用 public bool IsEnabled { get { return language.IsEnabled; } set { language.IsEnabled = value; OnPropertyChanged(); } } #endregion public LanguageDetailsViewModel(ILanguageAppService appService) { language = new ApplicationLanguageEditDto(); this.appService = appService; } public override async Task Save() { await SetBusyAsync(async () => { await appService.CreateOrUpdateLanguage(new CreateOrUpdateLanguageInput() { Language = language }) .WebAsync(base.Save); }); } public override async void OnDialogOpened(IDialogParameters parameters) { await SetBusyAsync(async () => { int? id = null; if (parameters.ContainsKey("Value")) id = parameters.GetValue("Value").Id; await appService.GetLanguageForEdit(new NullableIdDto(id)).WebAsync(GetLanguageForEditSuccessed); }); } private async Task GetLanguageForEditSuccessed(GetLanguageForEditOutput output) { Flags = new ObservableCollection(output.Flags); LanguageNames = new ObservableCollection(output.LanguageNames); if (output.Language != null) { language.Id = output.Language.Id; language.Name = output.Language.Name; language.Icon = output.Language.Icon; IsEnabled = output.Language.IsEnabled; var f = Flags.FirstOrDefault(t => t.Value.Equals(language.Icon)); if (f != null) SelectedFlag = f; var l = LanguageNames.FirstOrDefault(t => t.Value.Equals(language.Name)); if (l != null) SelectedLanguage = l; } else { SelectedFlag = Flags.First(); SelectedLanguage = LanguageNames.First(); } await Task.CompletedTask; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Language/LanguageTextDetailsViewModel.cs ================================================ using AppFramework.Shared; using AppFramework.Admin.Models; using AppFramework.Localization; using AppFramework.Localization.Dto; using Prism.Services.Dialogs; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels { public class LanguageTextDetailsViewModel : HostDialogViewModel { #region 字段/属性 private string key, baseValue, targetValue; public string Key { get { return key; } set { key = value; OnPropertyChanged(); } } public string BaseValue { get { return baseValue; } set { baseValue = value; OnPropertyChanged(); } } public string TargetValue { get { return targetValue; } set { targetValue = value; OnPropertyChanged(); } } private LanguageStruct baseLanguage; private LanguageStruct targetLanguage; private readonly ILanguageAppService appService; public LanguageStruct BaseLanguage { get { return baseLanguage; } set { baseLanguage = value; OnPropertyChanged(); } } public LanguageStruct TargetLanguage { get { return targetLanguage; } set { targetLanguage = value; OnPropertyChanged(); } } private string SourceName; #endregion public LanguageTextDetailsViewModel(ILanguageAppService appService) { this.appService = appService; } public override async Task Save() { await SetBusyAsync(async () => { await appService.UpdateLanguageText(new UpdateLanguageTextInput() { Key = Key, LanguageName = BaseLanguage.Name, SourceName = SourceName, Value = TargetValue }) .WebAsync(base.Save); }); } public override void OnDialogOpened(IDialogParameters parameters) { if (parameters.ContainsKey("Value")) { SourceName = parameters.GetValue("SourceName"); BaseLanguage = parameters.GetValue("Base"); TargetLanguage = parameters.GetValue("Target"); var lang = parameters.GetValue("Value"); Key = lang.Key; BaseValue = lang.BaseValue; TargetValue = lang.TargetValue; } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Language/LanguageTextViewModel.cs ================================================ using AppFramework.ApiClient; using AppFramework.Shared; using AppFramework.Admin.Models; using AppFramework.Localization; using AppFramework.Localization.Dto; using Prism.Commands; using Prism.Regions; using Prism.Services.Dialogs; using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using AppFramework.Shared.Services; namespace AppFramework.Admin.ViewModels { public class LanguageTextViewModel : NavigationCurdViewModel { public LanguageTextViewModel(ILanguageAppService appService, IApplicationContext context) { Title = Local.Localize("ChangeTexts"); sources = new ObservableCollection(); baseLanguages = new ObservableCollection(); targetLanguages = new ObservableCollection(); input = new GetLanguageTextsInput() { FilterText = "", MaxResultCount = AppConsts.DefaultPageSize, SkipCount = 0 }; this.appService = appService; this.context = context; EditCommand = new DelegateCommand(Edit); SearchCommand = new DelegateCommand(Search); dataPager.OnPageIndexChangedEventhandler += LanguageOnPageIndexChangedEventhandler; } #region 字段/属性 private readonly ILanguageAppService appService; private readonly IApplicationContext context; public DelegateCommand SearchCommand { get; private set; } public DelegateCommand EditCommand { get; private set; } private int targetIndex; private GetLanguageTextsInput input; private ObservableCollection sources; private ObservableCollection baseLanguages; private ObservableCollection targetLanguages; private LanguageStruct selectedBaseLanguage; private LanguageStruct selectedTargetLanguage; public string Filter { get { return input.FilterText; } set { input.FilterText = value; OnPropertyChanged(); } } /// /// 目标值选项 全部/单个值 /// public int TargetIndex { get { return targetIndex; } set { targetIndex = value; input.TargetValueFilter = value == 0 ? "ALL" : "EMPTY"; OnPropertyChanged(); } } public ObservableCollection BaseLanguages { get { return baseLanguages; } set { baseLanguages = value; OnPropertyChanged(); } } public ObservableCollection TargetLanguages { get { return targetLanguages; } set { targetLanguages = value; OnPropertyChanged(); } } public ObservableCollection Sources { get { return sources; } set { sources = value; OnPropertyChanged(); } } public LanguageStruct SelectedBaseLanguage { get { return selectedBaseLanguage; } set { selectedBaseLanguage = value; input.BaseLanguageName = value.Name; OnPropertyChanged(); } } public LanguageStruct SelectedTargetLanguage { get { return selectedTargetLanguage; } set { selectedTargetLanguage = value; input.TargetLanguageName = value.Name; OnPropertyChanged(); } } public string SelectedSource { get { return input.SourceName; } set { input.SourceName = value; OnPropertyChanged(); } } #endregion private async void LanguageOnPageIndexChangedEventhandler(object sender, PageIndexChangedEventArgs e) { input.SkipCount = e.SkipCount; input.MaxResultCount = e.PageSize; await SetBusyAsync(async () => { await GetLanguageTexts(input); }); } private async void Edit(LanguageTextListDto obj) { DialogParameters param = new DialogParameters(); param.Add("Value", obj); param.Add("Base", SelectedBaseLanguage); param.Add("Target", SelectedTargetLanguage); param.Add("SourceName", input.SourceName); var dialogResult = await dialog.ShowDialogAsync(AppViews.LanguageTextDetails, param); if (dialogResult.Result == ButtonResult.OK) { dataPager.PageIndex = 0; } } private void Search() { dataPager.PageIndex = 0; } private async Task GetLanguageTexts(GetLanguageTextsInput filter) { await appService.GetLanguageTexts(filter).WebAsync(dataPager.SetList); } public override async Task OnNavigatedToAsync(NavigationContext navigationContext = null) { foreach (var item in context.Configuration.Localization.Sources) { Sources.Add(item.Name); } foreach (var item in context.Configuration.Localization.Languages) { BaseLanguages.Add(new LanguageStruct(item.Icon, item.Name, item.DisplayName)); TargetLanguages.Add(new LanguageStruct(item.Icon, item.Name, item.DisplayName)); } if (navigationContext.Parameters.ContainsKey("Name")) { var Name = navigationContext.Parameters.GetValue("Name"); var lang = context.Configuration.Localization.Languages.FirstOrDefault(t => t.Name.Equals(Name)); if (lang != null) { SelectedBaseLanguage = new LanguageStruct(lang.Icon, lang.Name, lang.DisplayName); SelectedTargetLanguage = new LanguageStruct(lang.Icon, lang.Name, lang.DisplayName); } input.TargetValueFilter = "ALL"; input.SourceName = Sources.Last(); } await SetBusyAsync(async () => await GetLanguageTexts(input)); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Language/LanguageViewModel.cs ================================================ using Abp.Application.Services.Dto; using AppFramework.Shared; using AppFramework.Admin.Models; using AppFramework.Shared.Services.Permission; using AppFramework.Localization; using AppFramework.Localization.Dto; using AppFramework.Admin.Services; using Prism.Regions; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels { public class LanguageViewModel : NavigationCurdViewModel { private readonly ILanguageAppService appService; private readonly NavigationService navigationService; public LanguageListModel SelectedItem => Map(dataPager.SelectedItem); public LanguageViewModel(ILanguageAppService languageAppService, NavigationService navigationService) { Title = Local.Localize("Languages"); this.appService = languageAppService; this.navigationService = navigationService; } /// /// 更改文本 /// private void ChangeTexts() { NavigationParameters param = new NavigationParameters(); param.Add("Name", SelectedItem.Name); navigationService.Navigate(AppViews.LanguageText, param); } /// /// 设置默认语言 /// private async void SetAsDefaultLanguage() { await SetBusyAsync(async () => { await appService.SetDefaultLanguage(new Localization.Dto.SetDefaultLanguageInput() { Name = SelectedItem.Name }).WebAsync(); }); } /// /// 删除语言 /// private async void Delete() { if (await dialog.Question(Local.Localize("LanguageDeleteWarningMessage", SelectedItem.DisplayName))) { await SetBusyAsync(async () => { await appService.DeleteLanguage(new EntityDto(SelectedItem.Id)) .WebAsync(async () => await OnNavigatedToAsync()); }); } } /// /// 获取语言列表 /// /// private async Task GetLanguages() { await appService.GetLanguages().WebAsync(dataPager.SetList); } /// /// 刷新语言列表模块 /// /// public override async Task OnNavigatedToAsync(NavigationContext navigationContext = null) { await SetBusyAsync(GetLanguages); } public override PermissionItem[] CreatePermissionItems() { return new PermissionItem[] { new PermissionItem(AppPermissions.LanguageEdit, Local.Localize("Change"),Edit), new PermissionItem(AppPermissions.LanguageChangeTexts, Local.Localize("ChangeTexts"),ChangeTexts), new PermissionItem(AppPermissions.Languages, Local.Localize("SetAsDefaultLanguage"),SetAsDefaultLanguage), new PermissionItem(AppPermissions.LanguageDelete, Local.Localize("Delete"),Delete) }; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/LoginViewModel.cs ================================================ using Abp.Localization; using AppFramework.ApiClient; using AppFramework.Authorization.Accounts; using AppFramework.Authorization.Accounts.Dto; using AppFramework.Shared; using AppFramework.Admin.Services; using AppFramework.Admin.Services.Account; using Prism.Commands; using Prism.Services.Dialogs; using System; using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using AppFramework.Shared.Services; namespace AppFramework.Admin.ViewModels { public class LoginViewModel : DialogViewModel { #region 字段/属性 public DelegateCommand ExecuteCommand { get; } public DelegateCommand ChangeLanguageCommand { get; } private readonly IHostDialogService dialogService; private readonly IAccountService accountService; private readonly IAccountAppService accountAppService; private readonly IApplicationContext applicationContext; private readonly IAccountStorageService dataStorageService; private readonly IDataStorageService storageService; private string tenancyName; private bool isLoginEnabled; private bool isRememberMe; private string currentTenancyNameOrDefault; public string CurrentTenancyNameOrDefault { get => currentTenancyNameOrDefault; set { currentTenancyNameOrDefault = value; OnPropertyChanged(); } } private LanguageInfo selectedLanguage; private ObservableCollection languages; public bool IsMultiTenancyEnabled { get; set; } public LanguageInfo SelectedLanguage { get => selectedLanguage; set { selectedLanguage = value; OnPropertyChanged(); } } public ObservableCollection Languages { get => languages; set { languages = value; OnPropertyChanged(); } } public string TenancyName { get => tenancyName; set { tenancyName = value; OnPropertyChanged(); } } public string UserName { get => accountService.AuthenticateModel.UserNameOrEmailAddress; set { accountService.AuthenticateModel.UserNameOrEmailAddress = value; SetLoginButtonEnabled(); OnPropertyChanged(); } } public string Password { get => accountService.AuthenticateModel.Password; set { accountService.AuthenticateModel.Password = value; SetLoginButtonEnabled(); OnPropertyChanged(); } } public bool IsLoginEnabled { get { return isLoginEnabled; } set { isLoginEnabled = value; OnPropertyChanged(); } } public bool IsRememberMe { get { return isRememberMe; } set { isRememberMe = value; OnPropertyChanged(); } } #endregion public LoginViewModel(IHostDialogService dialogService, IAccountService accountService, IAccountAppService accountAppService, IApplicationContext applicationContext, IAccountStorageService dataStorageService, IDataStorageService storageService) { this.dialogService = dialogService; this.accountService = accountService; this.accountAppService = accountAppService; this.applicationContext = applicationContext; this.dataStorageService = dataStorageService; this.storageService = storageService; ExecuteCommand = new DelegateCommand(Execute); ChangeLanguageCommand = new DelegateCommand(ChangeLanguage); } private async void Execute(string arg) { switch (arg) { case "LoginUser": await LoginUserAsync(); break; case "ChangeTenant": ChangeTenantAsync(); break; case "ForgotPassword": ForgotPasswordAsync(); break; case "EmailActivation": EmailActivationAsync(); break; } } #region 忘记密码/激活邮件/修改语言/登录/租户 public void SetLoginButtonEnabled() { IsLoginEnabled = !string.IsNullOrWhiteSpace(UserName) && !string.IsNullOrWhiteSpace(Password); } public async void ForgotPasswordAsync() { await dialogService.ShowDialogAsync(AppViews.ForgotPassword, null, AppSharedConsts.LoginIdentifier); } public async void EmailActivationAsync() { await dialogService.ShowDialogAsync(AppViews.EmailActivation, null, AppSharedConsts.LoginIdentifier); } public async void ChangeLanguage(LanguageInfo languageInfo) { applicationContext.CurrentLanguage = languageInfo; await SetBusyAsync(async () => { await UserConfigurationManager.GetAsync().WebAsync(async () => { OnDialogClosed(ButtonResult.Retry); await Task.CompletedTask; }); }); } public async void ChangeTenantAsync() { var dialogResult = await dialogService.ShowDialogAsync(AppViews.SelectTenant, null, AppSharedConsts.LoginIdentifier); if (dialogResult.Result == ButtonResult.OK) { CurrentTenancyNameOrDefault = dialogResult.Parameters.GetValue("Value"); await SetTenantAsync(CurrentTenancyNameOrDefault); } else applicationContext.SetAsTenant(null, 0); } private async Task LoginUserAsync() { await SetBusyAsync(async () => { await accountService.LoginUserAsync().WebAsync(LoginUserSuccessed); }); } private async Task LoginUserSuccessed() { //记住密码? storageService.SetValue(nameof(UserName), IsRememberMe ? UserName : null); storageService.SetValue(nameof(Password), IsRememberMe ? Password : null, true); //清理 UserName = string.Empty; Password = string.Empty; OnDialogClosed(); await Task.CompletedTask; } public async Task SetTenantAsync(string tenancyName) { await SetBusyAsync(async () => { await WebRequest.Execute(() => accountAppService.IsTenantAvailable( new IsTenantAvailableInput { TenancyName = tenancyName }), result => IsTenantAvailableExecuted(result, tenancyName) ); }); } public async Task IsTenantAvailableExecuted(IsTenantAvailableOutput result, string tenancyName) { var tenantAvailableResult = result; IsBusy = false; switch (tenantAvailableResult.State) { case TenantAvailabilityState.Available: applicationContext.SetAsTenant(tenancyName, tenantAvailableResult.TenantId.Value); ApiUrlConfig.ChangeBaseUrl(tenantAvailableResult.ServerRootAddress); OnPropertyChanged(CurrentTenancyNameOrDefault); break; case TenantAvailabilityState.InActive: await dialogService.Question("InActive", Local.Localize("TenantIsNotActive", tenancyName), "Login"); break; case TenantAvailabilityState.NotFound: await dialogService.Question("NotFound", Local.Localize("ThereIsNoTenantDefinedWithName{0}", tenancyName), "Login"); break; default: throw new ArgumentOutOfRangeException(); } await Task.CompletedTask; } #endregion public override async void OnDialogOpened(IDialogParameters parameters) { await SetBusyAsync(async () => { SetAppSettings(); PopulateLoginInfoFromStorage(); await Task.CompletedTask; }); } /// /// 设置应用程序信息 语言/租户选项 /// private void SetAppSettings() { var configuration = applicationContext.Configuration; if (configuration != null) { Languages = new ObservableCollection(configuration.Localization.Languages); var currentLanguage = Languages.FirstOrDefault(l => l.Name == applicationContext.Configuration.Localization.CurrentLanguage.Name); if (currentLanguage != null) SelectedLanguage = currentLanguage; if (applicationContext.CurrentTenant != null) { IsMultiTenancyEnabled = configuration.MultiTenancy.IsEnabled; CurrentTenancyNameOrDefault = applicationContext.CurrentTenant.TenancyName; } } else { CurrentTenancyNameOrDefault = Local.Localize(AppLocalizationKeys.NotSelected); } } /// /// 从本地存储当中读取账户信息, 可能是用户之前登陆的信息 /// private void PopulateLoginInfoFromStorage() { UserName = storageService.GetValue(nameof(UserName), ""); Password = storageService.GetValue(nameof(Password), "", true); var loginInfo = dataStorageService.RetrieveLoginInfo(); if (loginInfo == null) return; if (loginInfo.Tenant != null) TenancyName = loginInfo.Tenant.TenancyName; if (loginInfo.Tenant == null) applicationContext.SetAsHost(); else applicationContext.SetAsTenant(TenancyName, loginInfo.Tenant.Id); OnPropertyChanged("CurrentTenancyNameOrDefault"); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/MainTabsViewModel.cs ================================================ using AppFramework.Shared; using AppFramework.Shared.Models; using AppFramework.Admin.Services; using AppFramework.Admin.Services.Notification; using Prism.Commands; using Prism.Regions; using System.Threading.Tasks; using AppFramework.ApiClient; namespace AppFramework.Admin.ViewModels { public class MainTabsViewModel : NavigationViewModel { public MainTabsViewModel( NotificationService notificationService, IRegionManager regionManager, NavigationService navigationService, IApplicationService appService, IApplicationContext applicationContext) { this.notificationService = notificationService; this.regionManager = regionManager; NavigationService = navigationService; this.appService = appService; this.applicationContext = applicationContext; SettingsCommand = new DelegateCommand(notificationService.Settings); NavigateCommand = new DelegateCommand(Navigate); SeeAllNotificationsCommand = new DelegateCommand(() => { NotificationPanelIsOpen = false; notificationService.SeeAllNotificationsPage(); }); SetNotificationAsRead = new DelegateCommand(notificationService.SetNotificationAsRead); SetAllNotificationsAsReadCommand = new DelegateCommand(notificationService.SetAllNotificationsAsRead); } #region 字段/属性 public NavigationService NavigationService { get; set; } public NotificationService notificationService { get; set; } public IApplicationService appService { get; init; } public DelegateCommand NavigateCommand { get; private set; } private bool notificationPanelIsOpen; private bool isShowFriendsPanel; private readonly IRegionManager regionManager; private readonly IApplicationContext applicationContext; public bool NotificationPanelIsOpen { get { return notificationPanelIsOpen; } set { notificationPanelIsOpen = value; if (value) { AsyncRunner.Run(notificationService.GetNotifications()); } OnPropertyChanged(); } } private bool isShowUserPanel; public bool IsShowUserPanel { get { return isShowUserPanel; } set { if (value && !isShowUserPanel) { regionManager.Regions[AppRegions.UserPanel].RequestNavigate(AppViews.UserPanel); } isShowUserPanel = value; OnPropertyChanged(); } } public bool IsShowFriendsPanel { get { return isShowFriendsPanel; } set { if (value && !isShowFriendsPanel) { regionManager.Regions[AppRegions.UserPanel].RequestNavigate(AppViews.Friends); } isShowUserPanel = isShowFriendsPanel = value; OnPropertyChanged(); OnPropertyChanged(nameof(IsShowUserPanel)); } } public DelegateCommand SeeAllNotificationsCommand { get; private set; } public DelegateCommand SettingsCommand { get; private set; } public DelegateCommand SetAllNotificationsAsReadCommand { get; private set; } public DelegateCommand SetNotificationAsRead { get; private set; } #endregion public void Navigate(NavigationItem item) { if (item==null) return; NavigationService.Navigate(item.PageViewName); } public override async Task OnNavigatedToAsync(NavigationContext navigationContext) { IsShowUserPanel=false; await appService.GetApplicationInfo(); if (applicationContext.Configuration.Auth.GrantedPermissions.ContainsKey(AppPermissions.HostDashboard)) NavigationService.Navigate(AppViews.Dashboard); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Organizations/AddRolesViewModel.cs ================================================ using Abp.Application.Services.Dto; using AppFramework.Organizations; using AppFramework.Organizations.Dto; using Prism.Commands; using Prism.Services.Dialogs; using System; using System.Linq; using System.Threading.Tasks; using AppFramework.Shared.Services; using AppFramework.Shared; using AppFramework.Admin.Models; namespace AppFramework.Admin.ViewModels { public class AddRolesViewModel : HostDialogViewModel { #region 字段/属性 public string Filter { get { return input.Filter; } set { input.Filter = value; OnPropertyChanged(); } } public IDataPagerService dataPager { get; private set; } private readonly IOrganizationUnitAppService appService; public FindOrganizationUnitRolesInput input; public DelegateCommand QueryCommand { get; private set; } #endregion public AddRolesViewModel(IOrganizationUnitAppService appService, IDataPagerService dataPager) { input = new FindOrganizationUnitRolesInput(); QueryCommand = new DelegateCommand(Query); this.appService = appService; this.dataPager = dataPager; dataPager.OnPageIndexChangedEventhandler += RoleOnPageIndexChangedEventhandler; } private async void RoleOnPageIndexChangedEventhandler(object sender, PageIndexChangedEventArgs e) { input.SkipCount = e.SkipCount; input.MaxResultCount = e.PageSize; await SetBusyAsync(async () => { await FindRoles(input); }); } public override async Task Save() { var roleIds = dataPager.GridModelList .Where(t => t is ChooseItem q && q.IsSelected) .Select(t => Convert.ToInt32(((ChooseItem)t).Value.Value)).ToArray(); await SetBusyAsync(async () => { await appService.AddRolesToOrganizationUnit(new RolesToOrganizationUnitInput() { OrganizationUnitId = input.OrganizationUnitId, RoleIds = roleIds }).WebAsync(base.Save); }); } private async Task FindRoles(FindOrganizationUnitRolesInput input) { await appService.FindRoles(input).WebAsync(async result => { await dataPager.SetList(new PagedResultDto() { Items = result.Items.Select(t => new ChooseItem(t)).ToList() }); }); } private void Query() { dataPager.PageIndex = 0; } public override void OnDialogOpened(IDialogParameters parameters) { if (parameters.ContainsKey("Value")) { input.OrganizationUnitId = parameters.GetValue("Id"); var pagedResult = parameters.GetValue>("Value"); dataPager.SetList(new PagedResultDto() { Items = pagedResult.Items.Select(t => new ChooseItem(t)).ToList() }); } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Organizations/AddUsersViewModel.cs ================================================ using Abp.Application.Services.Dto; using AppFramework.Admin.Models; using AppFramework.Organizations; using AppFramework.Organizations.Dto; using Prism.Commands; using Prism.Services.Dialogs; using System; using System.Linq; using System.Threading.Tasks; using AppFramework.Shared.Services; using AppFramework.Shared; namespace AppFramework.Admin.ViewModels { public class AddUsersViewModel : HostDialogViewModel { #region 字段/属性 public string Filter { get { return input.Filter; } set { input.Filter = value; OnPropertyChanged(); } } public IDataPagerService dataPager { get; private set; } private readonly IOrganizationUnitAppService appService; public DelegateCommand QueryCommand { get; private set; } public FindOrganizationUnitUsersInput input; #endregion public AddUsersViewModel(IOrganizationUnitAppService appService, IDataPagerService dataPager) { input = new FindOrganizationUnitUsersInput(); QueryCommand = new DelegateCommand(Query); this.dataPager = dataPager; this.appService = appService; dataPager.OnPageIndexChangedEventhandler += UserOnPageIndexChangedEventhandler; } private async void UserOnPageIndexChangedEventhandler(object sender, PageIndexChangedEventArgs e) { input.SkipCount = e.SkipCount; input.MaxResultCount = e.PageSize; await SetBusyAsync(async () => { await FindUsers(input); }); } public override async Task Save() { var userIds = dataPager.GridModelList .Where(t => t is ChooseItem q && q.IsSelected) .Select(t => Convert.ToInt64(((ChooseItem)t).Value.Value)).ToArray(); await SetBusyAsync(async () => { await appService.AddUsersToOrganizationUnit(new UsersToOrganizationUnitInput() { OrganizationUnitId = input.OrganizationUnitId, UserIds = userIds }).WebAsync(base.Save); }); } private async Task FindUsers(FindOrganizationUnitUsersInput input) { await appService.FindUsers(input).WebAsync(async result => { await dataPager.SetList(new PagedResultDto() { Items = result.Items.Select(t => new ChooseItem(t)).ToList() }); }); } private void Query() { dataPager.PageIndex = 0; } public override void OnDialogOpened(IDialogParameters parameters) { if (parameters.ContainsKey("Value")) { input.OrganizationUnitId = parameters.GetValue("Id"); var pagedResult = parameters.GetValue>("Value"); dataPager.SetList(new PagedResultDto() { Items = pagedResult.Items.Select(t => new ChooseItem(t)).ToList() }); } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Organizations/OrganizationsAddViewModel.cs ================================================ using AppFramework.Shared; using AppFramework.Admin.Models; using AppFramework.Organizations; using AppFramework.Organizations.Dto; using Prism.Services.Dialogs; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels { public class OrganizationsAddViewModel : HostDialogViewModel { public OrganizationsAddViewModel(IOrganizationUnitAppService appService) { this.appService = appService; } #region 字段/属性 private long? ParentId; private bool IsNewOrganization; private OrganizationListModel input; private readonly IOrganizationUnitAppService appService; public OrganizationListModel Input { get { return input; } set { input = value; OnPropertyChanged(); } } #endregion public override async Task Save() { await SetBusyAsync(async () => { if (IsNewOrganization) { await appService.CreateOrganizationUnit( new CreateOrganizationUnitInput() { DisplayName = input.DisplayName, ParentId = ParentId }).WebAsync(); } else { await appService.UpdateOrganizationUnit( new UpdateOrganizationUnitInput() { Id = input.Id, DisplayName = input.DisplayName }).WebAsync(); } }); await base.Save(); } public override void OnDialogOpened(IDialogParameters parameters) { if (parameters.ContainsKey("Value")) { Input = parameters.GetValue("Value"); } else { IsNewOrganization = true; Input = new OrganizationListModel(); } if (parameters.ContainsKey("ParentId")) ParentId = parameters.GetValue("ParentId"); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Organizations/OrganizationsViewModel.cs ================================================ using Abp.Application.Services.Dto; using AppFramework.Shared; using AppFramework.Admin.Models; using AppFramework.Organizations; using AppFramework.Organizations.Dto; using Prism.Commands; using Prism.Services.Dialogs; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using Prism.Ioc; using System.Threading.Tasks; using Prism.Regions; using AppFramework.Shared.Services; using CommunityToolkit.Mvvm.Input; namespace AppFramework.Admin.ViewModels { public partial class OrganizationsViewModel : NavigationCurdViewModel { public OrganizationsViewModel(IOrganizationUnitAppService userAppService) { Title = Local.Localize("OrganizationUnits"); this.appService = userAppService; usersInput = new GetOrganizationUnitUsersInput(); rolesInput = new GetOrganizationUnitRolesInput(); roledataPager = ContainerLocator.Container.Resolve(); roledataPager.OnPageIndexChangedEventhandler += RoleOnPageIndexChangedEventhandler; memberdataPager = ContainerLocator.Container.Resolve(); memberdataPager.OnPageIndexChangedEventhandler += MemberdataPager_OnPageIndexChangedEventhandler; ExecuteItemCommand = new DelegateCommand(ExecuteItem); } private async void MemberdataPager_OnPageIndexChangedEventhandler(object sender, PageIndexChangedEventArgs e) { if (usersInput.Id == 0) return; usersInput.SkipCount = e.SkipCount; usersInput.MaxResultCount = e.PageSize; await SetBusyAsync(async () => { await GetOrganizationUnitUsers(usersInput); }); } private async void RoleOnPageIndexChangedEventhandler(object sender, PageIndexChangedEventArgs e) { if (rolesInput.Id == 0) return; rolesInput.SkipCount = e.SkipCount; rolesInput.MaxResultCount = e.PageSize; await SetBusyAsync(async () => { await GetOrganizationUnitRoles(rolesInput); }); } #region 字段/属性 private OrganizationListModel SelectedOrganizationUnit; private readonly IOrganizationUnitAppService appService; public IDataPagerService roledataPager { get; private set; } public IDataPagerService memberdataPager { get; private set; } private GetOrganizationUnitUsersInput usersInput; private GetOrganizationUnitRolesInput rolesInput; //选中组织、添加跟组织、修改、删除组织 public DelegateCommand ExecuteItemCommand { get; private set; } #endregion #region 组织机构 /// /// 选中组织机构-更新成员和角色信息 /// /// [RelayCommand] private async void Selected(OrganizationListModel organizationUnit) { if (organizationUnit == null) return; SelectedOrganizationUnit = organizationUnit; rolesInput.Id = SelectedOrganizationUnit.Id; usersInput.Id = SelectedOrganizationUnit.Id; await GetOrganizationUnitUsers(usersInput); await GetOrganizationUnitRoles(rolesInput); } /// /// UI的按钮命令 /// 说明: 添加组织、添加成员、添加角色、刷新组织机构树 /// /// public async void ExecuteItem(string arg) { switch (arg) { case "AddOrganizationUnit": AddRootUnit(); break; case "AddMember": await AddMember(SelectedOrganizationUnit); break; case "AddRole": await AddRole(SelectedOrganizationUnit); break; case "Refresh": await OnNavigatedToAsync(); break; } } /// /// 刷新组织结构树 /// /// public override async Task OnNavigatedToAsync(NavigationContext navigationContext = null) { await SetBusyAsync(async () => { await appService.GetOrganizationUnits().WebAsync(async result => { dataPager.GridModelList.Clear(); var items = BuildOrganizationTree(Map>(result.Items)); foreach (var item in items) dataPager.GridModelList.Add(item); await Task.CompletedTask; }); }); } /// /// 删除组织机构 /// /// [RelayCommand] public async void Remove(OrganizationListModel organization) { if (await dialog.Question(Local.Localize("OrganizationUnitDeleteWarningMessage", organization.DisplayName))) { await appService.DeleteOrganizationUnit(new EntityDto() { Id = organization.Id }) .WebAsync(async () => await OnNavigatedToAsync()); } } /// /// 编辑组织机构 /// /// [RelayCommand] public async void Change(OrganizationListModel organization) { DialogParameters param = new DialogParameters(); param.Add("Value", organization); var dialogResult = await dialog.ShowDialogAsync("OrganizationsAddView", param); if (dialogResult.Result == ButtonResult.OK) await OnNavigatedToAsync(); } /// /// 新增组织机构 /// /// [RelayCommand] public async void AddRootUnit(OrganizationListModel organization = null) { DialogParameters param = new DialogParameters(); if (organization != null) param.Add("ParentId", organization.Id); var dialogResult = await dialog.ShowDialogAsync("OrganizationsAddView", param); if (dialogResult.Result == ButtonResult.OK) await OnNavigatedToAsync(); } /// /// 更新组织机构显示信息 /// /// private void UpdateOrganizationUnit(long id) { var organizationUnit = dataPager.GridModelList .FirstOrDefault(t => t is OrganizationListModel q && q.Id.Equals(id)) as OrganizationListModel; if (organizationUnit != null) { organizationUnit.MemberCount = memberdataPager.GridModelList.Count; organizationUnit.RoleCount = roledataPager.GridModelList.Count; } } public ObservableCollection BuildOrganizationTree( List organizationUnits, long? parentId = null) { var masters = organizationUnits .Where(x => x.ParentId == parentId).ToList(); var childs = organizationUnits .Where(x => x.ParentId != parentId).ToList(); foreach (OrganizationListModel dpt in masters) dpt.Items = BuildOrganizationTree(childs, dpt.Id); return new ObservableCollection(masters); } #endregion #region 角色 /// /// 添加角色 /// /// /// private async Task AddRole(OrganizationListModel organizationUnit) { if (organizationUnit == null) return; long Id = organizationUnit.Id; await appService.FindRoles(new FindOrganizationUnitRolesInput() { OrganizationUnitId = Id }) .WebAsync(async result => { DialogParameters param = new DialogParameters(); param.Add("Id", Id); param.Add("Value", result); var dialogResult = await dialog.ShowDialogAsync(AppViews.AddRoles, param); if (dialogResult.Result == ButtonResult.OK) { rolesInput.Id = Id; await GetOrganizationUnitRoles(rolesInput); } }); } /// /// 刷新角色 /// /// /// private async Task GetOrganizationUnitRoles(GetOrganizationUnitRolesInput input) { await SetBusyAsync(async () => { var pagedResult = await appService.GetOrganizationUnitRoles(input); if (pagedResult != null) await roledataPager.SetList(pagedResult); UpdateOrganizationUnit(input.Id); }); } /// /// 删除角色 /// /// [RelayCommand] private async void DeleteRole(OrganizationUnitRoleListDto obj) { if (await dialog.Question(Local.Localize("RemoveRoleFromOuWarningMessage", SelectedOrganizationUnit.DisplayName, obj.DisplayName))) { await SetBusyAsync(async () => { await appService.RemoveRoleFromOrganizationUnit(new RoleToOrganizationUnitInput() { RoleId = (int)obj.Id, OrganizationUnitId = SelectedOrganizationUnit.Id }) .WebAsync(async () => { rolesInput.Id = SelectedOrganizationUnit.Id; await GetOrganizationUnitRoles(rolesInput); }); }); } } #endregion #region 成员 /// /// 添加成员 /// /// /// private async Task AddMember(OrganizationListModel organizationUnit) { if (organizationUnit == null) return; long Id = organizationUnit.Id; await appService.FindUsers(new FindOrganizationUnitUsersInput() { OrganizationUnitId = Id }).WebAsync(async result => { DialogParameters param = new DialogParameters(); param.Add("Id", Id); param.Add("Value", result); var dialogResult = await dialog.ShowDialogAsync(AppViews.AddUsers, param); if (dialogResult.Result == ButtonResult.OK) await GetOrganizationUnitUsers(usersInput); }); } /// /// 刷新成员 /// /// /// private async Task GetOrganizationUnitUsers(GetOrganizationUnitUsersInput input) { await SetBusyAsync(async () => { var pagedResult = await appService.GetOrganizationUnitUsers(input); if (pagedResult != null) await memberdataPager.SetList(pagedResult); UpdateOrganizationUnit(input.Id); }); } /// /// 删除成员 /// /// [RelayCommand] private async void DeleteMember(OrganizationUnitUserListDto obj) { if (await dialog.Question(Local.Localize("RemoveUserFromOuWarningMessage", SelectedOrganizationUnit.DisplayName, obj.UserName))) { await SetBusyAsync(async () => { await appService.RemoveUserFromOrganizationUnit(new UserToOrganizationUnitInput() { OrganizationUnitId = SelectedOrganizationUnit.Id, UserId = obj.Id }).WebAsync(async () => { await GetOrganizationUnitUsers(usersInput); }); }); } } #endregion } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Roles/RoleDetailsViewModel.cs ================================================ using Abp.Application.Services.Dto; using AppFramework.Authorization.Roles; using AppFramework.Authorization.Roles.Dto; using AppFramework.Shared; using AppFramework.Admin.Models; using Prism.Services.Dialogs; using AppFramework.Admin.Services; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels { public class RoleDetailsViewModel : HostDialogViewModel { #region 字段/属性 private readonly IRoleAppService appService; public IPermissionTreesService treesService { get; set; } private RoleEditModel role; public RoleEditModel Role { get { return role; } set { role = value; OnPropertyChanged(); } } #endregion 字段/属性 public RoleDetailsViewModel(IRoleAppService appService, IPermissionTreesService treesService) { this.appService = appService; this.treesService = treesService; } public override async Task Save() { await SetBusyAsync(async () => { await appService.CreateOrUpdateRole(new CreateOrUpdateRoleInput() { Role = Map(Role), GrantedPermissionNames = treesService.GetSelectedItems() }).WebAsync(base.Save); }); } public override async void OnDialogOpened(IDialogParameters parameters) { await SetBusyAsync(async () => { int? id = null; if (parameters != null && parameters.ContainsKey("Value")) id = parameters.GetValue("Value").Id; var output = await appService.GetRoleForEdit(new NullableIdDto(id)); Role = Map(output.Role); treesService.CreatePermissionTrees(output.Permissions, output.GrantedPermissionNames); }); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Roles/RoleViewModel.cs ================================================ using Abp.Application.Services.Dto; using AppFramework.Authorization.Permissions; using AppFramework.Authorization.Permissions.Dto; using AppFramework.Authorization.Roles; using AppFramework.Authorization.Roles.Dto; using AppFramework.Shared; using AppFramework.Shared.Services; using AppFramework.Shared.Services.Permission; using CommunityToolkit.Mvvm.Input; using Prism.Commands; using Prism.Regions; using Prism.Services.Dialogs; using System.Collections.Generic; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels { public partial class RoleViewModel : NavigationCurdViewModel { #region 字段/属性 private readonly IRoleAppService appService; private readonly IPermissionAppService permissionAppService; public GetRolesInput input; private string selectPermissions = string.Empty; /// /// 已选择权限的文本 /// public string SelectPermissions { get { return selectPermissions; } set { selectPermissions = value; OnPropertyChanged(); } } private ListResultDto flatPermission; #endregion public RoleViewModel(IRoleAppService appService, IPermissionAppService permissionAppService) { Title = Local.Localize("Roles"); this.appService = appService; this.permissionAppService = permissionAppService; input = new GetRolesInput(); dataPager.OnPageIndexChangedEventhandler += RoleOnPageIndexChangedEventhandler; UpdateTitle(); } private async void RoleOnPageIndexChangedEventhandler(object sender, PageIndexChangedEventArgs e) { //filter... await SetBusyAsync(async () => { await GetRoles(input); }); } private void UpdateTitle(int count = 0) { SelectPermissions = Local.Localize("SelectPermissions") + $"({count})"; } /// /// 选择权限 /// [RelayCommand] private async void Selected() { DialogParameters param = new DialogParameters(); param.Add("Value", flatPermission); var dialogResult = await dialog.ShowDialogAsync(AppViews.SelectedPermission, param); if (dialogResult.Result == Prism.Services.Dialogs.ButtonResult.OK) { var selectedPermissions = dialogResult.Parameters.GetValue>("Value"); input.Permissions = selectedPermissions; UpdateTitle(selectedPermissions.Count); await OnNavigatedToAsync(); } } /// /// 删除角色 /// public async void Delete() { if (dataPager.SelectedItem is RoleListDto item) { if (await dialog.Question(Local.Localize("RoleDeleteWarningMessage", item.DisplayName))) { await SetBusyAsync(async () => { await appService.DeleteRole(new EntityDto(item.Id)) .WebAsync(async () => await OnNavigatedToAsync()); }); } } } /// /// 获取角色列表 /// /// /// private async Task GetRoles(GetRolesInput filter) { await appService.GetRoles(filter).WebAsync(dataPager.SetList); } /// /// 刷新角色模块 /// /// public override async Task OnNavigatedToAsync(NavigationContext navigationContext = null) { await SetBusyAsync(async () => { if (flatPermission == null) { await permissionAppService.GetAllPermissions().WebAsync(result => { flatPermission = result; return Task.CompletedTask; }); } await GetRoles(input); }); } public override PermissionItem[] CreatePermissionItems() { return new PermissionItem[] { new PermissionItem(AppPermissions.RoleEdit, Local.Localize("Change"),Edit), new PermissionItem(AppPermissions.RoleDelete, Local.Localize("Delete"),Delete) }; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Roles/SelectedPermissionViewModel.cs ================================================ using Abp.Application.Services.Dto; using AppFramework.Authorization.Permissions.Dto; using AppFramework.Shared; using Prism.Services.Dialogs; using System.Collections.Generic; using System.Linq; using AppFramework.Admin.Services; using System.Runtime.CompilerServices; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels { public class SelectedPermissionViewModel : HostDialogViewModel { public IPermissionTreesService treesService { get; set; } public SelectedPermissionViewModel(IPermissionTreesService treesService) { this.treesService = treesService; } public override async Task Save() { base.Save(treesService.GetSelectedItems()); await Task.CompletedTask; } public override void OnDialogOpened(IDialogParameters parameters) { if (parameters.ContainsKey("Value")) { var flatPermissions = parameters.GetValue>("Value"); var permissions = flatPermissions.Items.Select(t => t as FlatPermissionDto).ToList(); treesService.CreatePermissionTrees(permissions, new List()); } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Settings/SettingsViewModel.cs ================================================ using AppFramework.Shared; using AppFramework.Shared.Models.Configuration; using AppFramework.Configuration.Host; using AppFramework.Configuration.Host.Dto; using AppFramework.Editions.Dto; using AppFramework.Admin.ViewModels.Shared; using Prism.Commands; using Prism.Regions; using System; using System.Collections.ObjectModel; using System.Threading.Tasks; using AppFramework.Common; using CommunityToolkit.Mvvm.Input; namespace AppFramework.Admin.ViewModels { public partial class SettingsViewModel : NavigationViewModel { #region 字段/属性 private readonly IHostSettingsAppService appService; private readonly ICommonLookupAppService lookupAppService; private HostSettingsEditModel setting; private SubscribableEditionComboboxItemDto selectedEdition; private ObservableCollection editions; public HostSettingsEditModel Setting { get { return setting; } set { setting = value; OnPropertyChanged(); } } /// /// 选中版本 /// public SubscribableEditionComboboxItemDto SelectedEdition { get { return selectedEdition; } set { selectedEdition = value; if (selectedEdition != null) setting.TenantManagement.DefaultEditionId = Convert.ToInt32(value.Value); OnPropertyChanged(); } } /// /// 版本列表 /// public ObservableCollection Editions { get => editions; set { editions = value; OnPropertyChanged(); } } #endregion public SettingsViewModel(IHostSettingsAppService appService, ICommonLookupAppService lookupAppService) { Title = Local.Localize("Settings"); this.appService = appService; this.lookupAppService = lookupAppService; editions = new ObservableCollection(); } [RelayCommand] private async void Save() { //验证输入合法性... var input = Map(Setting); await SetBusyAsync(async () => { await appService.UpdateAllSettings(input).WebAsync(); }); } /// /// 获取系统设置信息 /// /// private async Task GetSettings() { await appService.GetAllSettings().WebAsync(async result => { Setting = Map(result); await Task.CompletedTask; }); } /// /// 获取版本列表 /// /// private async Task GetEditions() { await lookupAppService.GetEditionsForCombobox().WebAsync(async result => { foreach (var item in result.Items) Editions.Add(item); await Task.CompletedTask; }); } public override async Task OnNavigatedToAsync(NavigationContext navigationContext) { await SetBusyAsync(async () => { await GetSettings(); await GetEditions(); }); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Shared/DemoUiViewModel.cs ================================================ using AppFramework.Shared; namespace AppFramework.Admin.ViewModels.Shared { public class DemoUiViewModel : NavigationViewModel { public DemoUiViewModel() { Title = Local.Localize("DemoUiComponents"); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Shared/FirstChangedPwdViewModel.cs ================================================ using AppFramework.ApiClient; using AppFramework.ApiClient.Models; using AppFramework.Authorization.Accounts; using AppFramework.Authorization.Accounts.Dto; using AppFramework.Shared; using Prism.Services.Dialogs; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels.Shared { public class FirstChangedPwdViewModel : HostDialogViewModel { private readonly IAccountAppService appService; private readonly IAccessTokenManager accessTokenManager; private readonly AbpAuthenticateModel authenticateModel; public FirstChangedPwdViewModel( IAccountAppService appService, IAccessTokenManager accessTokenManager, AbpAuthenticateModel authenticateModel) { this.appService = appService; this.accessTokenManager = accessTokenManager; this.authenticateModel = authenticateModel; } private string passWord; private string newpassWord; private string errorMessage; public string PassWord { get { return passWord; } set { passWord = value; ValidationPassWord(); OnPropertyChanged(); } } public string NewPassWord { get { return newpassWord; } set { newpassWord = value; ValidationPassWord(); OnPropertyChanged(); } } public string ErrorMessage { get { return errorMessage; } set { errorMessage = value; OnPropertyChanged(); } } private AbpAuthenticateResultModel model; public override async Task Save() { if (ValidationPassWord()) { //密码策略验证... await SetBusyAsync(async () => { await WebRequest.Execute(() => appService.ResetPassword( new ResetPasswordInput() { UserId = model.UserId, Password = PassWord, ResetCode = model.PasswordResetCode }), ResetPasswordSuccessed); }); } } private async Task ResetPasswordSuccessed(ResetPasswordOutput output) { if (output.CanLogin) { authenticateModel.Password = PassWord; await accessTokenManager.LoginAsync().WebAsync(base.Save); } else base.Cancel(); } private bool ValidationPassWord() { if (!string.IsNullOrWhiteSpace(PassWord) && !string.IsNullOrWhiteSpace(NewPassWord)) { if (PassWord != NewPassWord) ErrorMessage = Local.Localize("PasswordsDontMatch"); else { ErrorMessage = string.Empty; return true; } } return false; } public override void OnDialogOpened(IDialogParameters parameters) { model = parameters.GetValue("Value"); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Shared/SelectTenantViewModel.cs ================================================ using AppFramework.Shared; using Prism.Services.Dialogs; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels.Shared { public class SelectTenantViewModel : HostDialogViewModel { private string tenancyName = string.Empty; private bool isLoginForTenants; public string TenancyName { get { return tenancyName; } set { tenancyName = value; OnPropertyChanged(); } } public bool IsLoginForTenants { get { return isLoginForTenants; } set { isLoginForTenants = value; if (!value) TenancyName = string.Empty; OnPropertyChanged(); } } public override async Task Save() { base.Save(IsLoginForTenants ? TenancyName : ""); await Task.CompletedTask; } public override void OnDialogOpened(IDialogParameters parameters) { } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Shared/UserPanelViewModel.cs ================================================ using AppFramework.Admin.Services; using AppFramework.Shared; using Prism.Mvvm; using Prism.Regions; using System.Threading.Tasks; using Prism.Ioc; using Prism.Commands; namespace AppFramework.Admin.ViewModels { public class UserPanelViewModel : NavigationViewModel { public IApplicationService appService { get; set; } public DelegateCommand ExecuteUserActionCommand { get; private set; } public override async Task OnNavigatedToAsync(NavigationContext navigationContext = null) { appService = ContainerLocator.Container.Resolve(); ExecuteUserActionCommand = new DelegateCommand(appService.ExecuteUserAction); await Task.CompletedTask; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/SplashScreenViewModel.cs ================================================ using AppFramework.ApiClient; using AppFramework.Shared; using AppFramework.Shared.Services; using AppFramework.Admin.Services.Account; using Prism.Services.Dialogs; using System.Threading.Tasks; using System; namespace AppFramework.Admin.ViewModels { public class SplashScreenViewModel : DialogViewModel { private readonly IAccessTokenManager accessTokenManager; private readonly IAccountStorageService dataStorageService; private readonly IApplicationContext applicationContext; private string displayText; public string DisplayText { get { return displayText; } set { displayText = value; OnPropertyChanged(); } } public SplashScreenViewModel( IApplicationContext applicationContext, IAccessTokenManager accessTokenManager, IAccountStorageService dataStorageService) { this.applicationContext = applicationContext; this.accessTokenManager = accessTokenManager; this.dataStorageService = dataStorageService; } public override async void OnDialogOpened(IDialogParameters parameters) { await SetBusyAsync(async () => { await Task.Delay(200); //加载本地的缓存信息 DisplayText = LocalTranslationHelper.Localize("Initializing"); accessTokenManager.AuthenticateResult = dataStorageService.RetrieveAuthenticateResult(); applicationContext.Load(dataStorageService.RetrieveTenantInfo(), dataStorageService.RetrieveLoginInfo()); //加载系统资源 DisplayText = LocalTranslationHelper.Localize("LoadResource"); await UserConfigurationManager.GetIfNeedsAsync(GetIfNeedsFailCallback); //如果本地授权存在,直接进入系统首页 if (accessTokenManager.IsUserLoggedIn && applicationContext.Configuration != null) OnDialogClosed(); else if (applicationContext.Configuration != null) OnDialogClosed(ButtonResult.Ignore); else OnDialogClosed(ButtonResult.No); }); } private async Task GetIfNeedsFailCallback(Exception ex) { OnDialogClosed(ButtonResult.No); await Task.CompletedTask; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/TaskBarViewModel.cs ================================================ using AppFramework.Shared; using Prism.Commands; using Prism.Mvvm; using Prism.Ioc; using AppFramework.Shared.Services.App; using AppFramework.Shared.Services; namespace AppFramework.Admin.ViewModels { public class TaskBarViewModel : BindableBase { private readonly IHostDialogService dialog; private readonly IAppStartService appStartService; public DelegateCommand ExitCommand { get; set; } public DelegateCommand ShowViewCommand { get; private set; } public TaskBarViewModel() { dialog = ContainerLocator.Container.Resolve(); appStartService= ContainerLocator.Container.Resolve(); ExitCommand = new DelegateCommand(Exit); ShowViewCommand = new DelegateCommand(ShowView); } private async void Exit() { ShowView(); if (await dialog.Question(Local.Localize("AreYouSure"))) appStartService.Exit(); } private void ShowView() { if (!System.Windows.Application.Current.MainWindow.IsVisible) { System.Windows.Application.Current.MainWindow.Show(); System.Windows.Application.Current.MainWindow.WindowState = System.Windows.WindowState.Normal; } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Tenants/TenantChangeFeaturesViewModel.cs ================================================ using AppFramework.Shared; using AppFramework.MultiTenancy; using AppFramework.MultiTenancy.Dto; using Prism.Services.Dialogs; using System.Threading.Tasks; using AppFramework.Admin.Services; namespace AppFramework.Admin.ViewModels { public class TenantChangeFeaturesViewModel : HostDialogViewModel { private int Id; private readonly ITenantAppService tenantAppService; public IFeaturesService featuresService { get; set; } public TenantChangeFeaturesViewModel(IFeaturesService featuresService, ITenantAppService tenantAppService) { this.featuresService = featuresService; this.tenantAppService = tenantAppService; } public override async Task Save() { await SetBusyAsync(async () => { await tenantAppService.UpdateTenantFeatures(new UpdateTenantFeaturesInput() { Id = Id, FeatureValues = featuresService.GetSelectedItems() }).WebAsync(base.Save); }); } public override void OnDialogOpened(IDialogParameters parameters) { if (parameters.ContainsKey("Id")) Id = parameters.GetValue("Id"); if (parameters.ContainsKey("Value")) { var output = parameters.GetValue("Value"); featuresService.CreateFeatures(output.Features, output.FeatureValues); } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Tenants/TenantDetailsViewModel.cs ================================================ using Abp.Runtime.Security; using AppFramework.Shared; using AppFramework.Admin.Models; using AppFramework.Editions.Dto; using AppFramework.MultiTenancy; using AppFramework.MultiTenancy.Dto; using Prism.Services.Dialogs; using System; using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; using AppFramework.Common; namespace AppFramework.Admin.ViewModels { public class TenantDetailsViewModel : HostDialogViewModel { private readonly ITenantAppService tenantAppService; private readonly IPermissionService permissionService; private readonly ICommonLookupAppService commonLookupAppService; public TenantDetailsViewModel( ITenantAppService tenantAppService, ICommonLookupAppService commonLookupAppService, IPermissionService permissionService) { this.tenantAppService = tenantAppService; this.permissionService = permissionService; this.commonLookupAppService = commonLookupAppService; } #region 字段/属性 private const string NotAssignedValue = "0"; private bool isSubscriptionFieldVisible; private bool isUnlimitedTimeSubscription; private bool isNewTenant; private string pageTitle; private bool useHostDatabase; private string adminPassword; private string adminPasswordRepeat; private bool isSetRandomPassword; private TenantListModel model; private ObservableCollection editions; private SubscribableEditionComboboxItemDto selectedEdition; public ObservableCollection Editions { get => editions; set { editions = value; OnPropertyChanged(); } } //是否无限时间订阅 public bool IsUnlimitedTimeSubscription { get => isUnlimitedTimeSubscription; set { isUnlimitedTimeSubscription = value; if (isUnlimitedTimeSubscription) { //如果是无时间订阅限制, 将订阅事件设置为null model.SubscriptionEndDateUtc = null; } else { //如果不是无限时间订阅,重置是否到期选项 model.IsInTrialPeriod = false; } OnPropertyChanged(); } } public bool IsNewTenant { get => isNewTenant; set { isNewTenant = value; PageTitle = isNewTenant ? Local.Localize(AppLocalizationKeys.CreatingNewTenant) : Local.Localize(AppLocalizationKeys.EditTenant); OnPropertyChanged(); } } public string PageTitle { get => pageTitle; set { pageTitle = value; OnPropertyChanged(); } } //管理员密码 public string AdminPassword { get => adminPassword; set { adminPassword = value; OnPropertyChanged(); } } //管理员密码重复 public string AdminPasswordRepeat { get => adminPasswordRepeat; set { adminPasswordRepeat = value; OnPropertyChanged(); } } //使用主机数据库 public bool UseHostDatabase { get => useHostDatabase; set { useHostDatabase = value; OnPropertyChanged(); } } //是否设置随机密码 public bool IsSetRandomPassword { get => isSetRandomPassword; set { isSetRandomPassword = value; if (isSetRandomPassword) { AdminPassword = null; AdminPasswordRepeat = null; } OnPropertyChanged(); } } public bool IsSelectedEditionFree { get { if (Model == null || SelectedEdition == null) return true; if (!Model.EditionId.HasValue) return true; if (!SelectedEdition.IsFree.HasValue) return true; return SelectedEdition.IsFree.Value; } } public SubscribableEditionComboboxItemDto SelectedEdition { get => selectedEdition; set { selectedEdition = value; UpdateModel(); IsSubscriptionFieldVisible = SelectedEdition != null && SelectedEdition.Value != NotAssignedValue; OnPropertyChanged("IsSelectedEditionFree"); OnPropertyChanged(); } } //订阅字段是否可见 public bool IsSubscriptionFieldVisible { get => isSubscriptionFieldVisible; set { isSubscriptionFieldVisible = value; OnPropertyChanged(); } } public TenantListModel Model { get => model; set { model = value; OnPropertyChanged(); } } #endregion #region 内部方法 private void InitializeNewTenant() { IsNewTenant = true; Model = new TenantListModel { IsActive = true }; UseHostDatabase = true; IsSetRandomPassword = true; } private void InitializeEditTenant() { IsNewTenant = false; IsSetRandomPassword = false; UseHostDatabase = string.IsNullOrEmpty(Model.ConnectionString); if (!string.IsNullOrEmpty(Model.ConnectionString)) Model.ConnectionString = TryDecryptConnectionString(); } private string TryDecryptConnectionString() { try { return SimpleStringCipher.Instance.Decrypt(Model.ConnectionString); } catch (Exception ex) { return null; } } private void NormalizeTenantUpdateInput(TenantEditDto input) { input.EditionId = NormalizeEditionId(input.EditionId); input.SubscriptionEndDateUtc = NormalizeSubscriptionEndDateUtc(input.SubscriptionEndDateUtc); } private void NormalizeTenantCreateInput(CreateTenantInput input) { input.EditionId = NormalizeEditionId(input.EditionId); input.SubscriptionEndDateUtc = NormalizeSubscriptionEndDateUtc(input.SubscriptionEndDateUtc); } private int? NormalizeEditionId(int? editionId) { return editionId.HasValue && editionId.Value == 0 ? null : editionId; } private DateTime? NormalizeSubscriptionEndDateUtc(DateTime? subscriptionEndDateUtc) { if (IsUnlimitedTimeSubscription) return null; return subscriptionEndDateUtc?.Date.AddDays(1).AddTicks(-1); } private async Task PopulateEditionsCombobox(Action editionsPopulated) { var editions = await commonLookupAppService.GetEditionsForCombobox(); if(editions!=null) { Editions = new ObservableCollection(editions.Items); AddNotAssignedItem(); editionsPopulated(); } } private void AddNotAssignedItem() { Editions.Insert(0, new SubscribableEditionComboboxItemDto(NotAssignedValue, string.Format("- {0} -", Local.Localize(AppLocalizationKeys.NotAssigned)), null)); } private void SetSelectedEdition(int? editionId) { SelectedEdition = editionId.HasValue ? Editions.Single(e => e.Value == editionId.Value.ToString()) : Editions.Single(e => e.Value == NotAssignedValue); } private void UpdateModel() { if (SelectedEdition != null && int.TryParse(SelectedEdition.Value, out var selectedEditionId)) Model.EditionId = selectedEditionId; else Model.EditionId = null; Model.IsInTrialPeriod = !IsSelectedEditionFree; } #endregion 内部方法 public override async Task Save() { if (IsNewTenant) { var input = Map(Model); input.AdminPassword = AdminPassword; NormalizeTenantCreateInput(input); if (!Verify(input).IsValid) return; await CreateTenantAsync(input); } else { var input = Map(Model); NormalizeTenantUpdateInput(input); if (!Verify(input).IsValid) return; await UpdateTenantAsync(input); } } private async Task UpdateTenantAsync(TenantEditDto input) { await SetBusyAsync(async () => { await tenantAppService.UpdateTenant(input).WebAsync(base.Save); }); } private async Task CreateTenantAsync(CreateTenantInput input) { await SetBusyAsync(async () => { await tenantAppService.CreateTenant(input).WebAsync(base.Save); }); } public override async void OnDialogOpened(IDialogParameters parameters) { await SetBusyAsync(async () => { if (parameters.ContainsKey("Value")) { var tenant = parameters.GetValue("Value"); Model = Map(tenant); InitializeEditTenant(); } else InitializeNewTenant(); await PopulateEditionsCombobox(() => { if (Model != null) SetSelectedEdition(Model.EditionId); }); }); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Tenants/TenantViewModel.cs ================================================ using Abp.Application.Services.Dto; using AppFramework.Shared; using AppFramework.Shared.Services.Permission; using AppFramework.Editions; using AppFramework.Admin.Models; using AppFramework.MultiTenancy; using AppFramework.MultiTenancy.Dto; using Prism.Commands; using System.Collections.Generic; using System.Threading.Tasks; using System.Collections.ObjectModel; using Prism.Services.Dialogs; using AppFramework.Admin.ViewModels.Shared; using Prism.Regions; using AppFramework.Shared.Services; using CommunityToolkit.Mvvm.Input; namespace AppFramework.Admin.ViewModels { public partial class TenantViewModel : NavigationCurdViewModel { #region 字段/属性 private readonly ITenantAppService appService; private readonly IEditionAppService editionAppService; private bool isSubscription; private bool isCreation; private GetTenantsFilter filter; private EditionListModel edition; private ObservableCollection editions; /// /// 启用订阅日期查询 /// public bool IsSubscription { get { return isSubscription; } set { isSubscription = value; if (value) { Filter.SubscriptionEndDateStart = null; Filter.SubscriptionEndDateEnd = null; } OnPropertyChanged(); } } /// /// 启用创建时间查询 /// public bool IsCreation { get { return isCreation; } set { isCreation = value; if (value) { Filter.CreationDateStart = null; Filter.CreationDateEnd = null; } OnPropertyChanged(); } } public GetTenantsFilter Filter { get { return filter; } set { filter = value; OnPropertyChanged(); } } public EditionListModel Edition { get { return edition; } set { edition = value; OnPropertyChanged(); } } public ObservableCollection Editions { get { return editions; } set { editions = value; OnPropertyChanged(); } } #endregion public TenantListModel SelectedItem => Map(dataPager.SelectedItem); public TenantViewModel(ITenantAppService appService, IEditionAppService editionAppService) { Title = Local.Localize("TenantManagement"); filter = new GetTenantsFilter() { EditionIdSpecified = false, MaxResultCount = 10, SkipCount = 0, }; this.appService = appService; this.editionAppService = editionAppService; dataPager.OnPageIndexChangedEventhandler += TenantOnPageIndexChangedEventhandler; editions = new ObservableCollection(); } private async void TenantOnPageIndexChangedEventhandler(object sender, PageIndexChangedEventArgs e) { filter.SkipCount = e.SkipCount; filter.MaxResultCount = e.PageSize; await SetBusyAsync(GetTenants); } /// /// 搜索 /// [RelayCommand] private void Search() { dataPager.PageIndex = 0; } /// /// 获取租户列表 /// /// private async Task GetTenants() { var input = Map(filter); await appService.GetTenants(input).WebAsync(dataPager.SetList); } /// /// 获取筛选版本列表 /// /// public async Task GetAllEditions() { if (Editions.Count > 0) return; await editionAppService.GetEditions().WebAsync(async result => { Editions.Clear(); foreach (var item in Map>(result.Items)) Editions.Add(item); await Task.CompletedTask; }); } #region 修改租户/使用当前租户登录/解锁/删除 /// /// 修改租户功能 /// /// private async void TenantChangeFeatures() { GetTenantFeaturesEditOutput output = null; await SetBusyAsync(async () => { await appService.GetTenantFeaturesForEdit(new EntityDto(SelectedItem.Id)).WebAsync(async result => { output = result; await Task.CompletedTask; }); }); if (output == null) return; DialogParameters param = new DialogParameters(); param.Add("Id", SelectedItem.Id); param.Add("Value", output); await dialog.ShowDialogAsync(AppViews.TenantChangeFeatures, param); } /// /// 使用租户登录 /// private void TenantImpersonation() { //..使用当前租户登录 } /// /// 解锁租户 /// private async void Unlock() { await SetBusyAsync(async () => { await appService.UnlockTenantAdmin(new EntityDto(SelectedItem.Id)) .WebAsync(async () => await OnNavigatedToAsync()); }); } /// /// 删除租户 /// private async void Delete() { var result = await dialog.Question(Local.Localize("TenantDeleteWarningMessage", SelectedItem.TenancyName)); if (result) { await SetBusyAsync(async () => { await appService.DeleteTenant(new EntityDto(SelectedItem.Id)) .WebAsync(async () => await OnNavigatedToAsync()); }); } } #endregion /// /// 刷新租户模块 /// /// public override async Task OnNavigatedToAsync(NavigationContext navigationContext = null) { await SetBusyAsync(async () => { await GetAllEditions(); await GetTenants(); }); } public override PermissionItem[] CreatePermissionItems() { return new PermissionItem[] { new PermissionItem(AppPermissions.TenantImpersonation, Local.Localize("LoginAsThisTenant"),TenantImpersonation), new PermissionItem(AppPermissions.TenantEdit, Local.Localize("Change"),Edit), new PermissionItem(AppPermissions.TenantChangeFeatures, Local.Localize("Features"),TenantChangeFeatures), new PermissionItem(AppPermissions.TenantDelete, Local.Localize("Delete"),Delete), new PermissionItem(AppPermissions.TenantUnlock, Local.Localize("Unlock"),Unlock) }; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Users/SelectedUserViewModel.cs ================================================ using Abp.Application.Services.Dto; using AppFramework.Common; using AppFramework.Common.Dto; using AppFramework.Shared; using AppFramework.Shared.Services; using CommunityToolkit.Mvvm.Input; using Prism.Commands; using Prism.Services.Dialogs; using System; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels { public partial class SelectedUserViewModel : HostDialogViewModel { private readonly ICommonLookupAppService appService; public IDataPagerService dataPager { get; private set; } private FindUsersInput input; public SelectedUserViewModel(IDataPagerService dataPager, ICommonLookupAppService appService) { this.dataPager = dataPager; this.appService = appService; input = new FindUsersInput() { MaxResultCount = 10, }; this.dataPager.OnPageIndexChangedEventhandler += DataPager_OnPageIndexChangedEventhandler; } [RelayCommand] private void SelectedUser(NameValueDto obj) { Save(Convert.ToInt32(obj.Value)); } private async void DataPager_OnPageIndexChangedEventhandler(object sender, PageIndexChangedEventArgs e) { input.SkipCount = e.SkipCount; input.MaxResultCount = e.PageSize; await GetFindUsers(input); } private async Task GetFindUsers(FindUsersInput input) { await SetBusyAsync(async () => { await appService.FindUsers(input).WebAsync(dataPager.SetList); }); } public override async void OnDialogOpened(IDialogParameters parameters) { await GetFindUsers(input); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Users/UserChangePermissionViewModel.cs ================================================ using AppFramework.Authorization.Users.Dto; using Prism.Services.Dialogs; using System.Threading.Tasks; using AppFramework.Authorization.Users; using AppFramework.Shared; using AppFramework.Admin.Services; namespace AppFramework.Admin.ViewModels { public class UserChangePermissionViewModel : HostDialogViewModel { public UserChangePermissionViewModel(IUserAppService userAppService, IPermissionTreesService treesService) { this.userAppService = userAppService; this.treesService = treesService; } private long Id; private readonly IUserAppService userAppService; public IPermissionTreesService treesService { get; set; } public override async Task Save() { await SetBusyAsync(async () => { await userAppService.UpdateUserPermissions(new UpdateUserPermissionsInput() { Id = Id, GrantedPermissionNames = treesService.GetSelectedItems() }).WebAsync(base.Save); }); } public override async void OnDialogOpened(IDialogParameters parameters) { await SetBusyAsync(async () => { if (parameters.ContainsKey("Value")) { var output = parameters.GetValue("Value"); treesService.CreatePermissionTrees(output.Permissions, output.GrantedPermissionNames); } if (parameters.ContainsKey("Id")) Id = parameters.GetValue("Id"); await Task.CompletedTask; }); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Users/UserDetailsViewModel.cs ================================================ using Abp.Application.Services.Dto; using AppFramework.Authorization.Users; using AppFramework.Authorization.Users.Dto; using AppFramework.Authorization.Users.Profile.Dto; using AppFramework.Shared; using AppFramework.Admin.Models; using Prism.Services.Dialogs; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels { public class UserDetailsViewModel : HostDialogViewModel { public UserDetailsViewModel(IUserAppService userAppService, IPermissionService permissionService) { Input = new UserCreateOrUpdateModel(); this.userAppService = userAppService; this.permissionService = permissionService; } #region 字段/属性 private bool isNewUser; private UserForEditModel model; private UserCreateOrUpdateModel input; public UserCreateOrUpdateModel Input { get { return input; } set { input = value; OnPropertyChanged(); } } private GetPasswordComplexitySettingOutput PasswordComplexitySetting; private readonly IUserAppService userAppService; private readonly IPermissionService permissionService; /// /// 是否是新建用户 /// public bool IsNewUser { get => isNewUser; set { isNewUser = value; OnPropertyChanged(); } } public UserForEditModel Model { get => model; set { model = value; OnPropertyChanged(); } } #endregion /// /// 保存用户 /// public override async Task Save() { Input.User = Model.User; Input.AssignedRoleNames = Model.Roles.Where(x => x.IsAssigned).Select(x => x.RoleName).ToArray(); Input.OrganizationUnits = Model.OrganizationUnits.Where(x => x.IsAssigned).Select(x => x.Id).ToList(); if (!Verify(Input).IsValid) return; await SetBusyAsync(async () => { var input = Map(Input); await userAppService.CreateOrUpdateUser(input).WebAsync(base.Save); }, AppLocalizationKeys.SavingWithThreeDot); } /// /// 窗口打开时 /// /// public override async void OnDialogOpened(IDialogParameters parameters) { await SetBusyAsync(async () => { UserListDto? user = null; if (parameters.ContainsKey("Value")) user = parameters.GetValue("Value"); IsNewUser = user == null; Input.SetRandomPassword = IsNewUser; Input.SendActivationEmail = IsNewUser; await userAppService.GetUserForEdit(new NullableIdDto(user?.Id)).WebAsync(GetUserForEditSuccessed); }); if (parameters.ContainsKey("Config")) PasswordComplexitySetting = parameters.GetValue("Config"); } /// /// 设置编辑用户数据 /// /// /// private async Task GetUserForEditSuccessed(GetUserForEditOutput output) { Model = Map(output); Model.OrganizationUnits = Map>(output.AllOrganizationUnits); if (IsNewUser) { //Model.Photo = ImageSource.FromResource(AssetsHelper.ProfileImagePlaceholderNamespace); Model.User = new UserEditModel { IsActive = true, IsLockoutEnabled = true, ShouldChangePasswordOnNextLogin = true, }; } await Task.CompletedTask; } /// /// 生成可选的组织树 /// /// /// /// private ObservableCollection BuildOrganizationTree( List organizationUnits, long? parentId = null) { var masters = organizationUnits .Where(x => x.ParentId == parentId).ToList(); var childs = organizationUnits .Where(x => x.ParentId != parentId).ToList(); foreach (OrganizationListModel dpt in masters) dpt.Items = BuildOrganizationTree(childs, dpt.Id); return new ObservableCollection(masters); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Users/UserViewModel.cs ================================================ using AppFramework.Authorization.Users; using AppFramework.Authorization.Users.Dto; using AppFramework.Authorization.Users.Profile; using AppFramework.Shared; using AppFramework.Admin.Models; using System.Collections.Generic; using System.Threading.Tasks; using AppFramework.Shared.Services.Permission; using Abp.Application.Services.Dto; using Prism.Services.Dialogs; using AppFramework.Authorization.Permissions.Dto; using AppFramework.Authorization.Permissions; using AppFramework.Authorization.Roles; using AppFramework.Authorization.Roles.Dto; using System.Collections.ObjectModel; using Prism.Regions; using AppFramework.Shared.Services; using AppFramework.Admin.Services; using CommunityToolkit.Mvvm.Input; namespace AppFramework.Admin.ViewModels { public partial class UserViewModel : NavigationCurdViewModel { private readonly IUserAppService appService; private readonly IRoleAppService roleAppService; private readonly IAccountService accountService; private readonly IPermissionAppService permissionAppService; public UserListModel SelectedItem => Map(dataPager.SelectedItem); public UserViewModel(IUserAppService appService, IRoleAppService roleAppService, IAccountService accountService, IPermissionAppService permissionAppService) { Title = Local.Localize("UserManagement"); IsAdvancedFilter = false; input = new GetUsersInput { Filter = "", MaxResultCount = AppConsts.DefaultPageSize, SkipCount = 0 }; roleList = new ObservableCollection(); this.appService = appService; this.roleAppService = roleAppService; this.accountService = accountService; this.permissionAppService = permissionAppService; UpdateTitle(); dataPager.OnPageIndexChangedEventhandler += UsersOnPageIndexChangedEventhandler; } private async void UsersOnPageIndexChangedEventhandler(object sender, PageIndexChangedEventArgs e) { input.SkipCount = e.SkipCount; input.MaxResultCount = e.PageSize; await SetBusyAsync(async () => { await GetUsers(input); }); } #region 修改权限/解锁/使用当前账户登录 private async void UserChangePermission() { if (dataPager.SelectedItem is IEntityDto item) { GetUserPermissionsForEditOutput? output = null; await SetBusyAsync(async () => { await appService.GetUserPermissionsForEdit(new EntityDto(item.Id)).WebAsync(async result => { output = result; await Task.CompletedTask; }); }); if (output == null) return; DialogParameters param = new DialogParameters(); param.Add("Id", item.Id); param.Add("Value", output); await dialog.ShowDialogAsync(AppViews.UserChangePermission, param); } } private async void UsersUnlock() { await SetBusyAsync(async () => { await appService.UnlockUser(new EntityDto(SelectedItem.Id)).WebAsync(); }); } private async void LoginAsThisUser() { await accountService.LoginCurrentUserAsync(SelectedItem); } public async void Delete() { if (await dialog.Question(Local.Localize("UserDeleteWarningMessage", SelectedItem.UserName))) { await SetBusyAsync(async () => { await appService.DeleteUser(new EntityDto(SelectedItem.Id)) .WebAsync(async () => await OnNavigatedToAsync()); }); } } #endregion #region 条件高级筛选 #region 字段/属性 public GetUsersInput input { get; set; } /// /// 仅锁定用户 /// public bool IsLockUser { get { return isLockUser; } set { isLockUser = value; //更改查询条件 input.OnlyLockedUsers = value; OnPropertyChanged(); } } private bool isLockUser; private bool isAdvancedFilter; private string filterTitle = string.Empty; private string selectPermissions = string.Empty; private RoleListModel selectedRole; private ObservableCollection roleList; private ListResultDto flatPermission; public string FilterText { get { return input.Filter; } set { input.Filter = value; OnPropertyChanged(); Search(); } } /// /// 筛选标题文本: 收缩/展开 /// public string FilerTitle { get { return filterTitle; } set { filterTitle = value; OnPropertyChanged(); } } /// /// 高级筛选 /// public bool IsAdvancedFilter { get { return isAdvancedFilter; } set { isAdvancedFilter = value; FilerTitle = value ? "△ " + Local.Localize("HideAdvancedFilters") : "▽ " + Local.Localize("ShowAdvancedFilters"); OnPropertyChanged(); } } /// /// 已选择权限的文本 /// public string SelectPermissions { get { return selectPermissions; } set { selectPermissions = value; OnPropertyChanged(); } } /// /// 选中角色 /// public RoleListModel SelectedRole { get { return selectedRole; } set { selectedRole = value; //设置角色筛选条件 if (value != null) input.Role = value.Id; else input.Role = null; OnPropertyChanged(); } } /// /// 绑定角色列表 /// public ObservableCollection RoleList { get { return roleList; } set { roleList = value; OnPropertyChanged(); } } #endregion [RelayCommand] private void Advanced() => IsAdvancedFilter = !IsAdvancedFilter; /// /// 重置筛选条件 /// [RelayCommand] private void Reset() { SelectedRole = null; FilterText = string.Empty; input.Permissions?.Clear(); UpdateTitle(0); } /// /// 更新选中的权限筛选文本 /// /// private void UpdateTitle(int count = 0) { SelectPermissions = Local.Localize("SelectPermissions") + $"({count})"; } /// /// 选择权限 /// [RelayCommand] private async void Selected() { DialogParameters param = new DialogParameters(); param.Add("Value", flatPermission); var dialogResult = await dialog.ShowDialogAsync(AppViews.SelectedPermission, param); if (dialogResult.Result == Prism.Services.Dialogs.ButtonResult.OK) { var selectedPermissions = dialogResult.Parameters.GetValue>("Value"); input.Permissions = selectedPermissions; UpdateTitle(selectedPermissions.Count); await OnNavigatedToAsync(); } } /// /// 获取筛选权限列表 /// /// private async Task GetAllPermission() { if (flatPermission != null) return; await permissionAppService.GetAllPermissions().WebAsync(async result => { flatPermission = result; await Task.CompletedTask; }); } /// /// 获取可选角色列表 /// /// private async Task GetAllRoles() { if (RoleList.Count > 0) return; await roleAppService.GetRoles(new GetRolesInput()).WebAsync(async result => { foreach (var item in Map>(result.Items)) RoleList.Add(item); await Task.CompletedTask; }); } #endregion /// /// 搜索用户 /// [RelayCommand] public void Search() { dataPager.PageIndex = 0; } /// /// 查询用户列表 /// /// /// private async Task GetUsers(GetUsersInput filter) { await appService.GetUsers(filter).WebAsync(dataPager.SetList); } /// /// 刷新用户列表模块 /// /// public override async Task OnNavigatedToAsync(NavigationContext navigationContext = null) { await SetBusyAsync(async () => { await GetAllRoles(); await GetAllPermission(); await GetUsers(input); }); } public override PermissionItem[] CreatePermissionItems() { return new PermissionItem[] { new PermissionItem(AppPermissions.Users, Local.Localize("LoginAsThisUser"),LoginAsThisUser), new PermissionItem(AppPermissions.UserEdit, Local.Localize("Change"),Edit), new PermissionItem(AppPermissions.UserChangePermission, Local.Localize("Permissions"),UserChangePermission), new PermissionItem(AppPermissions.UsersUnlock, Local.Localize("Unlock"),UsersUnlock), new PermissionItem(AppPermissions.UserDelete, Local.Localize("Delete"),Delete) }; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Version/VersionManagerDetailsViewModel.cs ================================================ using AppFramework.Authorization.Users.Profile; using AppFramework.Shared; using AppFramework.Admin.Models; using AppFramework.Version.Dtos; using Microsoft.Win32; using Prism.Commands; using Prism.Services.Dialogs; using System.IO; using System.Threading.Tasks; namespace AppFramework.Admin.ViewModels.Version { public class VersionManagerDetailsViewModel : HostDialogViewModel { public VersionManagerDetailsViewModel(ProxyProfileControllerService profileControllerService) { this.profileControllerService = profileControllerService; SelectedFileCommand = new DelegateCommand(SelectedFile); } private VersionListModel model; public VersionListModel Model { get { return model; } set { model = value; OnPropertyChanged(); } } private string filePath; private readonly ProxyProfileControllerService profileControllerService; public string FilePath { get { return filePath; } set { filePath = value; OnPropertyChanged(); } } public DelegateCommand SelectedFileCommand { get; private set; } private void SelectedFile() { OpenFileDialog fileDialog = new OpenFileDialog(); fileDialog.Filter = "压缩文件(*.zip)|*.zip"; var dialogResult = fileDialog.ShowDialog(); if (dialogResult != null && (bool)dialogResult) FilePath = fileDialog.FileName; } public override async Task Save() { if (Model.Id == 0 && string.IsNullOrWhiteSpace(FilePath)) return; if (!Verify(Model).IsValid) return; await SetBusyAsync(async () => { MemoryStream? stream = null; if (!string.IsNullOrWhiteSpace(FilePath)) { var fileBytes = File.ReadAllBytes(FilePath); stream = new MemoryStream(fileBytes); } await profileControllerService.UploadVersionFile(content => { if (stream != null) content.AddFile("file", stream, "file.zip"); if (Model.Id > 0) content.AddString(nameof(CreateOrEditAbpVersionDto.Id), Model.Id.ToString()); content.AddString(nameof(CreateOrEditAbpVersionDto.Name), Model.Name); content.AddString(nameof(CreateOrEditAbpVersionDto.Version), Model.Version); content.AddString(nameof(CreateOrEditAbpVersionDto.IsForced), Model.IsForced.ToString()); content.AddString(nameof(CreateOrEditAbpVersionDto.IsEnable), Model.IsEnable.ToString()); content.AddString(nameof(CreateOrEditAbpVersionDto.MinimumVersion), Model.MinimumVersion.ToString()); }).WebAsync(async () => { stream?.Dispose(); stream?.Close(); await base.Save(); }); }); } public override async void OnDialogOpened(IDialogParameters parameters) { await SetBusyAsync(async () => { if (parameters.ContainsKey("Value")) { var tenant = parameters.GetValue("Value"); Model = Map(tenant); } else Model = new VersionListModel(); await Task.CompletedTask; }); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Version/VersionManagerViewModel.cs ================================================ using Abp.Application.Services.Dto; using AppFramework.Shared; using AppFramework.Admin.Models; using AppFramework.Shared.Services.Permission; using AppFramework.Version; using AppFramework.Version.Dtos; using Prism.Regions; using System.Threading.Tasks; using AppFramework.Shared.Services; namespace AppFramework.Admin.ViewModels { public class VersionManagerViewModel : NavigationCurdViewModel { private readonly IAbpVersionsAppService appService; public GetAllAbpVersionsInput input; public VersionListModel SelectedItem => Map(dataPager.SelectedItem); public VersionManagerViewModel(IAbpVersionsAppService appService) { Title = Local.Localize("VersionManager"); this.appService = appService; input = new GetAllAbpVersionsInput() { MaxResultCount = 10 }; dataPager.OnPageIndexChangedEventhandler += DataPager_OnPageIndexChangedEventhandler; } private void DataPager_OnPageIndexChangedEventhandler(object sender, PageIndexChangedEventArgs e) { } public override async Task OnNavigatedToAsync(NavigationContext navigationContext = null) { await SetBusyAsync(async () => { await GetVersions(input); }); } public override PermissionItem[] CreatePermissionItems() { return new PermissionItem[] { new PermissionItem(AppPermissions.VersionsEdit,Local.Localize("Change"),Edit), new PermissionItem(AppPermissions.VersionsDelete, Local.Localize("Delete"),Delete), }; } private async Task GetVersions(GetAllAbpVersionsInput filter) { await appService.GetAll(filter).WebAsync(dataPager.SetList); } private async void Delete() { var result = await dialog.Question(Local.Localize("VersionDeleteWarningMessage", SelectedItem.Name)); if (result) { await SetBusyAsync(async () => { await appService.Delete(new EntityDto(SelectedItem.Id)).WebAsync(async () => await OnNavigatedToAsync()); }); } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin/ViewModels/Visual/VisualViewModel.cs ================================================ using AppFramework.Shared; using AppFramework.Shared.Services; using CommunityToolkit.Mvvm.Input; using DryIoc; using Prism.Commands; namespace AppFramework.Admin.ViewModels.Shared { public partial class VisualViewModel : NavigationViewModel { public VisualViewModel(IThemeService themeService) { Title = Local.Localize("VisualSettings"); this.themeService = themeService; } public IThemeService themeService { get; set; } [RelayCommand] private void SetTheme(ThemeItem themeItem) { themeService.SetTheme(themeItem.DisplayName); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/App.xaml ================================================  ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/App.xaml.cs ================================================ using AppFramework.Admin.HandyUI.Themes.Controls; using AppFramework.Admin.Services; using AppFramework.Shared; using AppFramework.Shared.Services; using AppFramework.Shared.Services.App; using AppFramework.Shared.Services.Mapper; using Hardcodet.Wpf.TaskbarNotification; using Prism.DryIoc; using Prism.Ioc; using Prism.Regions; using System.Windows; namespace AppFramework.Admin.HandyUI { public partial class App : PrismApplication, IAppTaskBar { private TaskbarIcon? taskBar; protected override Window? CreateShell() => null; protected override async void OnInitialized() { Initialization(); var appVersionService = ContainerLocator.Container.Resolve(); await appVersionService.CheckVersion(); var appStart = ContainerLocator.Container.Resolve(); appStart.CreateShell(); base.OnInitialized(); } protected override void RegisterTypes(IContainerRegistry container) { container.AddViews(); container.AddAdminsServices(); container.AddSharedServices(); container.RegisterSingleton(); container.RegisterSingleton(); container.RegisterScoped(); container.RegisterScoped(); container.RegisterSingleton(); //container.RegisterSingleton(); } protected override void ConfigureRegionAdapterMappings(RegionAdapterMappings regionAdapterMappings) { regionAdapterMappings.RegisterMapping(); base.ConfigureRegionAdapterMappings(regionAdapterMappings); } public void ShowBalloonTip(string title, string message, BalloonIcon balloonIcon) { taskBar.ShowBalloonTip(title, message, balloonIcon); } public void Initialization() { taskBar = (TaskbarIcon)FindResource("taskBar"); } public void Dispose() => taskBar?.Dispose(); } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/AppFramework.Admin.HandyUI.csproj ================================================  WinExe net6.0-windows enable true Code Code Code Code Code Code Code Code Code Code Code Code Code Code Always $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) $(DefaultXamlRuntime) ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Converters/MenuTitleConverter.cs ================================================ using AppFramework.Admin.HandyUI.Themes.Controls; using AppFramework.Shared; using System; using System.Globalization; using System.Windows.Controls; using System.Windows.Data; namespace AppFramework.Admin.HandyUI.Converters { public class MenuTitleConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value != null && value is TabCloseItem tabItem) { var ctor = tabItem.Content as UserControl; if (ctor != null && ctor.DataContext is NavigationViewModel viewModel) { tabItem.Header = viewModel.Title; } return tabItem.Header; } return string.Empty; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Extensions/ContainerExtensions.cs ================================================ using AppFramework.Admin.HandyUI.Views; using AppFramework.Admin.ViewModels; using AppFramework.Admin.ViewModels.Chat; using AppFramework.Admin.ViewModels.Shared; using AppFramework.Admin.ViewModels.Version; using AppFramework.Shared; using Prism.Ioc; namespace AppFramework.Admin.HandyUI { internal static class ContainerExtensions { public static void AddViews(this IContainerRegistry services) { services.RegisterDialog(AppViews.SplashScreen); services.RegisterDialog(AppViews.Login); services.Add(AppViews.SelectedUser); services.Add(AppViews.Friends); services.Add(AppViews.FriendsChat); services.Add(AppViews.UserPanel); services.Add(AppViews.FirstChangedPwd); services.Add(AppViews.SelectTenant); services.Add(AppViews.Main); services.Add(AppViews.HostMessageBox); services.Add(AppViews.MessageBox); services.Add(AppViews.User); services.Add(AppViews.UserDetails); services.Add(AppViews.UserChangePermission); services.Add(AppViews.Role); services.Add(AppViews.RoleDetails); services.Add(AppViews.SelectedPermission); services.Add(AppViews.Edition); services.Add(AppViews.EditionDetails); services.Add(AppViews.DynamicProperty); services.Add(AppViews.DynamicPropertyDetails); services.Add(AppViews.DynamicAddEntity); services.Add(AppViews.DynamicEntityDetails); services.Add(AppViews.DynamicEditValues); services.Add(AppViews.Tenant); services.Add(AppViews.TenantDetails); services.Add(AppViews.TenantChangeFeatures); services.Add(AppViews.AddRoles); services.Add(AppViews.AddUsers); services.Add(AppViews.AuditLog); services.Add(AppViews.AuditLogDetails); services.Add(AppViews.Language); services.Add(AppViews.LanguageText); services.Add(AppViews.LanguageTextDetails); services.Add(AppViews.LanguageDetails); services.Add(AppViews.Dashboard); services.Add(AppViews.Organization); services.Add(AppViews.OrganizationAdd); services.Add(AppViews.Setting); services.Add(AppViews.Demo); //演示组件页 services.Add(AppViews.Visual); services.Add(AppViews.Version); services.Add(AppViews.VersionDetails); services.Add(AppViews.Notification); services.Add(AppViews.MyProfile); services.Add(AppViews.LoginAttempts); services.Add(AppViews.ManageLinkedAccounts); services.Add(AppViews.ManageUserDelegations); services.Add(AppViews.SelectDate); services.Add(AppViews.ManageNewUser); services.Add(AppViews.CreateLinkedAccount); services.Add(AppViews.MySetting); services.Add(AppViews.ChangeAvatar); services.Add(AppViews.ChangePassword); services.Add(AppViews.EmailActivation); services.Add(AppViews.ForgotPassword); services.Add(AppViews.SendTwoFactorCode); } static void Add(this IContainerRegistry containerRegistry, string name = null) { containerRegistry.RegisterForNavigation(name); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Extensions/TabControlRegionAdapter.cs ================================================ using AppFramework.Admin.HandyUI.Themes.Controls; using Prism.Regions; using System; namespace AppFramework.Admin.HandyUI { internal class TabControlRegionAdapter : RegionAdapterBase { public TabControlRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory) : base(regionBehaviorFactory) { } protected override void Adapt(IRegion region, TabControl regionTarget) { if (region == null) throw new ArgumentNullException(nameof(region)); if (regionTarget == null) throw new ArgumentNullException(nameof(regionTarget)); regionTarget.ItemsSource = region.Views; } protected override IRegion CreateRegion() { return new SingleActiveRegion(); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/HandyUIStartService.cs ================================================ using AppFramework.Configuration; using AppFramework.Shared; using AppFramework.Shared.Services.App; using Prism.Regions; using System; using System.Threading.Tasks; using Prism.Ioc; using AppFramework.Admin.Services; using AppFramework.Shared.Services; using Prism.Services.Dialogs; using System.Windows; namespace AppFramework.Admin.HandyUI { internal class HandyUIStartService : IAppStartService { public void CreateShell() { var container = ContainerLocator.Container; var userConfigurationService = container.Resolve(); userConfigurationService.OnAccessTokenRefresh = OnAccessTokenRefresh; userConfigurationService.OnSessionTimeOut = OnSessionTimeout; this.SplashScreenInitialized(); var shell = container.Resolve(AppViews.Main); if (shell is Window view) { var regionManager = container.Resolve(); RegionManager.SetRegionManager(view, regionManager); RegionManager.UpdateRegions(); if (view.DataContext is INavigationAware navigationAware) { navigationAware.OnNavigatedTo(null); App.Current.MainWindow = view; } } } private void SplashScreenInitialized() { var dialogService = ContainerLocator.Container.Resolve(); var result = dialogService.ShowWindow(AppViews.SplashScreen).Result; if (result == ButtonResult.Ignore) { if (!Authorization()) Exit(); } else if (result == ButtonResult.No) Exit(); } private bool Authorization() { var validationResult = Validation(); if (validationResult == ButtonResult.Retry) return Authorization(); return validationResult == ButtonResult.OK; static ButtonResult Validation() { var dialogService = ContainerLocator.Container.Resolve(); return dialogService.ShowWindow(AppViews.Login).Result; } } public static async Task OnSessionTimeout() { await ContainerLocator.Container.Resolve().LogoutAsync(); } public static async Task OnAccessTokenRefresh(string newAccessToken) { await ContainerLocator.Container.Resolve().StoreAccessTokenAsync(newAccessToken); } public void Exit() { if (System.Windows.Application.Current is IAppTaskBar appTaskBar) appTaskBar.Dispose(); Environment.Exit(0); } public void Logout() { App.Current.MainWindow.Hide(); SplashScreenInitialized(); App.Current.MainWindow.Show(); if (App.Current.MainWindow.DataContext is INavigationAware navigationAware) navigationAware.OnNavigatedTo(null); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Localization/LocalTranslationHelper.cs ================================================ using AppFramework.Shared; using Prism.Ioc; using System; using System.Reflection; using System.Resources; namespace AppFramework.Admin.HandyUI { public static class LocalTranslationHelper { private static readonly Lazy locale = new Lazy( ContainerLocator.Container.Resolve); private const string ResourceId = "AppFramework.Admin.HandyUI.Localization.Resources.LocalTranslation"; public static string Localize(string key) { return GetValue(key) ?? key; } private static string GetValue(string key) { var cultureInfo = locale.Value.GetCurrentCultureInfo(); var resourceManager = new ResourceManager(ResourceId, typeof(LocalTranslationHelper).GetTypeInfo().Assembly); return resourceManager.GetString(key, cultureInfo); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Localization/LocaleCulture.cs ================================================ using AppFramework.Localization.Resources; using System.Reflection; using System.Resources; using System.Globalization; using System.Threading; using AppFramework.Shared; namespace AppFramework.Admin.HandyUI { public class LocaleCulture : ILocaleCulture { private const string ResourceId = "AppFramework.Admin.HandyUI.Localization.Resources.LocalTranslation"; public CultureInfo GetCurrentCultureInfo() { return Thread.CurrentThread.CurrentUICulture; } public string GetString(string key) { var resourceManager = new ResourceManager(ResourceId, typeof(LocaleCulture).GetTypeInfo().Assembly); return resourceManager.GetString(key, GetCurrentCultureInfo()); } public void SetLocale(CultureInfo ci) { Thread.CurrentThread.CurrentCulture = ci; Thread.CurrentThread.CurrentUICulture = ci; LocalTranslation.Culture = ci; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Localization/Resources/LocalTranslation.Designer.cs ================================================ //------------------------------------------------------------------------------ // // 此代码由工具生成。 // 运行时版本:4.0.30319.42000 // // 对此文件的更改可能会导致不正确的行为,并且如果 // 重新生成代码,这些更改将会丢失。 // //------------------------------------------------------------------------------ namespace AppFramework.Localization.Resources { using System; /// /// 一个强类型的资源类,用于查找本地化的字符串等。 /// // 此类是由 StronglyTypedResourceBuilder // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen // (以 /str 作为命令选项),或重新生成 VS 项目。 [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class LocalTranslation { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal LocalTranslation() { } /// /// 返回此类使用的缓存的 ResourceManager 实例。 /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] public static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CodeShare.Shared.Localization.Resources.LocalTranslation", typeof(LocalTranslation).Assembly); resourceMan = temp; } return resourceMan; } } /// /// 重写当前线程的 CurrentUICulture 属性,对 /// 使用此强类型资源类的所有资源查找执行重写。 /// [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] public static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } /// /// 查找类似 Authenticating... 的本地化字符串。 /// public static string Authenticating { get { return ResourceManager.GetString("Authenticating", resourceCulture); } } /// /// 查找类似 Cancel 的本地化字符串。 /// public static string Cancel { get { return ResourceManager.GetString("Cancel", resourceCulture); } } /// /// 查找类似 A problem occurred while trying to communicate with the server. Do you want to try again? 的本地化字符串。 /// public static string HttpException { get { return ResourceManager.GetString("HttpException", resourceCulture); } } /// /// 查找类似 Initializing... 的本地化字符串。 /// public static string Initializing { get { return ResourceManager.GetString("Initializing", resourceCulture); } } /// /// 查找类似 CodeShare 的本地化字符串。 /// public static string MessageTitle { get { return ResourceManager.GetString("MessageTitle", resourceCulture); } } /// /// 查找类似 No internet connection! Do you want to enable internet and try again? 的本地化字符串。 /// public static string NoInternet { get { return ResourceManager.GetString("NoInternet", resourceCulture); } } /// /// 查找类似 Ok 的本地化字符串。 /// public static string Ok { get { return ResourceManager.GetString("Ok", resourceCulture); } } /// /// 查找类似 Request is timed out. Do you want to try again? 的本地化字符串。 /// public static string RequestTimedOut { get { return ResourceManager.GetString("RequestTimedOut", resourceCulture); } } /// /// 查找类似 An error occurred. Do you want to try again? 的本地化字符串。 /// public static string UnhandledWebRequestException { get { return ResourceManager.GetString("UnhandledWebRequestException", resourceCulture); } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Localization/Resources/LocalTranslation.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Authenticating... Cancel There was a problem trying to communicate with the server. Do you want to try again? initializing... LoadResource... AppFramework No internet connection! Do you want to enable internet and try again? Ok Request timed out. Do you want to try again? The server is not connected, do you want to resend? An error occurred. Do you want to try again? Yes ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Localization/Resources/LocalTranslation.zh-Hans.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 正在认证... 取消 尝试与服务器通信时出现问题。 你想再试一次吗? 正在初始化... 加载系统资源... AppFramework 取消 没有网络连接! 您要启用互联网并重试吗? 确定 请求超时。 你想再试一次吗? 服务器无法连接,是否重新发送? 发生错误。 你想再试一次吗? 确定 ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Services/Features/FeaturesService.cs ================================================ using Abp.Application.Services.Dto; using AppFramework.Editions.Dto; using AppFramework.Admin.Models; using AppFramework.Shared.Services.Mapper; using AutoMapper; using Prism.Mvvm; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using AppFramework.Admin.Services; namespace AppFramework.Admin.HandyUI.Services { public class FeaturesService : BindableBase, IFeaturesService { private readonly IAppMapper mapper; public FeaturesService(IAppMapper mapper) { this.mapper = mapper; } private ObservableCollection features; public ObservableCollection Features { get { return features; } set { features = value; RaisePropertyChanged(); } } public ObservableCollection SelectedItems { get; set; } public void CreateFeatures(List features, List featureValues) { if (features == null) throw new NullReferenceException(nameof(features)); if (featureValues == null) throw new NullReferenceException(nameof(featureValues)); var flats = mapper.Map>(features); Features = CreateFeatureTrees(flats); UpdateFeaturesIsCheckedState(Features, featureValues); } public List GetSelectedItems() { List items = new List(); GetFeatures(Features, ref items); return items; } /// /// 获取选中的功能节点 /// /// /// private void GetFeatures(ObservableCollection flatFeatures, ref List featureValues) { foreach (var item in flatFeatures) { if (bool.TryParse(item.DefaultValue, out bool result)) { featureValues.Add(new NameValueDto(item.Name, item.IsChecked ? "true" : "false")); } else featureValues.Add(new NameValueDto(item.Name, item.DefaultValue)); GetFeatures(item.Items, ref featureValues); } } /// /// 创建功能结点目录树 /// /// /// /// private ObservableCollection CreateFeatureTrees(List flatFeatureModels, string? parentName = null) { var trees = new ObservableCollection(); var nodes = flatFeatureModels.Where(q => q.ParentName == parentName).ToArray(); foreach (var node in nodes) { node.Items = CreateFeatureTrees(flatFeatureModels, node.Name); trees.Add(node); } return trees; } private void UpdateFeaturesIsCheckedState(ObservableCollection features, List featureValues) { foreach (var f in featureValues) { UpdateIsCheckedState(features, f); } void UpdateIsCheckedState(ObservableCollection flatFeatures, NameValueDto nameValue) { foreach (var flat in flatFeatures) { if (flat.Name.Equals(nameValue.Name) && flat.Items.Count == 0) { bool isAdd = false; if (bool.TryParse(nameValue.Value, out bool result)) isAdd = result; else isAdd = true; if (isAdd) flat.IsChecked=true; } UpdateIsCheckedState(flat.Items, nameValue); } } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Services/Permission/PermissionTreesService.cs ================================================ using AppFramework.Authorization.Permissions.Dto; using AppFramework.Admin.Models; using AppFramework.Shared.Services.Mapper; using Prism.Mvvm; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using AppFramework.Admin.Services; namespace AppFramework.Admin.HandyUI.Services { public class PermissionTreesService : BindableBase, IPermissionTreesService { private readonly IAppMapper mapper; public PermissionTreesService(IAppMapper mapper) { this.mapper = mapper; } private ObservableCollection permissions; public ObservableCollection Permissions { get { return permissions; } set { permissions = value; RaisePropertyChanged(); } } private ObservableCollection selectedItems; public ObservableCollection SelectedItems { get { return selectedItems; } set { selectedItems = value; RaisePropertyChanged(); } } public void CreatePermissionTrees(List permissions, List grantedPermissionNames) { if (permissions == null) throw new NullReferenceException(nameof(permissions)); if (grantedPermissionNames == null) throw new NullReferenceException(nameof(grantedPermissionNames)); var flats = mapper.Map>(permissions); Permissions = flats.CreateTrees(null); UpdatePermissionsIsCheckedState(Permissions, grantedPermissionNames); } public List GetSelectedItems() { List selectedItems = new List(); foreach (var item in Permissions) { if (item.IsChecked) selectedItems.Add(item.Name); if (item.Items!=null&& item.Items.Count>0) GetParentIsCheckedItem(selectedItems, item); } return selectedItems; } private void GetParentIsCheckedItem(List selectedItems, PermissionModel model) { foreach (var item in model.Items) { if (item.IsChecked) selectedItems.Add(item.Name); if (item.Items!=null&& item.Items.Count>0) GetParentIsCheckedItem(selectedItems, item); } } public void UpdatePermissionsIsCheckedState(ObservableCollection nodes, List GrantedPermissionNames) { foreach (var item in GrantedPermissionNames) UpdateIsCheckedState(nodes, item); void UpdateIsCheckedState(ObservableCollection nodes, string key) { foreach (var flat in nodes) { if (flat.Name.Equals(key)) flat.IsChecked=true; UpdateIsCheckedState(flat.Items, key); } } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Services/Sessions/DialogHostService.cs ================================================ using AppFramework.Services; using AppFramework.Shared.Services; using Prism.Common; using Prism.Ioc; using Prism.Mvvm; using Prism.Services.Dialogs; using System; using System.Threading.Tasks; using System.Windows; namespace AppFramework.Admin.HandyUI { /// /// 对话主机服务 /// public class DialogHostService : DialogService, IHostDialogService { private readonly IContainerExtension _containerExtension; public DialogHostService(IContainerExtension containerExtension) : base(containerExtension) { _containerExtension = containerExtension; } public IDialogResult ShowWindow(string name) { IDialogResult dialogResult = new DialogResult(ButtonResult.None); var content = _containerExtension.Resolve(name); if (!(content is Window dialogContent)) throw new NullReferenceException("A dialog's content must be a Window"); if (dialogContent is Window view && view.DataContext is null && ViewModelLocator.GetAutoWireViewModel(view) is null) ViewModelLocator.SetAutoWireViewModel(view, true); if (!(dialogContent.DataContext is IDialogAware viewModel)) throw new NullReferenceException("A dialog's ViewModel must implement the IDialogAware interface"); if (dialogContent is IDialogWindow dialogWindow) { ConfigureDialogWindowEvents(dialogWindow, result => { dialogResult = result; }); } MvvmHelpers.ViewAndViewModelAction(viewModel, d => d.OnDialogOpened(null)); dialogContent.ShowDialog(); return dialogResult; } public async Task ShowDialogAsync(string name, IDialogParameters parameters = null, string IdentifierName = "Root") { var dialogContent = GetDialogContent(name, IdentifierName); if (!(dialogContent.DataContext is IHostDialogAware viewModel)) throw new NullReferenceException("A dialog's ViewModel must implement the IDialogHostAware interface"); var eventHandler = GetDialogOpenedEventHandler(viewModel, parameters); var isDialogOpen = DialogHost.IsDialogOpen(IdentifierName); if (isDialogOpen) return new DialogResult(ButtonResult.Ignore); var dialogResult = await DialogHost.Show(dialogContent, IdentifierName, eventHandler); if (dialogResult == null) return new DialogResult(ButtonResult.Cancel); return (IDialogResult)dialogResult; } private FrameworkElement GetDialogContent(string name, string IdentifierName = "Root") { var content = _containerExtension.Resolve(name); if (!(content is FrameworkElement dialogContent)) throw new NullReferenceException("A dialog's content must be a FrameworkElement"); if (dialogContent is FrameworkElement view && view.DataContext is null && ViewModelLocator.GetAutoWireViewModel(view) is null) ViewModelLocator.SetAutoWireViewModel(view, true); if (!(dialogContent.DataContext is IHostDialogAware viewModel)) throw new NullReferenceException("A dialog's ViewModel must implement the IDialogHostAware interface"); viewModel.IdentifierName = IdentifierName; return dialogContent; } private DialogOpenedEventHandler GetDialogOpenedEventHandler(IHostDialogAware viewModel, IDialogParameters parameters) { if (parameters == null) parameters = new DialogParameters(); DialogOpenedEventHandler eventHandler = (sender, eventArgs) => { var _content = eventArgs.Session.Content; if (viewModel is IHostDialogAware aware) aware.OnDialogOpened(parameters); eventArgs.Session.UpdateContent(_content); }; return eventHandler; } public void Close(string IdentifierName, DialogResult dialogResult) { DialogHost.Close(IdentifierName, dialogResult); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Themes/Button.xaml ================================================  ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Themes/Controls/Card.cs ================================================ using System; using System.Windows; using System.Windows.Controls; using System.Windows.Media; namespace AppFramework.Admin.HandyUI.Themes.Controls { [TemplatePart(Name = ClipBorderPartName, Type = typeof(Border))] public class Card : ContentControl { private Border? _clipBorder; private const double DefaultUniformCornerRadius = 2.0; public const string ClipBorderPartName = "PART_ClipBorder"; #region DependencyProperty : UniformCornerRadiusProperty public double UniformCornerRadius { get => (double)GetValue(UniformCornerRadiusProperty); set => SetValue(UniformCornerRadiusProperty, value); } public static readonly DependencyProperty UniformCornerRadiusProperty = DependencyProperty.Register(nameof(UniformCornerRadius), typeof(double), typeof(Card), new FrameworkPropertyMetadata(DefaultUniformCornerRadius, FrameworkPropertyMetadataOptions.AffectsMeasure)); #endregion DependencyProperty : UniformCornerRadiusProperty #region DependencyProperty : ContentClipProperty private static readonly DependencyPropertyKey ContentClipPropertyKey = DependencyProperty.RegisterReadOnly(nameof(ContentClip), typeof(Geometry), typeof(Card), new PropertyMetadata(default(Geometry))); public Geometry? ContentClip { get => (Geometry?)GetValue(ContentClipProperty); private set => SetValue(ContentClipPropertyKey, value); } public static readonly DependencyProperty ContentClipProperty = ContentClipPropertyKey.DependencyProperty; #endregion DependencyProperty : ContentClipProperty static Card() { DefaultStyleKeyProperty.OverrideMetadata(typeof(Card), new FrameworkPropertyMetadata(typeof(Card))); } public override void OnApplyTemplate() { base.OnApplyTemplate(); _clipBorder = Template.FindName(ClipBorderPartName, this) as Border; } protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo) { base.OnRenderSizeChanged(sizeInfo); if (_clipBorder is null) { return; } var farPointX = Math.Max(0, _clipBorder.ActualWidth); var farPointY = Math.Max(0, _clipBorder.ActualHeight); var farPoint = new Point(farPointX, farPointY); var clipRect = new Rect(new Point(0, 0), farPoint); ContentClip = new RectangleGeometry(clipRect, UniformCornerRadius, UniformCornerRadius); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Themes/Controls/DataPager.cs ================================================ using Prism.Commands; using Prism.Mvvm; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Windows; using System.Windows.Controls; namespace AppFramework.Admin.HandyUI.Themes.Controls { internal class DataPager : Control, INotifyPropertyChanged { public DataPager() { ButtonCollections = new ObservableCollection(); } private ListBox _listBoxButtonList; private ComboBox comboBoxPageSize; private int SelectedIndex; /// /// 显示按钮数量 /// public int NumericButtonCount { get { return (int)GetValue(NumericButtonCountProperty); } set { SetValue(NumericButtonCountProperty, value); } } /// /// 总页数 /// public int PageCount { get { return (int)GetValue(PageCountProperty); } set { SetValue(PageCountProperty, value); } } /// /// 每页大小 /// public int PageSize { get { return (int)GetValue(PageSizeProperty); } set { SetValue(PageSizeProperty, value); } } /// /// 当前页索引 /// public int PageIndex { get { return (int)GetValue(PageIndexProperty); } set { SetValue(PageIndexProperty, value); } } internal ObservableCollection ButtonCollections { get; set; } public static readonly DependencyProperty NumericButtonCountProperty = DependencyProperty.Register("NumericButtonCount", typeof(int), typeof(DataPager), new PropertyMetadata(NumericButtonCountChangedCallback)); public static readonly DependencyProperty PageCountProperty = DependencyProperty.Register("PageCount", typeof(int), typeof(DataPager), new PropertyMetadata(PageCountChangedCallback)); public static readonly DependencyProperty PageSizeProperty = DependencyProperty.Register("PageSize", typeof(int), typeof(DataPager), new PropertyMetadata(PageSizeChangedCallback)); public static readonly DependencyProperty PageIndexProperty = DependencyProperty.Register("PageIndex", typeof(int), typeof(DataPager), new PropertyMetadata(PageIndexChangedCallback)); public event PropertyChangedEventHandler? PropertyChanged; public override void OnApplyTemplate() { var listBox = GetTemplateChild("ItemsControl") as ListBox; if (listBox != null) { _listBoxButtonList=listBox; _listBoxButtonList.ItemsSource = ButtonCollections; } if (GetTemplateChild("COMBOX_PAGESIZE") is ComboBox comboBoxPageSize) { this.comboBoxPageSize = comboBoxPageSize; this.comboBoxPageSize.SelectedIndex = SelectedIndex; this.comboBoxPageSize.SelectionChanged += ComboBoxPageSize_SelectionChanged; } GetTemplateButtonByName("HomePage").Click += HomePage_Click; GetTemplateButtonByName("PreviousPage").Click += PreviousPage_Click; GetTemplateButtonByName("NextPage").Click += NextPage_Click; GetTemplateButtonByName("EndPage").Click += EndPage; base.OnApplyTemplate(); } void ButtonIndexClick(ButtonCommandModel arg) { PageIndex = arg.Index-1; //设置当前页索引 } /// /// 首页 /// /// /// void HomePage_Click(object sender, RoutedEventArgs e) { PageIndex=0; } /// /// 上一页 /// /// /// void PreviousPage_Click(object sender, RoutedEventArgs e) { if (PageIndex > 0) PageIndex-=1; } /// /// 下一页 /// /// /// void NextPage_Click(object sender, RoutedEventArgs e) { if (PageIndex+1==PageCount) return; if (PageIndex < PageCount) PageIndex+=1; } /// /// 尾页 /// /// /// void EndPage(object sender, RoutedEventArgs e) { if (PageIndex != PageCount) PageIndex = PageCount-1; //设置尾页 } private Button GetTemplateButtonByName(string Name) { return GetTemplateChild(Name) as Button; } private static void NumericButtonCountChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) { var dataPager = (DataPager)d; dataPager.ButtonCollections.Clear(); if (dataPager.PageCount == 0) { dataPager.ButtonCollections.Add(new ButtonCommandModel { Index=1, ClickCommand=new DelegateCommand(dataPager.ButtonIndexClick) }); return; } if (int.TryParse(e.NewValue.ToString(), out int buttonCount)) { for (int i = 1; i < buttonCount + 1; i++) { dataPager.ButtonCollections.Add(new ButtonCommandModel { Index=i, ClickCommand=new DelegateCommand(dataPager.ButtonIndexClick) }); } } } private static void PageSizeChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) { var dataPager = (DataPager)d; if (int.TryParse(e.NewValue.ToString(), out int result)) { switch (result) { case 10: dataPager.SelectedIndex = 0; break; case 20: dataPager.SelectedIndex = 1; break; case 50: dataPager.SelectedIndex = 2; break; case 100: dataPager.SelectedIndex = 3; break; default: dataPager.SelectedIndex = 1; break; } } } private static void PageCountChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) { var dataPager = (DataPager)d; dataPager.ButtonCollections.Clear(); if (dataPager.PageCount == 0) { dataPager.ButtonCollections.Add(new ButtonCommandModel { Index=1, ClickCommand=new DelegateCommand(dataPager.ButtonIndexClick) }); return; } if (int.TryParse(e.NewValue.ToString(), out int pageCount)) { int Count = 0; if (dataPager.NumericButtonCount > pageCount) Count = pageCount; else Count = dataPager.NumericButtonCount; for (int i = 1; i < Count + 1; i++) { dataPager.ButtonCollections.Add(new ButtonCommandModel { Index=i, ClickCommand=new DelegateCommand(dataPager.ButtonIndexClick) }); } } } private static void PageIndexChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) { var dataPager = (DataPager)d; var newValue = (int)e.NewValue+1; if (newValue==1) { dataPager.RefreshButtonList(newValue); } else { var item = dataPager.ButtonCollections.FirstOrDefault(t => t.Index.Equals(newValue)); if (item==null) dataPager.RefreshButtonList(newValue-dataPager.NumericButtonCount+1); } var selectedItem = dataPager.ButtonCollections.FirstOrDefault(t => t.Index.Equals(newValue)); if (selectedItem!=null) dataPager._listBoxButtonList.SelectedItem=selectedItem; } private void ComboBoxPageSize_SelectionChanged(object sender, SelectionChangedEventArgs e) { switch (comboBoxPageSize.SelectedIndex) { case 0: PageSize = 10; break; case 1: PageSize = 20; break; case 2: PageSize = 50; break; case 3: PageSize = 100; break; default: PageSize = 10; break; } } void OnPropertyChanged([CallerMemberName] string propertyName = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } private void RefreshButtonList(int Index) { for (int i = 0; i < ButtonCollections.Count; i++) { ButtonCollections[i].Index=Index; Index++; } } internal class ButtonCommandModel : BindableBase { private int index; public int Index { get { return index; } set { index=value; RaisePropertyChanged(); } } public DelegateCommand ClickCommand { get; set; } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Themes/Controls/Extensions.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Media; using System.Windows.Media.Media3D; namespace AppFramework.Admin.HandyUI.Themes.Controls { internal static class Extensions { public static IEnumerable VisualDepthFirstTraversal(this DependencyObject node) { if (node is null) throw new ArgumentNullException(nameof(node)); yield return node; for (var i = 0; i < VisualTreeHelper.GetChildrenCount(node); i++) { var child = VisualTreeHelper.GetChild(node, i); foreach (var descendant in child.VisualDepthFirstTraversal()) { yield return descendant; } } } public static IEnumerable VisualBreadthFirstTraversal(this DependencyObject node) { if (node is null) throw new ArgumentNullException(nameof(node)); for (var i = 0; i < VisualTreeHelper.GetChildrenCount(node); i++) { var child = VisualTreeHelper.GetChild(node, i); yield return child; } for (var i = 0; i < VisualTreeHelper.GetChildrenCount(node); i++) { var child = VisualTreeHelper.GetChild(node, i); foreach (var descendant in child.VisualDepthFirstTraversal()) { yield return descendant; } } } public static bool IsAncestorOf(this DependencyObject parent, DependencyObject? node) => node != null && parent.VisualDepthFirstTraversal().Contains(node); /// /// Returns full visual ancestry, starting at the leaf. /// If element is not of or the /// logical ancestry is used. /// /// /// public static IEnumerable GetVisualAncestry(this DependencyObject? leaf) { while (leaf is not null) { yield return leaf; leaf = leaf is Visual || leaf is Visual3D ? VisualTreeHelper.GetParent(leaf) : LogicalTreeHelper.GetParent(leaf); } } public static IEnumerable GetLogicalAncestry(this DependencyObject leaf) { while (leaf is not null) { yield return leaf; leaf = LogicalTreeHelper.GetParent(leaf); } } public static bool IsDescendantOf(this DependencyObject? leaf, DependencyObject? ancestor) { DependencyObject? parent = null; foreach (var node in leaf.GetVisualAncestry()) { if (Equals(node, ancestor)) return true; parent = node; } return parent?.GetLogicalAncestry().Contains(ancestor) == true; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Themes/Controls/IntToStringConverter.cs ================================================ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Data; namespace AppFramework.Admin.HandyUI.Themes.Controls { internal class IntToStringConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return value.ToString(); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Themes/Controls/NotConverter.cs ================================================ using System; using System.Globalization; using System.Windows.Data; namespace AppFramework.Admin.HandyUI.Themes.Controls { public class NotConverter : IValueConverter { public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) { if (value is null) return null; return !(value as bool?) ?? !bool.Parse(value.ToString() ?? bool.TrueString); } public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) { if (value is null) return null; return !(value as bool?) ?? !bool.Parse(value.ToString() ?? bool.TrueString); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Themes/Controls/PopupBox.cs ================================================ using System; using System.ComponentModel; using System.Linq; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Input; using System.Windows.Markup; using System.Windows.Media; using System.Windows.Media.Animation; namespace AppFramework.Admin.HandyUI.Themes.Controls { /// /// Defines how the popup is aligned to the toggle part of the control. /// public enum PopupBoxPlacementMode { /// /// Display the popup below the toggle, and align the left edges.3 /// BottomAndAlignLeftEdges, /// /// Display the popup below the toggle, and align the right edges. /// BottomAndAlignRightEdges, /// /// Display the popup below the toggle, and align the center of the popup with the center of the toggle. /// BottomAndAlignCentres, /// /// Display the popup above the toggle, and align the left edges. /// TopAndAlignLeftEdges, /// /// Display the popup above the toggle, and align the right edges. /// TopAndAlignRightEdges, /// /// Display the popup above the toggle, and align the center of the popup with the center of the toggle. /// TopAndAlignCentres, /// /// Display the popup to the left of the toggle, and align the top edges. /// LeftAndAlignTopEdges, /// /// Display the popup to the left of the toggle, and align the bottom edges. /// LeftAndAlignBottomEdges, /// /// Display the popup to the left of the toggle, and align the middles. /// LeftAndAlignMiddles, /// /// Display the popup to the right of the toggle, and align the top edges. /// RightAndAlignTopEdges, /// /// Display the popup to the right of the toggle, and align the bottom edges. /// RightAndAlignBottomEdges, /// /// Display the popup to the right of the toggle, and align the middles. /// RightAndAlignMiddles, } /// /// Defines what causes the to open it's popup. /// public enum PopupBoxPopupMode { /// /// Open when the toggle button is clicked. /// Click, /// /// Open when the mouse goes over the toggle button. /// MouseOver, /// /// Open when the mouse goes over the toggle button, or the space in which the popup box would occupy should it be open. /// MouseOverEager } /// /// Popup box, similar to a , but allows more customizable content. /// [TemplatePart(Name = PopupPartName, Type = typeof(Popup))] [TemplatePart(Name = PopupContentControlPartName, Type = typeof(ContentControl))] [TemplatePart(Name = TogglePartName, Type = typeof(ToggleButton))] [TemplateVisualState(GroupName = "PopupStates", Name = PopupIsOpenStateName)] [TemplateVisualState(GroupName = "PopupStates", Name = PopupIsClosedStateName)] [ContentProperty("PopupContent")] public class PopupBox : ContentControl { public const string PopupPartName = "PART_Popup"; public const string TogglePartName = "PART_Toggle"; public const string PopupContentControlPartName = "PART_PopupContentControl"; public const string PopupIsOpenStateName = "IsOpen"; public const string PopupIsClosedStateName = "IsClosed"; /// /// Routed command to be used inside of a popup content to close it. /// public static readonly RoutedCommand ClosePopupCommand = new(); private PopupEx? _popup; private ContentControl? _popupContentControl; private ToggleButton? _toggleButton; private Point _popupPointFromLastRequest; private Point _lastRelativePosition; static PopupBox() { DefaultStyleKeyProperty.OverrideMetadata(typeof(PopupBox), new FrameworkPropertyMetadata(typeof(PopupBox))); ToolTipService.IsEnabledProperty.OverrideMetadata(typeof(PopupBox), new FrameworkPropertyMetadata(null, CoerceToolTipIsEnabled)); EventManager.RegisterClassHandler(typeof(PopupBox), Mouse.LostMouseCaptureEvent, new MouseEventHandler(OnLostMouseCapture)); EventManager.RegisterClassHandler(typeof(PopupBox), Mouse.MouseDownEvent, new MouseButtonEventHandler(OnMouseButtonDown), true); } public PopupBox() { LayoutUpdated += OnLayoutUpdated; } public static readonly DependencyProperty ToggleContentProperty = DependencyProperty.Register( nameof(ToggleContent), typeof(object), typeof(PopupBox), new PropertyMetadata(default(object?))); /// /// Content to display in the toggle button. /// public object? ToggleContent { get => GetValue(ToggleContentProperty); set => SetValue(ToggleContentProperty, value); } public static readonly DependencyProperty ToggleContentTemplateProperty = DependencyProperty.Register( nameof(ToggleContentTemplate), typeof(DataTemplate), typeof(PopupBox), new PropertyMetadata(default(DataTemplate?))); /// /// Template for . /// public DataTemplate? ToggleContentTemplate { get => (DataTemplate?)GetValue(ToggleContentTemplateProperty); set => SetValue(ToggleContentTemplateProperty, value); } public static readonly DependencyProperty ToggleCheckedContentProperty = DependencyProperty.Register( nameof(ToggleCheckedContent), typeof(object), typeof(PopupBox), new PropertyMetadata(default(object?))); /// /// Content to display in the toggle when it's checked (when the popup is open). Optional; if not provided the is used. /// public object? ToggleCheckedContent { get => GetValue(ToggleCheckedContentProperty); set => SetValue(ToggleCheckedContentProperty, value); } public static readonly DependencyProperty ToggleCheckedContentTemplateProperty = DependencyProperty.Register( nameof(ToggleCheckedContentTemplate), typeof(DataTemplate), typeof(PopupBox), new PropertyMetadata(default(DataTemplate?))); /// /// Template for . /// public DataTemplate? ToggleCheckedContentTemplate { get => (DataTemplate?)GetValue(ToggleCheckedContentTemplateProperty); set => SetValue(ToggleCheckedContentTemplateProperty, value); } public static readonly DependencyProperty ToggleCheckedContentCommandProperty = DependencyProperty.Register( nameof(ToggleCheckedContentCommand), typeof(ICommand), typeof(PopupBox), new PropertyMetadata(default(ICommand?))); /// /// Command to execute if toggle is checked (popup is open) and is set. /// public ICommand? ToggleCheckedContentCommand { get => (ICommand?)GetValue(ToggleCheckedContentCommandProperty); set => SetValue(ToggleCheckedContentCommandProperty, value); } public static readonly DependencyProperty ToggleCheckedContentCommandParameterProperty = DependencyProperty.Register( nameof(ToggleCheckedContentCommandParameter), typeof(object), typeof(PopupBox), new PropertyMetadata(default(object?))); /// /// Command parameter to use in conjunction with . /// public object? ToggleCheckedContentCommandParameter { get => GetValue(ToggleCheckedContentCommandParameterProperty); set => SetValue(ToggleCheckedContentCommandParameterProperty, value); } public static readonly DependencyProperty PopupContentProperty = DependencyProperty.Register( nameof(PopupContent), typeof(object), typeof(PopupBox), new PropertyMetadata(default(object?))); /// /// Content to display in the content. /// public object? PopupContent { get => GetValue(PopupContentProperty); set => SetValue(PopupContentProperty, value); } public static readonly DependencyProperty PopupContentTemplateProperty = DependencyProperty.Register( nameof(PopupContentTemplate), typeof(DataTemplate), typeof(PopupBox), new PropertyMetadata(default(DataTemplate?))); /// /// Popup content template. /// public DataTemplate? PopupContentTemplate { get => (DataTemplate?)GetValue(PopupContentTemplateProperty); set => SetValue(PopupContentTemplateProperty, value); } public static readonly DependencyProperty IsPopupOpenProperty = DependencyProperty.Register( nameof(IsPopupOpen), typeof(bool), typeof(PopupBox), new FrameworkPropertyMetadata(default(bool), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, IsPopupOpenPropertyChangedCallback)); private static void IsPopupOpenPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) { var popupBox = (PopupBox)dependencyObject; var newValue = (bool)dependencyPropertyChangedEventArgs.NewValue; if (popupBox.PopupMode == PopupBoxPopupMode.Click) { if (newValue) Mouse.Capture(popupBox, CaptureMode.SubTree); else Mouse.Capture(null); } popupBox.AnimateChildrenIn(!newValue); popupBox._popup?.RefreshPosition(); VisualStateManager.GoToState(popupBox, newValue ? PopupIsOpenStateName : PopupIsClosedStateName, true); if (newValue) popupBox.OnOpened(); else popupBox.OnClosed(); } /// /// Gets or sets whether the popup is currently open. /// public bool IsPopupOpen { get => (bool)GetValue(IsPopupOpenProperty); set => SetValue(IsPopupOpenProperty, value); } public static readonly DependencyProperty StaysOpenProperty = DependencyProperty.Register( nameof(StaysOpen), typeof(bool), typeof(PopupBox), new PropertyMetadata(default(bool))); /// /// Indicates of the popup should stay open if a click occurs inside the popup. /// public bool StaysOpen { get => (bool)GetValue(StaysOpenProperty); set => SetValue(StaysOpenProperty, value); } public static readonly DependencyProperty PlacementModeProperty = DependencyProperty.Register( nameof(PlacementMode), typeof(PopupBoxPlacementMode), typeof(PopupBox), new PropertyMetadata(default(PopupBoxPlacementMode), PlacementModePropertyChangedCallback)); private static void PlacementModePropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) { ((PopupBox)dependencyObject)._popup?.RefreshPosition(); } /// /// Gets or sets how the popup is aligned in relation to the toggle. /// public PopupBoxPlacementMode PlacementMode { get => (PopupBoxPlacementMode)GetValue(PlacementModeProperty); set => SetValue(PlacementModeProperty, value); } public static readonly DependencyProperty PopupModeProperty = DependencyProperty.Register( nameof(PopupMode), typeof(PopupBoxPopupMode), typeof(PopupBox), new PropertyMetadata(default(PopupBoxPopupMode))); /// /// Gets or sets what trigger causes the popup to open. /// public PopupBoxPopupMode PopupMode { get => (PopupBoxPopupMode)GetValue(PopupModeProperty); set => SetValue(PopupModeProperty, value); } /// /// Get or sets how to unfurl controls when opening the popups. Only child elements of type are animated. /// public static readonly DependencyProperty UnfurlOrientationProperty = DependencyProperty.Register( nameof(UnfurlOrientation), typeof(Orientation), typeof(PopupBox), new PropertyMetadata(Orientation.Vertical)); /// /// Gets or sets how to unfurl controls when opening the popups. Only child elements of type are animated. /// public Orientation UnfurlOrientation { get => (Orientation)GetValue(UnfurlOrientationProperty); set => SetValue(UnfurlOrientationProperty, value); } /// /// Get or sets the popup horizontal offset in relation to the button. /// public static readonly DependencyProperty PopupHorizontalOffsetProperty = DependencyProperty.Register( nameof(PopupHorizontalOffset), typeof(double), typeof(PopupBox), new PropertyMetadata(default(double))); /// /// Get or sets the popup horizontal offset in relation to the button. /// public double PopupHorizontalOffset { get => (double)GetValue(PopupHorizontalOffsetProperty); set => SetValue(PopupHorizontalOffsetProperty, value); } /// /// Get or sets the popup vertical offset in relation to the button. /// public static readonly DependencyProperty PopupVerticalOffsetProperty = DependencyProperty.Register( nameof(PopupVerticalOffset), typeof(double), typeof(PopupBox), new PropertyMetadata(default(double))); /// /// Get or sets the popup vertical offset in relation to the button. /// public double PopupVerticalOffset { get => (double)GetValue(PopupVerticalOffsetProperty); set => SetValue(PopupVerticalOffsetProperty, value); } /// /// Get or sets the corner radius of the popup card. /// public static readonly DependencyProperty PopupUniformCornerRadiusProperty = DependencyProperty.Register( nameof(PopupUniformCornerRadius), typeof(double), typeof(PopupBox), new PropertyMetadata(default(double))); /// /// Get or sets the corner radius of the popup card. /// public double PopupUniformCornerRadius { get => (double)GetValue(PopupUniformCornerRadiusProperty); set => SetValue(PopupUniformCornerRadiusProperty, value); } /// /// Framework use. Provides the method used to position the popup. /// public CustomPopupPlacementCallback PopupPlacementMethod => GetPopupPlacement; /// /// Event raised when the checked toggled content (if set) is clicked. /// public static readonly RoutedEvent ToggleCheckedContentClickEvent = EventManager.RegisterRoutedEvent("ToggleCheckedContentClick", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(PopupBox)); /// /// Event raised when the checked toggled content (if set) is clicked. /// [Category("Behavior")] public event RoutedEventHandler ToggleCheckedContentClick { add { AddHandler(ToggleCheckedContentClickEvent, value); } remove { RemoveHandler(ToggleCheckedContentClickEvent, value); } } /// /// Raises . /// protected virtual void OnToggleCheckedContentClick() { var newEvent = new RoutedEventArgs(ToggleCheckedContentClickEvent, this); RaiseEvent(newEvent); } public static readonly RoutedEvent OpenedEvent = EventManager.RegisterRoutedEvent( "Opened", RoutingStrategy.Bubble, typeof(EventHandler), typeof(PopupBox)); /// /// Raised when the popup is opened. /// public event RoutedEventHandler Opened { add { AddHandler(OpenedEvent, value); } remove { RemoveHandler(OpenedEvent, value); } } /// /// Raises . /// protected virtual void OnOpened() { var newEvent = new RoutedEventArgs(OpenedEvent, this); RaiseEvent(newEvent); } public static readonly RoutedEvent ClosedEvent = EventManager.RegisterRoutedEvent( "Closed", RoutingStrategy.Bubble, typeof(EventHandler), typeof(PopupBox)); /// /// Raised when the popup is closed. /// public event RoutedEventHandler Closed { add { AddHandler(ClosedEvent, value); } remove { RemoveHandler(ClosedEvent, value); } } /// /// Raises . /// protected virtual void OnClosed() { var newEvent = new RoutedEventArgs(ClosedEvent, this); RaiseEvent(newEvent); } public override void OnApplyTemplate() { if (_toggleButton != null) _toggleButton.PreviewMouseLeftButtonUp -= ToggleButtonOnPreviewMouseLeftButtonUp; base.OnApplyTemplate(); _popup = GetTemplateChild(PopupPartName) as PopupEx; _popupContentControl = GetTemplateChild(PopupContentControlPartName) as ContentControl; _toggleButton = GetTemplateChild(TogglePartName) as ToggleButton; _popup?.CommandBindings.Add(new CommandBinding(ClosePopupCommand, ClosePopupHandler)); if (_toggleButton != null) _toggleButton.PreviewMouseLeftButtonUp += ToggleButtonOnPreviewMouseLeftButtonUp; VisualStateManager.GoToState(this, IsPopupOpen ? PopupIsOpenStateName : PopupIsClosedStateName, false); } protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e) { base.OnIsKeyboardFocusWithinChanged(e); if (IsPopupOpen && !IsKeyboardFocusWithin && !StaysOpen) { Close(); } } protected override void OnMouseEnter(MouseEventArgs e) { if (IsEnabled && IsLoaded && (PopupMode == PopupBoxPopupMode.MouseOverEager || PopupMode == PopupBoxPopupMode.MouseOver)) { if (_popupContentControl != null) { //if the invisible popup that is watching the mouse, isn't where we expected it to be //then the main popup toggle has been moved off screen...so we shouldn't show the popup content var inputSource = PresentationSource.FromVisual(_popupContentControl); if (inputSource != null) { var popupScreenPoint = _popupContentControl.PointToScreen(new Point()); popupScreenPoint.Offset(-_popupContentControl.Margin.Left, -_popupContentControl.Margin.Top); var expectedPopupScreenPoint = PointToScreen(_popupPointFromLastRequest); if (Math.Abs(popupScreenPoint.X - expectedPopupScreenPoint.X) > ActualWidth / 3 || Math.Abs(popupScreenPoint.Y - expectedPopupScreenPoint.Y) > ActualHeight / 3) return; } } SetCurrentValue(IsPopupOpenProperty, true); } base.OnMouseEnter(e); } private void ClosePopupHandler(object? sender, ExecutedRoutedEventArgs executedRoutedEventArgs) => IsPopupOpen = false; private void OnLayoutUpdated(object? sender, EventArgs eventArgs) { if (_popupContentControl != null && _popup != null && (PopupMode == PopupBoxPopupMode.MouseOver || PopupMode == PopupBoxPopupMode.MouseOverEager)) { Point relativePosition = _popupContentControl.TranslatePoint(new Point(), this); if (relativePosition != _lastRelativePosition) { _popup.RefreshPosition(); _lastRelativePosition = _popupContentControl.TranslatePoint(new Point(), this); } } } protected override void OnMouseLeave(MouseEventArgs e) { if (PopupMode == PopupBoxPopupMode.MouseOverEager || PopupMode == PopupBoxPopupMode.MouseOver) { Close(); } base.OnMouseLeave(e); } protected void Close() { if (IsPopupOpen) SetCurrentValue(IsPopupOpenProperty, false); } private CustomPopupPlacement[] GetPopupPlacement(Size popupSize, Size targetSize, Point offset) { double x, y; if (FlowDirection == FlowDirection.RightToLeft) offset.X += targetSize.Width / 2; switch (PlacementMode) { case PopupBoxPlacementMode.BottomAndAlignLeftEdges: x = 0 - Math.Abs(offset.X * 3); y = targetSize.Height - Math.Abs(offset.Y); break; case PopupBoxPlacementMode.BottomAndAlignRightEdges: x = 0 - popupSize.Width + targetSize.Width - offset.X; y = targetSize.Height - Math.Abs(offset.Y); break; case PopupBoxPlacementMode.BottomAndAlignCentres: x = targetSize.Width / 2 - popupSize.Width / 2 - Math.Abs(offset.X * 2); y = targetSize.Height - Math.Abs(offset.Y); break; case PopupBoxPlacementMode.TopAndAlignLeftEdges: x = 0 - Math.Abs(offset.X * 3); y = 0 - popupSize.Height - Math.Abs(offset.Y * 2); break; case PopupBoxPlacementMode.TopAndAlignRightEdges: x = 0 - popupSize.Width + targetSize.Width - offset.X; y = 0 - popupSize.Height - Math.Abs(offset.Y * 2); break; case PopupBoxPlacementMode.TopAndAlignCentres: x = targetSize.Width / 2 - popupSize.Width / 2 - Math.Abs(offset.X * 2); y = 0 - popupSize.Height - Math.Abs(offset.Y * 2); break; case PopupBoxPlacementMode.LeftAndAlignTopEdges: x = 0 - popupSize.Width - Math.Abs(offset.X * 2); y = 0 - Math.Abs(offset.Y * 3); break; case PopupBoxPlacementMode.LeftAndAlignBottomEdges: x = 0 - popupSize.Width - Math.Abs(offset.X * 2); y = 0 - (popupSize.Height - targetSize.Height); break; case PopupBoxPlacementMode.LeftAndAlignMiddles: x = 0 - popupSize.Width - Math.Abs(offset.X * 2); y = targetSize.Height / 2 - popupSize.Height / 2 - Math.Abs(offset.Y * 2); break; case PopupBoxPlacementMode.RightAndAlignTopEdges: x = targetSize.Width; y = 0 - Math.Abs(offset.X * 3); break; case PopupBoxPlacementMode.RightAndAlignBottomEdges: x = targetSize.Width; y = 0 - (popupSize.Height - targetSize.Height); break; case PopupBoxPlacementMode.RightAndAlignMiddles: x = targetSize.Width; y = targetSize.Height / 2 - popupSize.Height / 2 - Math.Abs(offset.Y * 2); break; default: throw new ArgumentOutOfRangeException(); } _popupPointFromLastRequest = new Point(x, y); return new[] { new CustomPopupPlacement(_popupPointFromLastRequest, PopupPrimaryAxis.Horizontal) }; } private void AnimateChildrenIn(bool reverse) { if (_popupContentControl == null) return; if (VisualTreeHelper.GetChildrenCount(_popupContentControl) != 1) return; var contentPresenter = VisualTreeHelper.GetChild(_popupContentControl, 0) as ContentPresenter; var controls = contentPresenter?.VisualDepthFirstTraversal().OfType(); double translateCoordinateFrom; if ((PlacementMode == PopupBoxPlacementMode.TopAndAlignCentres || PlacementMode == PopupBoxPlacementMode.TopAndAlignLeftEdges || PlacementMode == PopupBoxPlacementMode.TopAndAlignRightEdges || PlacementMode == PopupBoxPlacementMode.LeftAndAlignBottomEdges || PlacementMode == PopupBoxPlacementMode.RightAndAlignBottomEdges || (UnfurlOrientation == Orientation.Horizontal && ( PlacementMode == PopupBoxPlacementMode.LeftAndAlignBottomEdges || PlacementMode == PopupBoxPlacementMode.LeftAndAlignMiddles || PlacementMode == PopupBoxPlacementMode.LeftAndAlignTopEdges )) )) { controls = controls?.Reverse(); translateCoordinateFrom = 80; } else translateCoordinateFrom = -80; var translateCoordinatePath = "(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform." + (UnfurlOrientation == Orientation.Horizontal ? "X)" : "Y)"); var sineEase = new SineEase(); var i = 0; foreach (var uiElement in controls ?? Enumerable.Empty()) { var deferredStart = i++ * 20; var deferredEnd = deferredStart + 200.0; var absoluteZeroKeyTime = KeyTime.FromPercent(0.0); var deferredStartKeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(deferredStart)); var deferredEndKeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(deferredEnd)); var elementTranslateCoordinateFrom = translateCoordinateFrom * i; var translateTransform = new TranslateTransform( UnfurlOrientation == Orientation.Vertical ? 0 : elementTranslateCoordinateFrom, UnfurlOrientation == Orientation.Vertical ? elementTranslateCoordinateFrom : 0); var transformGroup = new TransformGroup { Children = new TransformCollection(new Transform[] { new ScaleTransform(0, 0), translateTransform }) }; uiElement.SetCurrentValue(RenderTransformOriginProperty, new Point(.5, .5)); uiElement.RenderTransform = transformGroup; var opacityAnimation = new DoubleAnimationUsingKeyFrames(); opacityAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(0, absoluteZeroKeyTime, sineEase)); opacityAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(0, deferredStartKeyTime, sineEase)); opacityAnimation.KeyFrames.Add(new EasingDoubleKeyFrame((double)uiElement.GetAnimationBaseValue(OpacityProperty), deferredEndKeyTime, sineEase)); Storyboard.SetTargetProperty(opacityAnimation, new PropertyPath("Opacity")); Storyboard.SetTarget(opacityAnimation, uiElement); var scaleXAnimation = new DoubleAnimationUsingKeyFrames(); scaleXAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(0, absoluteZeroKeyTime, sineEase)); scaleXAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(0, deferredStartKeyTime, sineEase)); scaleXAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(1, deferredEndKeyTime, sineEase)); Storyboard.SetTargetProperty(scaleXAnimation, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)")); Storyboard.SetTarget(scaleXAnimation, uiElement); var scaleYAnimation = new DoubleAnimationUsingKeyFrames(); scaleYAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(0, absoluteZeroKeyTime, sineEase)); scaleYAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(0, deferredStartKeyTime, sineEase)); scaleYAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(1, deferredEndKeyTime, sineEase)); Storyboard.SetTargetProperty(scaleYAnimation, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)")); Storyboard.SetTarget(scaleYAnimation, uiElement); var translateCoordinateAnimation = new DoubleAnimationUsingKeyFrames(); translateCoordinateAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(elementTranslateCoordinateFrom, absoluteZeroKeyTime, sineEase)); translateCoordinateAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(elementTranslateCoordinateFrom, deferredStartKeyTime, sineEase)); translateCoordinateAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(0, deferredEndKeyTime, sineEase)); Storyboard.SetTargetProperty(translateCoordinateAnimation, new PropertyPath(translateCoordinatePath)); Storyboard.SetTarget(translateCoordinateAnimation, uiElement); var storyboard = new Storyboard(); storyboard.Children.Add(opacityAnimation); storyboard.Children.Add(scaleXAnimation); storyboard.Children.Add(scaleYAnimation); storyboard.Children.Add(translateCoordinateAnimation); if (reverse) { storyboard.AutoReverse = true; storyboard.Begin(); storyboard.Seek(TimeSpan.FromMilliseconds(deferredEnd)); storyboard.Resume(); } else storyboard.Begin(); } } #region Capture [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern IntPtr GetCapture(); private static void OnLostMouseCapture(object? sender, MouseEventArgs e) { var popupBox = sender as PopupBox; if (popupBox is null || Equals(Mouse.Captured, popupBox)) return; if (Equals(e.OriginalSource, popupBox)) { if (Mouse.Captured is null || popupBox._popup is null) { if (!(Mouse.Captured as DependencyObject).IsDescendantOf(popupBox._popup)) { popupBox.Close(); } } } else { if ((Mouse.Captured as DependencyObject).GetVisualAncestry().Contains(popupBox._popup?.Child)) { // Take capture if one of our children gave up capture (by closing their drop down) if (!popupBox.IsPopupOpen || Mouse.Captured is not null || GetCapture() != IntPtr.Zero) return; Mouse.Capture(popupBox, CaptureMode.SubTree); e.Handled = true; } else { if (popupBox.StaysOpen && popupBox.IsPopupOpen) { // allow scrolling if (GetCapture() != IntPtr.Zero) return; // Take capture back because click happened outside of control Mouse.Capture(popupBox, CaptureMode.SubTree); e.Handled = true; } else { popupBox.Close(); } } } } private static void OnMouseButtonDown(object sender, MouseButtonEventArgs e) { var popupBox = (PopupBox)sender; if (!popupBox.IsKeyboardFocusWithin) { popupBox.Focus(); } e.Handled = true; if (Mouse.Captured == popupBox && e.OriginalSource == popupBox) { popupBox.Close(); } } protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) { if (IsPopupOpen && !StaysOpen) { Close(); e.Handled = true; } else base.OnMouseLeftButtonUp(e); } #endregion private void ToggleButtonOnPreviewMouseLeftButtonUp(object? sender, MouseButtonEventArgs mouseButtonEventArgs) { if (PopupMode == PopupBoxPopupMode.Click || !IsPopupOpen) return; if (ToggleCheckedContent != null) { OnToggleCheckedContentClick(); if (ToggleCheckedContentCommand != null && ToggleCheckedContentCommand.CanExecute(ToggleCheckedContentCommandParameter) ) { ToggleCheckedContentCommand.Execute(ToggleCheckedContentCommandParameter); } } Close(); Mouse.Capture(null); mouseButtonEventArgs.Handled = true; } private static object CoerceToolTipIsEnabled(DependencyObject dependencyObject, object value) { var popupBox = (PopupBox)dependencyObject; return popupBox.IsPopupOpen ? false : value; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Themes/Controls/PopupEx.cs ================================================ using System; using System.Runtime.InteropServices; using System.Security; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Input; using System.Windows.Interop; namespace AppFramework.Admin.HandyUI.Themes.Controls { /// /// This class was initially based on work done in ControlzEx /// https://github.com/ControlzEx/ControlzEx /// /// This custom popup can be used by validation error templates or something else. /// It provides some additional nice features: /// - repositioning if host-window size or location changed /// - repositioning if host-window gets maximized and vice versa /// - it's only topmost if the host-window is activated /// public class PopupEx : Popup { public static readonly DependencyProperty CloseOnMouseLeftButtonDownProperty = DependencyProperty.Register(nameof(CloseOnMouseLeftButtonDown), typeof(bool), typeof(PopupEx), new PropertyMetadata(false)); /// /// Gets/sets if the popup can be closed by left mouse button down. /// public bool CloseOnMouseLeftButtonDown { get => (bool)GetValue(CloseOnMouseLeftButtonDownProperty); set => SetValue(CloseOnMouseLeftButtonDownProperty, value); } public static readonly DependencyProperty AllowTopMostProperty = DependencyProperty.Register(nameof(AllowTopMost), typeof(bool), typeof(PopupEx), new PropertyMetadata(true)); public bool AllowTopMost { get => (bool)GetValue(AllowTopMostProperty); set => SetValue(AllowTopMostProperty, value); } public PopupEx() { Loaded += PopupEx_Loaded; Opened += PopupEx_Opened; } /// /// Causes the popup to update it's position according to it's current settings. /// public void RefreshPosition() { var offset = HorizontalOffset; // "bump" the offset to cause the popup to reposition itself on its own SetCurrentValue(HorizontalOffsetProperty, offset + 1); SetCurrentValue(HorizontalOffsetProperty, offset); } private void PopupEx_Loaded(object? sender, RoutedEventArgs e) { var target = PlacementTarget as FrameworkElement; if (target is null) { return; } _hostWindow = Window.GetWindow(target); if (_hostWindow is null) { return; } _hostWindow.LocationChanged -= HostWindow_SizeOrLocationChanged; _hostWindow.LocationChanged += HostWindow_SizeOrLocationChanged; _hostWindow.SizeChanged -= HostWindow_SizeOrLocationChanged; _hostWindow.SizeChanged += HostWindow_SizeOrLocationChanged; target.SizeChanged -= HostWindow_SizeOrLocationChanged; target.SizeChanged += HostWindow_SizeOrLocationChanged; _hostWindow.StateChanged -= HostWindow_StateChanged; _hostWindow.StateChanged += HostWindow_StateChanged; _hostWindow.Activated -= HostWindow_Activated; _hostWindow.Activated += HostWindow_Activated; _hostWindow.Deactivated -= HostWindow_Deactivated; _hostWindow.Deactivated += HostWindow_Deactivated; Unloaded -= PopupEx_Unloaded; Unloaded += PopupEx_Unloaded; } private void PopupEx_Opened(object? sender, EventArgs e) => SetTopmostState(_hostWindow?.IsActive ?? true); private void HostWindow_Activated(object? sender, EventArgs e) => SetTopmostState(true); private void HostWindow_Deactivated(object? sender, EventArgs e) => SetTopmostState(_hostWindow?.Topmost ?? false); private void PopupEx_Unloaded(object? sender, RoutedEventArgs e) { if (PlacementTarget is FrameworkElement target) { target.SizeChanged -= HostWindow_SizeOrLocationChanged; } if (_hostWindow != null) { _hostWindow.LocationChanged -= HostWindow_SizeOrLocationChanged; _hostWindow.SizeChanged -= HostWindow_SizeOrLocationChanged; _hostWindow.StateChanged -= HostWindow_StateChanged; _hostWindow.Activated -= HostWindow_Activated; _hostWindow.Deactivated -= HostWindow_Deactivated; } Unloaded -= PopupEx_Unloaded; Opened -= PopupEx_Opened; _hostWindow = null; } private void HostWindow_StateChanged(object? sender, EventArgs e) { if (_hostWindow != null && _hostWindow.WindowState != WindowState.Minimized) { // special handling for validation popup var target = PlacementTarget as FrameworkElement; var holder = target != null ? target.DataContext as AdornedElementPlaceholder : null; if (holder != null && holder.AdornedElement != null) { PopupAnimation = PopupAnimation.None; IsOpen = false; } } } private void HostWindow_SizeOrLocationChanged(object? sender, EventArgs e) => RefreshPosition(); private void SetTopmostState(bool isTop) { isTop &= AllowTopMost; // Dont apply state if its the same as incoming state if (appliedTopMost.HasValue && appliedTopMost == isTop) { return; } if (Child is null) { return; } var hwndSource = (PresentationSource.FromVisual(Child)) as HwndSource; if (hwndSource is null) { return; } var hwnd = hwndSource.Handle; RECT rect; if (!GetWindowRect(hwnd, out rect)) { return; } //Debug.WriteLine("setting z-order " + isTop); var left = rect.Left; var top = rect.Top; var width = rect.Width; var height = rect.Height; if (isTop) { SetWindowPos(hwnd, HWND_TOPMOST, left, top, width, height, SWP.TOPMOST); } else { // Z-Order would only get refreshed/reflected if clicking the // the titlebar (as opposed to other parts of the external // window) unless I first set the popup to HWND_BOTTOM // then HWND_TOP before HWND_NOTOPMOST SetWindowPos(hwnd, HWND_BOTTOM, left, top, width, height, SWP.TOPMOST); SetWindowPos(hwnd, HWND_TOP, left, top, width, height, SWP.TOPMOST); SetWindowPos(hwnd, HWND_NOTOPMOST, left, top, width, height, SWP.TOPMOST); } appliedTopMost = isTop; } protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e) { if (CloseOnMouseLeftButtonDown) { IsOpen = false; } } private Window? _hostWindow; private bool? appliedTopMost; private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1); private static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2); private static readonly IntPtr HWND_TOP = new IntPtr(0); private static readonly IntPtr HWND_BOTTOM = new IntPtr(1); /// /// SetWindowPos options /// [Flags] internal enum SWP { ASYNCWINDOWPOS = 0x4000, DEFERERASE = 0x2000, DRAWFRAME = 0x0020, FRAMECHANGED = 0x0020, HIDEWINDOW = 0x0080, NOACTIVATE = 0x0010, NOCOPYBITS = 0x0100, NOMOVE = 0x0002, NOOWNERZORDER = 0x0200, NOREDRAW = 0x0008, NOREPOSITION = 0x0200, NOSENDCHANGING = 0x0400, NOSIZE = 0x0001, NOZORDER = 0x0004, SHOWWINDOW = 0x0040, TOPMOST = SWP.NOACTIVATE | SWP.NOOWNERZORDER | SWP.NOSIZE | SWP.NOMOVE | SWP.NOREDRAW | SWP.NOSENDCHANGING, } internal static int LOWORD(int i) { return (short)(i & 0xFFFF); } [StructLayout(LayoutKind.Sequential)] internal struct POINT { public int x; public int y; } [StructLayout(LayoutKind.Sequential)] internal struct SIZE { public int cx; public int cy; } [StructLayout(LayoutKind.Sequential)] internal struct RECT { private int _left; private int _top; private int _right; private int _bottom; public void Offset(int dx, int dy) { _left += dx; _top += dy; _right += dx; _bottom += dy; } public int Left { get => _left; set => _left = value; } public int Right { get => _right; set => _right = value; } public int Top { get => _top; set => _top = value; } public int Bottom { get => _bottom; set => _bottom = value; } public int Width => _right - _left; public int Height => _bottom - _top; public POINT Position => new POINT { x = _left, y = _top }; public SIZE Size => new SIZE { cx = Width, cy = Height }; public static RECT Union(RECT rect1, RECT rect2) { return new RECT { Left = Math.Min(rect1.Left, rect2.Left), Top = Math.Min(rect1.Top, rect2.Top), Right = Math.Max(rect1.Right, rect2.Right), Bottom = Math.Max(rect1.Bottom, rect2.Bottom), }; } public override bool Equals(object? obj) { try { var rc = (RECT)obj!; return rc._bottom == _bottom && rc._left == _left && rc._right == _right && rc._top == _top; } catch (InvalidCastException) { return false; } } public override int GetHashCode() => (_left << 16 | LOWORD(_right)) ^ (_top << 16 | LOWORD(_bottom)); } [SecurityCritical] [DllImport("user32.dll", EntryPoint = "GetWindowRect", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect); [SecurityCritical] [DllImport("user32.dll", EntryPoint = "SetWindowPos", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool _SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SWP uFlags); [SecurityCritical] private static bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SWP uFlags) { if (!_SetWindowPos(hWnd, hWndInsertAfter, x, y, cx, cy, uFlags)) { // If this fails it's never worth taking down the process. Let the caller deal with the error if they want. return false; } return true; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Themes/Controls/ScrollViewerAssist.cs ================================================ using System; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Interop; namespace AppFramework.Admin.HandyUI.Themes.Controls; public static class ScrollViewerAssist { internal static readonly DependencyProperty HorizontalOffsetProperty = DependencyProperty.RegisterAttached( "SyncHorizontalOffset", typeof(double), typeof(ScrollViewerAssist), new PropertyMetadata(default(double), OnSyncHorizontalOffsetChanged)); private static void OnSyncHorizontalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var scrollViewer = d as ScrollViewer; scrollViewer?.ScrollToHorizontalOffset((double)e.NewValue); } internal static void SetSyncHorizontalOffset(DependencyObject element, double value) { element.SetValue(HorizontalOffsetProperty, value); } internal static double GetSyncHorizontalOffset(DependencyObject element) { return (double)element.GetValue(HorizontalOffsetProperty); } public static readonly DependencyProperty IsAutoHideEnabledProperty = DependencyProperty.RegisterAttached( "IsAutoHideEnabled", typeof(bool), typeof(ScrollViewerAssist), new PropertyMetadata(default(bool))); public static void SetIsAutoHideEnabled(DependencyObject element, bool value) { element.SetValue(IsAutoHideEnabledProperty, value); } public static bool GetIsAutoHideEnabled(DependencyObject element) { return (bool)element.GetValue(IsAutoHideEnabledProperty); } public static readonly DependencyProperty CornerRectangleVisibilityProperty = DependencyProperty.RegisterAttached( "CornerRectangleVisibility", typeof(Visibility), typeof(ScrollViewerAssist), new PropertyMetadata(default(Visibility))); public static void SetCornerRectangleVisibility(DependencyObject element, Visibility value) { element.SetValue(CornerRectangleVisibilityProperty, value); } public static Visibility GetCornerRectangleVisibility(DependencyObject element) { return (Visibility)element.GetValue(CornerRectangleVisibilityProperty); } public static readonly DependencyProperty ShowSeparatorsProperty = DependencyProperty.RegisterAttached( "ShowSeparators", typeof(bool), typeof(ScrollViewerAssist), new PropertyMetadata(default(bool))); public static void SetShowSeparators(DependencyObject element, bool value) { element.SetValue(ShowSeparatorsProperty, value); } public static bool GetShowSeparators(DependencyObject element) { return (bool)element.GetValue(ShowSeparatorsProperty); } public static readonly DependencyProperty IgnorePaddingProperty = DependencyProperty.RegisterAttached( "IgnorePadding", typeof(bool), typeof(ScrollViewerAssist), new PropertyMetadata(true)); public static void SetIgnorePadding(DependencyObject element, bool value) => element.SetValue(IgnorePaddingProperty, value); public static bool GetIgnorePadding(DependencyObject element) => (bool)element.GetValue(IgnorePaddingProperty); private static readonly DependencyProperty HorizontalScrollHookProperty = DependencyProperty.RegisterAttached( "HorizontalScrollHook", typeof(HwndSourceHook), typeof(ScrollViewerAssist), new PropertyMetadata(null)); public static readonly DependencyProperty SupportHorizontalScrollProperty = DependencyProperty.RegisterAttached( "SupportHorizontalScroll", typeof(bool), typeof(ScrollViewerAssist), new PropertyMetadata(false, OnSupportHorizontalScrollChanged)); private static void OnSupportHorizontalScrollChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { //Based on: https://blog.walterlv.com/post/handle-horizontal-scrolling-of-touchpad-en.html if (d is ScrollViewer scrollViewer) { if ((bool)e.NewValue) { OnLoaded(scrollViewer, sv => { if (GetSupportHorizontalScroll(sv)) { RegisterHook(sv); } }); } else { OnLoaded(scrollViewer, sv => { if (!GetSupportHorizontalScroll(sv)) { RemoveHook(sv); } }); } } static void OnLoaded(ScrollViewer scrollViewer, Action doOnLoaded) { if (scrollViewer.IsLoaded) { doOnLoaded(scrollViewer); } else { RoutedEventHandler? onLoaded = null; onLoaded = (_, _) => { scrollViewer.Loaded -= onLoaded; doOnLoaded(scrollViewer); }; scrollViewer.Loaded += onLoaded; } } static void RemoveHook(ScrollViewer scrollViewer) { if (scrollViewer.GetValue(HorizontalScrollHookProperty) is HwndSourceHook hook && PresentationSource.FromVisual(scrollViewer) is HwndSource source) { source.RemoveHook(hook); scrollViewer.SetValue(HorizontalScrollHookProperty, null); } } static void RegisterHook(ScrollViewer scrollViewer) { RemoveHook(scrollViewer); if (PresentationSource.FromVisual(scrollViewer) is HwndSource source) { HwndSourceHook hook = Hook; scrollViewer.SetValue(HorizontalScrollHookProperty, hook); source.AddHook(hook); } IntPtr Hook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { const int WM_MOUSEHWHEEL = 0x020E; switch (msg) { case WM_MOUSEHWHEEL: int tilt = (short)((wParam.ToInt64() >> 16) & 0xFFFF); OnMouseTilt(tilt); return (IntPtr)1; } return IntPtr.Zero; } void OnMouseTilt(int tilt) { scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset + tilt); } } } public static readonly DependencyProperty BubbleVerticalScrollProperty = DependencyProperty.RegisterAttached( "BubbleVerticalScroll", typeof(bool), typeof(ScrollViewerAssist), new PropertyMetadata(false, OnBubbleVerticalScrollChanged)); private static void OnBubbleVerticalScrollChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is ScrollViewer scrollViewer) { if ((bool)e.NewValue) { OnLoaded(scrollViewer, sv => { if (GetBubbleVerticalScroll(sv)) { RegisterHook(sv); } }); } else { OnLoaded(scrollViewer, sv => { if (!GetBubbleVerticalScroll(sv)) { RemoveHook(sv); } }); } } static void OnLoaded(ScrollViewer scrollViewer, Action doOnLoaded) { if (scrollViewer.IsLoaded) { doOnLoaded(scrollViewer); } else { RoutedEventHandler? onLoaded = null; onLoaded = (_, _) => { scrollViewer.Loaded -= onLoaded; doOnLoaded(scrollViewer); }; scrollViewer.Loaded += onLoaded; } } static void RemoveHook(ScrollViewer scrollViewer) { scrollViewer.RemoveHandler(UIElement.MouseWheelEvent, (RoutedEventHandler)ScrollViewerOnMouseWheel); } static void RegisterHook(ScrollViewer scrollViewer) { RemoveHook(scrollViewer); scrollViewer.AddHandler(UIElement.MouseWheelEvent, (RoutedEventHandler)ScrollViewerOnMouseWheel, true); } // This relay is only needed because the UIElement.AddHandler() has strict requirements for the signature of the passed Delegate static void ScrollViewerOnMouseWheel(object sender, RoutedEventArgs e) => HandleMouseWheel(sender, (MouseWheelEventArgs)e); static void HandleMouseWheel(object sender, MouseWheelEventArgs e) { var scrollViewer = (ScrollViewer)sender; if (scrollViewer.GetVisualAncestry().Skip(1).FirstOrDefault() is not UIElement parentUiElement) return; // Re-raise the mouse wheel event on the visual parent to bubble it upwards e.Handled = true; var mouseWheelEventArgs = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta) { RoutedEvent = UIElement.MouseWheelEvent, Source = sender }; parentUiElement.RaiseEvent(mouseWheelEventArgs); } } public static void SetSupportHorizontalScroll(DependencyObject element, bool value) => element.SetValue(SupportHorizontalScrollProperty, value); public static bool GetSupportHorizontalScroll(DependencyObject element) => (bool)element.GetValue(SupportHorizontalScrollProperty); public static void SetBubbleVerticalScroll(DependencyObject element, bool value) => element.SetValue(BubbleVerticalScrollProperty, value); public static bool GetBubbleVerticalScroll(DependencyObject element) => (bool)element.GetValue(BubbleVerticalScrollProperty); } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Themes/Controls/TabAssist.cs ================================================ using System.Windows; namespace AppFramework.Admin.HandyUI.Themes.Controls { public static class TabAssist { public static readonly DependencyProperty HasFilledTabProperty = DependencyProperty.RegisterAttached( "HasFilledTab", typeof(bool), typeof(TabAssist), new PropertyMetadata(false)); public static void SetHasFilledTab(DependencyObject element, bool value) => element.SetValue(HasFilledTabProperty, value); public static bool GetHasFilledTab(DependencyObject element) => (bool)element.GetValue(HasFilledTabProperty); public static readonly DependencyProperty HasUniformTabWidthProperty = DependencyProperty.RegisterAttached( "HasUniformTabWidth", typeof(bool), typeof(TabAssist), new PropertyMetadata(false)); public static void SetHasUniformTabWidth(DependencyObject element, bool value) => element.SetValue(HasUniformTabWidthProperty, value); public static bool GetHasUniformTabWidth(DependencyObject element) => (bool)element.GetValue(HasUniformTabWidthProperty); } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Themes/Controls/TabCloseItem.cs ================================================ using System.Windows; using System.Windows.Controls; using System.Windows.Input; namespace AppFramework.Admin.HandyUI.Themes.Controls { internal class TabCloseItem : TabItem { public ICommand? CloseCommand { get => (ICommand?)GetValue(CloseCommandProperty); set => SetValue(CloseCommandProperty, value); } public static readonly DependencyProperty CloseCommandProperty = DependencyProperty.Register(nameof(CloseCommand), typeof(ICommand), typeof(TabCloseItem), new PropertyMetadata(default(ICommand?))); public object? CloseCommandParameter { get => GetValue(CloseCommandParameterProperty); set => SetValue(CloseCommandParameterProperty, value); } public static readonly DependencyProperty CloseCommandParameterProperty = DependencyProperty.Register(nameof(CloseCommandParameter), typeof(object), typeof(TabCloseItem), new PropertyMetadata(default(object?))); public override void OnApplyTemplate() { if (GetTemplateChild("PART_DeleteButton") is Button closeButton) { closeButton.Click+=CloseButton_Click; } base.OnApplyTemplate(); } private void CloseButton_Click(object sender, System.Windows.RoutedEventArgs e) { OnCloseClick(); e.Handled = true; } public event RoutedEventHandler CloseClick { add => AddHandler(CloseClickEvent, value); remove => RemoveHandler(CloseClickEvent, value); } public static readonly RoutedEvent CloseClickEvent = EventManager.RegisterRoutedEvent(nameof(CloseClick), RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(TabCloseItem)); protected virtual void OnCloseClick() { RaiseEvent(new RoutedEventArgs(CloseClickEvent, this)); if (CloseCommand?.CanExecute(CloseCommandParameter) ?? false) { CloseCommand.Execute(CloseCommandParameter); } } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Themes/Controls/TabControl.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; namespace AppFramework.Admin.HandyUI.Themes.Controls { internal class TabControl: System.Windows.Controls.TabControl { protected override bool IsItemItsOwnContainerOverride(object item) { return item is TabCloseItem; } protected override DependencyObject GetContainerForItemOverride() { return new TabCloseItem(); } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Themes/DataPager.xaml ================================================  ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Views/LoginView.xaml.cs ================================================ using Prism.Services.Dialogs; using System; using System.Windows; namespace AppFramework.Admin.HandyUI.Views { public partial class LoginView : Window, IDialogWindow { public LoginView() { InitializeComponent(); HeaderBorder.MouseMove += (s, e) => { if (e.LeftButton == System.Windows.Input.MouseButtonState.Pressed) this.DragMove(); }; btnClose.Click += (s, e) => { Environment.Exit(0); }; } public IDialogResult Result { get; set; } } } ================================================ FILE: aspnet-core/src/AppFramework.Admin.HandyUI/Views/MainTabsView.xaml ================================================