Repository: mysteryx93/HanumanInstitute.MvvmDialogs Branch: master Commit: 4a548705b722 Files: 589 Total size: 838.2 KB Directory structure: gitextract_3wxtmbfy/ ├── .editorconfig ├── .gitattributes ├── .gitignore ├── CHANGELOG.md ├── Directory.Packages.props ├── LICENSE.md ├── MvvmDialogs.sln ├── MvvmDialogs.sln.DotSettings ├── README.md ├── deletebin.sh ├── nuget.config ├── samples/ │ ├── Avalonia/ │ │ ├── CrossPlatform/ │ │ │ ├── .gitignore │ │ │ ├── Demo.CrossPlatform/ │ │ │ │ ├── App.axaml │ │ │ │ ├── App.axaml.cs │ │ │ │ ├── Business/ │ │ │ │ │ ├── StreamExtensions.cs │ │ │ │ │ └── SynchronousProgress.cs │ │ │ │ ├── Demo.CrossPlatform.csproj │ │ │ │ ├── FodyWeavers.xml │ │ │ │ ├── GlobalUsings.cs │ │ │ │ ├── Roots.xml │ │ │ │ ├── Services/ │ │ │ │ │ ├── IStorageService.cs │ │ │ │ │ └── StorageService.cs │ │ │ │ ├── ViewLocator.cs │ │ │ │ ├── ViewModels/ │ │ │ │ │ ├── ConfirmCloseViewModel.cs │ │ │ │ │ ├── CurrentTimeViewModel.cs │ │ │ │ │ ├── MainViewModel.cs │ │ │ │ │ └── ViewModelBase.cs │ │ │ │ └── Views/ │ │ │ │ ├── ConfirmCloseView.axaml │ │ │ │ ├── ConfirmCloseView.axaml.cs │ │ │ │ ├── ConfirmCloseWindow.axaml │ │ │ │ ├── ConfirmCloseWindow.axaml.cs │ │ │ │ ├── CurrentTimeView.axaml │ │ │ │ ├── CurrentTimeView.axaml.cs │ │ │ │ ├── CurrentTimeWindow.axaml │ │ │ │ ├── CurrentTimeWindow.axaml.cs │ │ │ │ ├── MainView.axaml │ │ │ │ ├── MainView.axaml.cs │ │ │ │ ├── MainWindow.axaml │ │ │ │ └── MainWindow.axaml.cs │ │ │ ├── Demo.CrossPlatform.Android/ │ │ │ │ ├── Demo.CrossPlatform.Android.csproj │ │ │ │ ├── MainActivity.cs │ │ │ │ ├── Properties/ │ │ │ │ │ └── AndroidManifest.xml │ │ │ │ └── Resources/ │ │ │ │ ├── drawable/ │ │ │ │ │ └── splash_screen.xml │ │ │ │ └── values/ │ │ │ │ ├── colors.xml │ │ │ │ └── styles.xml │ │ │ ├── Demo.CrossPlatform.Browser/ │ │ │ │ ├── AppBundle/ │ │ │ │ │ ├── app.css │ │ │ │ │ ├── index.html │ │ │ │ │ └── main.js │ │ │ │ ├── Demo.CrossPlatform.Browser.csproj │ │ │ │ ├── Program.cs │ │ │ │ ├── Properties/ │ │ │ │ │ └── launchSettings.json │ │ │ │ └── runtimeconfig.template.json │ │ │ ├── Demo.CrossPlatform.Desktop/ │ │ │ │ ├── Demo.CrossPlatform.Desktop.csproj │ │ │ │ ├── Program.cs │ │ │ │ └── app.manifest │ │ │ ├── Demo.CrossPlatform.iOS/ │ │ │ │ ├── AppDelegate.cs │ │ │ │ ├── Demo.CrossPlatform.iOS.csproj │ │ │ │ ├── Entitlements.plist │ │ │ │ ├── Info.plist │ │ │ │ ├── Main.cs │ │ │ │ └── Resources/ │ │ │ │ └── LaunchScreen.xib │ │ │ └── Demo.CrossPlatform.sln │ │ ├── Demo.ActivateNonModalDialog.MvvmToolkit/ │ │ │ ├── App.axaml │ │ │ ├── App.axaml.cs │ │ │ ├── CurrentTimeDialog.axaml │ │ │ ├── CurrentTimeDialog.axaml.cs │ │ │ ├── CurrentTimeDialogViewModel.cs │ │ │ ├── Demo.ActivateNonModalDialog.MvvmToolkit.csproj │ │ │ ├── MainWindow.axaml │ │ │ ├── MainWindow.axaml.cs │ │ │ ├── MainWindowViewModel.cs │ │ │ ├── Program.cs │ │ │ ├── ViewLocator.cs │ │ │ └── ViewModelBase.cs │ │ ├── Demo.CloseNonModalDialog/ │ │ │ ├── App.axaml │ │ │ ├── App.axaml.cs │ │ │ ├── CurrentTimeDialog.axaml │ │ │ ├── CurrentTimeDialog.axaml.cs │ │ │ ├── CurrentTimeDialogViewModel.cs │ │ │ ├── Demo.CloseNonModalDialog.csproj │ │ │ ├── MainWindow.axaml │ │ │ ├── MainWindow.axaml.cs │ │ │ ├── MainWindowViewModel.cs │ │ │ ├── Program.cs │ │ │ ├── ViewLocator.cs │ │ │ └── ViewModelBase.cs │ │ ├── Demo.CustomOpenFolderDialog/ │ │ │ ├── App.axaml │ │ │ ├── App.axaml.cs │ │ │ ├── CustomDialogFactory.cs │ │ │ ├── Demo.CustomOpenFolderDialog.csproj │ │ │ ├── DialogFactoryExtensions.cs │ │ │ ├── MainWindow.axaml │ │ │ ├── MainWindow.axaml.cs │ │ │ ├── MainWindowViewModel.cs │ │ │ ├── Program.cs │ │ │ ├── ViewLocator.cs │ │ │ └── ViewModelBase.cs │ │ ├── Demo.DialogHost/ │ │ │ ├── App.axaml │ │ │ ├── App.axaml.cs │ │ │ ├── AskTextBoxView.axaml │ │ │ ├── AskTextBoxView.axaml.cs │ │ │ ├── AskTextBoxViewModel.cs │ │ │ ├── CurrentTimeView.axaml │ │ │ ├── CurrentTimeView.axaml.cs │ │ │ ├── CurrentTimeViewModel.cs │ │ │ ├── Demo.DialogHost.csproj │ │ │ ├── DialogServiceExtensions.cs │ │ │ ├── FodyWeavers.xml │ │ │ ├── FodyWeavers.xsd │ │ │ ├── MainView.axaml │ │ │ ├── MainView.axaml.cs │ │ │ ├── MainViewModel.cs │ │ │ ├── MessageView.axaml │ │ │ ├── MessageView.axaml.cs │ │ │ ├── Program.cs │ │ │ ├── ViewLocator.cs │ │ │ └── ViewModelBase.cs │ │ ├── Demo.FluentContentDialog/ │ │ │ ├── App.axaml │ │ │ ├── App.axaml.cs │ │ │ ├── AskTextBoxView.axaml │ │ │ ├── AskTextBoxView.axaml.cs │ │ │ ├── AskTextBoxViewModel.cs │ │ │ ├── CurrentTimeView.axaml │ │ │ ├── CurrentTimeView.axaml.cs │ │ │ ├── CurrentTimeViewModel.cs │ │ │ ├── Demo.FluentContentDialog.csproj │ │ │ ├── FodyWeavers.xml │ │ │ ├── FodyWeavers.xsd │ │ │ ├── MainView.axaml │ │ │ ├── MainView.axaml.cs │ │ │ ├── MainViewModel.cs │ │ │ ├── MessageView.axaml │ │ │ ├── MessageView.axaml.cs │ │ │ ├── Program.cs │ │ │ ├── ViewLocator.cs │ │ │ └── ViewModelBase.cs │ │ ├── Demo.FluentMessageBoxContentDialog/ │ │ │ ├── App.axaml │ │ │ ├── App.axaml.cs │ │ │ ├── Demo.FluentMessageBoxContentDialog.csproj │ │ │ ├── MainWindow.axaml │ │ │ ├── MainWindow.axaml.cs │ │ │ ├── MainWindowViewModel.cs │ │ │ ├── Program.cs │ │ │ ├── ViewLocator.cs │ │ │ └── ViewModelBase.cs │ │ ├── Demo.FluentMessageBoxTaskDialog/ │ │ │ ├── App.axaml │ │ │ ├── App.axaml.cs │ │ │ ├── Demo.FluentMessageBoxTaskDialog.csproj │ │ │ ├── MainWindow.axaml │ │ │ ├── MainWindow.axaml.cs │ │ │ ├── MainWindowViewModel.cs │ │ │ ├── Program.cs │ │ │ ├── ViewLocator.cs │ │ │ └── ViewModelBase.cs │ │ ├── Demo.FluentTaskDialog/ │ │ │ ├── App.axaml │ │ │ ├── App.axaml.cs │ │ │ ├── AskTextBoxView.axaml │ │ │ ├── AskTextBoxView.axaml.cs │ │ │ ├── AskTextBoxViewModel.cs │ │ │ ├── CurrentTimeView.axaml │ │ │ ├── CurrentTimeView.axaml.cs │ │ │ ├── CurrentTimeViewModel.cs │ │ │ ├── Demo.FluentTaskDialog.csproj │ │ │ ├── FodyWeavers.xml │ │ │ ├── FodyWeavers.xsd │ │ │ ├── MainView.axaml │ │ │ ├── MainView.axaml.cs │ │ │ ├── MainViewModel.cs │ │ │ ├── MessageView.axaml │ │ │ ├── MessageView.axaml.cs │ │ │ ├── Program.cs │ │ │ ├── ViewLocator.cs │ │ │ └── ViewModelBase.cs │ │ ├── Demo.Logging/ │ │ │ ├── AddTextDialog.axaml │ │ │ ├── AddTextDialog.axaml.cs │ │ │ ├── AddTextDialogViewModel.cs │ │ │ ├── App.axaml │ │ │ ├── App.axaml.cs │ │ │ ├── Demo.Logging.csproj │ │ │ ├── MainWindow.axaml │ │ │ ├── MainWindow.axaml.cs │ │ │ ├── MainWindowViewModel.cs │ │ │ ├── Program.cs │ │ │ ├── ViewLocator.cs │ │ │ └── ViewModelBase.cs │ │ ├── Demo.MessageBox/ │ │ │ ├── App.axaml │ │ │ ├── App.axaml.cs │ │ │ ├── Demo.MessageBox.csproj │ │ │ ├── MainWindow.axaml │ │ │ ├── MainWindow.axaml.cs │ │ │ ├── MainWindowViewModel.cs │ │ │ ├── Program.cs │ │ │ ├── ViewLocator.cs │ │ │ └── ViewModelBase.cs │ │ ├── Demo.ModalCustomDialog/ │ │ │ ├── AddTextCustomDialog.cs │ │ │ ├── AddTextCustomDialogViewModel.cs │ │ │ ├── AddTextDialog.axaml │ │ │ ├── AddTextDialog.axaml.cs │ │ │ ├── App.axaml │ │ │ ├── App.axaml.cs │ │ │ ├── Demo.ModalCustomDialog.csproj │ │ │ ├── MainWindow.axaml │ │ │ ├── MainWindow.axaml.cs │ │ │ ├── MainWindowViewModel.cs │ │ │ ├── Program.cs │ │ │ ├── ViewLocator.cs │ │ │ └── ViewModelBase.cs │ │ ├── Demo.ModalDialog/ │ │ │ ├── AddTextDialog.axaml │ │ │ ├── AddTextDialog.axaml.cs │ │ │ ├── AddTextDialogViewModel.cs │ │ │ ├── App.axaml │ │ │ ├── App.axaml.cs │ │ │ ├── Demo.ModalDialog.csproj │ │ │ ├── MainWindow.axaml │ │ │ ├── MainWindow.axaml.cs │ │ │ ├── MainWindowViewModel.cs │ │ │ ├── Program.cs │ │ │ ├── ViewLocator.cs │ │ │ └── ViewModelBase.cs │ │ ├── Demo.ModalDialog.Tests/ │ │ │ ├── Demo.ModalDialog.Tests.csproj │ │ │ └── MainWindowViewModelTests.cs │ │ ├── Demo.NonModalCustomDialog/ │ │ │ ├── App.axaml │ │ │ ├── App.axaml.cs │ │ │ ├── CurrentTimeCustomDialog.cs │ │ │ ├── CurrentTimeCustomDialogViewModel.cs │ │ │ ├── CurrentTimeDialog.axaml │ │ │ ├── CurrentTimeDialog.axaml.cs │ │ │ ├── Demo.NonModalCustomDialog.csproj │ │ │ ├── MainWindow.axaml │ │ │ ├── MainWindow.axaml.cs │ │ │ ├── MainWindowViewModel.cs │ │ │ ├── Program.cs │ │ │ ├── ViewLocator.cs │ │ │ └── ViewModelBase.cs │ │ ├── Demo.NonModalDialog/ │ │ │ ├── App.axaml │ │ │ ├── App.axaml.cs │ │ │ ├── CurrentTimeDialog.axaml │ │ │ ├── CurrentTimeDialog.axaml.cs │ │ │ ├── CurrentTimeDialogViewModel.cs │ │ │ ├── Demo.NonModalDialog.csproj │ │ │ ├── MainWindow.axaml │ │ │ ├── MainWindow.axaml.cs │ │ │ ├── MainWindowViewModel.cs │ │ │ ├── Program.cs │ │ │ ├── ViewLocator.cs │ │ │ └── ViewModelBase.cs │ │ ├── Demo.OpenFileDialog/ │ │ │ ├── App.axaml │ │ │ ├── App.axaml.cs │ │ │ ├── Demo.OpenFileDialog.csproj │ │ │ ├── MainWindow.axaml │ │ │ ├── MainWindow.axaml.cs │ │ │ ├── MainWindowViewModel.cs │ │ │ ├── Program.cs │ │ │ ├── ViewLocator.cs │ │ │ └── ViewModelBase.cs │ │ ├── Demo.OpenFolderDialog/ │ │ │ ├── App.axaml │ │ │ ├── App.axaml.cs │ │ │ ├── Demo.OpenFolderDialog.csproj │ │ │ ├── MainWindow.axaml │ │ │ ├── MainWindow.axaml.cs │ │ │ ├── MainWindowViewModel.cs │ │ │ ├── Program.cs │ │ │ ├── ViewLocator.cs │ │ │ └── ViewModelBase.cs │ │ ├── Demo.SaveFileDialog/ │ │ │ ├── App.axaml │ │ │ ├── App.axaml.cs │ │ │ ├── Demo.SaveFileDialog.csproj │ │ │ ├── MainWindow.axaml │ │ │ ├── MainWindow.axaml.cs │ │ │ ├── MainWindowViewModel.cs │ │ │ ├── Program.cs │ │ │ ├── ViewLocator.cs │ │ │ └── ViewModelBase.cs │ │ ├── Demo.StrongLocator/ │ │ │ ├── AddTextDialog.axaml │ │ │ ├── AddTextDialog.axaml.cs │ │ │ ├── AddTextDialogViewModel.cs │ │ │ ├── App.axaml │ │ │ ├── App.axaml.cs │ │ │ ├── Demo.StrongLocator.csproj │ │ │ ├── MainWindow.axaml │ │ │ ├── MainWindow.axaml.cs │ │ │ ├── MainWindowViewModel.cs │ │ │ ├── Program.cs │ │ │ ├── ViewLocator.cs │ │ │ └── ViewModelBase.cs │ │ └── Demo.ViewEvents/ │ │ ├── App.axaml │ │ ├── App.axaml.cs │ │ ├── Demo.ViewEvents.csproj │ │ ├── MainWindow.axaml │ │ ├── MainWindow.axaml.cs │ │ ├── MainWindowViewModel.cs │ │ ├── Program.cs │ │ ├── ViewLocator.cs │ │ └── ViewModelBase.cs │ ├── Directory.Build.props │ └── Wpf/ │ ├── Demo.ActivateNonModalDialog/ │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── ApplicationResources.xaml │ │ ├── CurrentTimeDialog.xaml │ │ ├── CurrentTimeDialog.xaml.cs │ │ ├── CurrentTimeDialogViewModel.cs │ │ ├── Demo.ActivateNonModalDialog.csproj │ │ ├── MainWindow.xaml │ │ ├── MainWindow.xaml.cs │ │ ├── MainWindowViewModel.cs │ │ ├── ViewLocator.cs │ │ └── ViewModelLocator.cs │ ├── Demo.CloseNonModalDialog/ │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── ApplicationResources.xaml │ │ ├── CurrentTimeDialog.xaml │ │ ├── CurrentTimeDialog.xaml.cs │ │ ├── CurrentTimeDialogViewModel.cs │ │ ├── Demo.CloseNonModalDialog.csproj │ │ ├── MainWindow.xaml │ │ ├── MainWindow.xaml.cs │ │ ├── MainWindowViewModel.cs │ │ ├── ViewLocator.cs │ │ └── ViewModelLocator.cs │ ├── Demo.CustomOpenFolderDialog/ │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── ApplicationResources.xaml │ │ ├── CustomDialogFactory.cs │ │ ├── Demo.CustomOpenFolderDialog.csproj │ │ ├── DialogFactoryExtensions.cs │ │ ├── MainWindow.xaml │ │ ├── MainWindow.xaml.cs │ │ ├── MainWindowViewModel.cs │ │ ├── ViewLocator.cs │ │ └── ViewModelLocator.cs │ ├── Demo.MessageBox/ │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── ApplicationResources.xaml │ │ ├── Demo.MessageBox.csproj │ │ ├── MainWindow.xaml │ │ ├── MainWindow.xaml.cs │ │ ├── MainWindowViewModel.cs │ │ ├── ViewLocator.cs │ │ └── ViewModelLocator.cs │ ├── Demo.ModalCustomDialog/ │ │ ├── AddTextCustomDialog.cs │ │ ├── AddTextCustomDialogViewModel.cs │ │ ├── AddTextDialog.xaml │ │ ├── AddTextDialog.xaml.cs │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── ApplicationResources.xaml │ │ ├── Demo.ModalCustomDialog.csproj │ │ ├── MainWindow.xaml │ │ ├── MainWindow.xaml.cs │ │ ├── MainWindowViewModel.cs │ │ ├── ViewLocator.cs │ │ └── ViewModelLocator.cs │ ├── Demo.ModalDialog/ │ │ ├── AddTextDialog.xaml │ │ ├── AddTextDialog.xaml.cs │ │ ├── AddTextDialogViewModel.cs │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── ApplicationResources.xaml │ │ ├── Demo.ModalDialog.csproj │ │ ├── MainWindow.xaml │ │ ├── MainWindow.xaml.cs │ │ ├── MainWindowViewModel.cs │ │ ├── ViewLocator.cs │ │ └── ViewModelLocator.cs │ ├── Demo.ModalDialog.Tests/ │ │ ├── Demo.ModalDialog.Tests.csproj │ │ └── MainWindowViewModelTests.cs │ ├── Demo.NonModalCustomDialog/ │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── ApplicationResources.xaml │ │ ├── CurrentTimeCustomDialog.cs │ │ ├── CurrentTimeCustomDialogViewModel.cs │ │ ├── CurrentTimeDialog.xaml │ │ ├── CurrentTimeDialog.xaml.cs │ │ ├── Demo.NonModalCustomDialog.csproj │ │ ├── MainWindow.xaml │ │ ├── MainWindow.xaml.cs │ │ ├── MainWindowViewModel.cs │ │ ├── ViewLocator.cs │ │ └── ViewModelLocator.cs │ ├── Demo.NonModalDialog/ │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── ApplicationResources.xaml │ │ ├── CurrentTimeDialog.xaml │ │ ├── CurrentTimeDialog.xaml.cs │ │ ├── CurrentTimeDialogViewModel.cs │ │ ├── Demo.NonModalDialog.csproj │ │ ├── MainWindow.xaml │ │ ├── MainWindow.xaml.cs │ │ ├── MainWindowViewModel.cs │ │ ├── ViewLocator.cs │ │ └── ViewModelLocator.cs │ ├── Demo.OpenFileDialog/ │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── ApplicationResources.xaml │ │ ├── Demo.OpenFileDialog.csproj │ │ ├── MainWindow.xaml │ │ ├── MainWindow.xaml.cs │ │ ├── MainWindowViewModel.cs │ │ ├── OpenMe.txt │ │ ├── ViewLocator.cs │ │ └── ViewModelLocator.cs │ ├── Demo.OpenFolderDialog/ │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── ApplicationResources.xaml │ │ ├── Demo.OpenFolderDialog.csproj │ │ ├── MainWindow.xaml │ │ ├── MainWindow.xaml.cs │ │ ├── MainWindowViewModel.cs │ │ ├── ViewLocator.cs │ │ └── ViewModelLocator.cs │ ├── Demo.SaveFileDialog/ │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── ApplicationResources.xaml │ │ ├── Demo.SaveFileDialog.csproj │ │ ├── MainWindow.xaml │ │ ├── MainWindow.xaml.cs │ │ ├── MainWindowViewModel.cs │ │ ├── ViewLocator.cs │ │ └── ViewModelLocator.cs │ ├── Demo.StrongLocator/ │ │ ├── AddTextDialog.xaml │ │ ├── AddTextDialog.xaml.cs │ │ ├── AddTextDialogViewModel.cs │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── ApplicationResources.xaml │ │ ├── Demo.StrongLocator.csproj │ │ ├── MainWindow.xaml │ │ ├── MainWindow.xaml.cs │ │ ├── MainWindowViewModel.cs │ │ ├── ViewLocator.cs │ │ └── ViewModelLocator.cs │ ├── Demo.ViewEvents/ │ │ ├── App.xaml │ │ ├── App.xaml.cs │ │ ├── ApplicationResources.xaml │ │ ├── Demo.ViewEvents.csproj │ │ ├── MainWindow.xaml │ │ ├── MainWindow.xaml.cs │ │ ├── MainWindowViewModel.cs │ │ ├── ViewLocator.cs │ │ └── ViewModelLocator.cs │ └── TestBaseClasses/ │ ├── Features/ │ │ └── FeatureSteps.cs │ └── TestBaseClasses.csproj └── src/ ├── Directory.Build.props ├── MvvmDialogs/ │ ├── DialogManagerBase.cs │ ├── DialogNotFoundException.cs │ ├── DialogServiceBase.cs │ ├── DialogServiceExtensions.cs │ ├── DialogSettingsBase.cs │ ├── FileSystem/ │ │ ├── DesktopDialogStorageFactory.cs │ │ ├── DesktopDialogStorageFile.cs │ │ ├── DesktopDialogStorageFolder.cs │ │ ├── DesktopDialogStorageItem.cs │ │ ├── DesktopDialogStorageItemProperties.cs │ │ ├── IDesktopDialogStorageFactory.cs │ │ ├── IDialogStorageFile.cs │ │ ├── IDialogStorageFolder.cs │ │ └── IDialogStorageItem.cs │ ├── FrameworkDialogs/ │ │ ├── FileDialogSettings.cs │ │ ├── FileFilter.cs │ │ ├── MessageBoxButton.cs │ │ ├── MessageBoxImage.cs │ │ ├── MessageBoxSettings.cs │ │ ├── OpenFileDialogSettings.cs │ │ ├── OpenFolderDialogSettings.cs │ │ ├── PickerDialogSettings.cs │ │ └── SaveFileDialogSettings.cs │ ├── IActivable.cs │ ├── ICloseable.cs │ ├── IDialogFactory.cs │ ├── IDialogManager.cs │ ├── IDialogService.cs │ ├── IModalDialogViewModel.cs │ ├── IView.cs │ ├── IViewClosed.cs │ ├── IViewClosing.cs │ ├── IViewLoaded.cs │ ├── IViewLocator.cs │ ├── MvvmDialogs.csproj │ ├── MvvmDialogs.csproj.DotSettings │ ├── Private/ │ │ ├── NullableAttributes.cs │ │ └── ViewIdGenerator.cs │ ├── StrongViewLocatorBase.cs │ ├── Usings.cs │ ├── ViewBase.cs │ ├── ViewDefinition.cs │ └── ViewNotRegisteredException.cs ├── MvvmDialogs.Avalonia/ │ ├── Api/ │ │ ├── FrameworkDialogsApi.cs │ │ └── IFrameworkDialogsApi.cs │ ├── DialogFactory.cs │ ├── DialogFactoryBase.cs │ ├── DialogManager.cs │ ├── DialogService.cs │ ├── FileSystem/ │ │ ├── AvaloniaDialogStorageFile.cs │ │ ├── AvaloniaDialogStorageFolder.cs │ │ ├── AvaloniaDialogStorageItem.cs │ │ └── StorageExtensions.cs │ ├── IViewLocatorNavigation.cs │ ├── MvvmDialogs.Avalonia.csproj │ ├── MvvmDialogs.Avalonia.csproj.DotSettings │ ├── Navigation/ │ │ ├── CancellableActions.cs │ │ ├── DialogTask.cs │ │ ├── INavigationManager.cs │ │ ├── NavigationManager.cs │ │ ├── NavigationRoot.axaml │ │ ├── NavigationRoot.axaml.cs │ │ ├── NavigationRootWindow.axaml │ │ ├── NavigationRootWindow.axaml.cs │ │ ├── ViewCache.cs │ │ ├── ViewCacheItem.cs │ │ └── ViewNavigationWrapper.cs │ ├── Private/ │ │ └── NullableAttributes.cs │ ├── StrongViewLocator.cs │ ├── UiExtensions.cs │ ├── Usings.cs │ ├── ViewClosingHandler.cs │ ├── ViewLocatorBase.cs │ └── ViewWrapper.cs ├── MvvmDialogs.Avalonia.DialogHost/ │ ├── DialogFactoryExtensions.cs │ ├── DialogHostDialogFactory.cs │ ├── DialogHostSettings.cs │ ├── DialogHostView.cs │ ├── DialogServiceExtensions.cs │ ├── MvvmDialogs.Avalonia.DialogHost.csproj │ └── Usings.cs ├── MvvmDialogs.Avalonia.Fluent/ │ ├── ContentDialogSettings.cs │ ├── DialogFactoryExtensions.cs │ ├── DialogServiceExtensions.cs │ ├── FluentApi.cs │ ├── FluentContentView.cs │ ├── FluentDialogFactory.cs │ ├── FluentMessageBoxType.cs │ ├── FluentTaskView.cs │ ├── MvvmDialogs.Avalonia.Fluent.csproj │ ├── TaskDialogSettings.cs │ └── Usings.cs ├── MvvmDialogs.Avalonia.MessageBox/ │ ├── DialogFactoryExtensions.cs │ ├── IMessageBoxApi.cs │ ├── MessageBoxApi.cs │ ├── MessageBoxApiSettings.cs │ ├── MessageBoxDialogFactory.cs │ ├── MessageBoxMode.cs │ ├── MvvmDialogs.Avalonia.MessageBox.csproj │ └── Usings.cs ├── MvvmDialogs.Avalonia.Tests/ │ ├── MvvmDialogs.Avalonia.Tests.csproj │ ├── NavigationTests.cs │ ├── TestsBase.cs │ ├── Usings.cs │ ├── ViewNavigationWrapperTests.cs │ └── Views/ │ ├── FirstView.axaml │ ├── FirstView.axaml.cs │ ├── FirstViewModel.cs │ ├── FirstWindow.axaml │ ├── FirstWindow.axaml.cs │ ├── SecondView.axaml │ ├── SecondView.axaml.cs │ ├── SecondViewModel.cs │ ├── SecondWindow.axaml │ ├── SecondWindow.axaml.cs │ ├── ThirdView.axaml │ ├── ThirdView.axaml.cs │ ├── ThirdViewModel.cs │ ├── ThirdWindow.axaml │ └── ThirdWindow.axaml.cs ├── MvvmDialogs.Wpf/ │ ├── Api/ │ │ ├── FileApiSettings.cs │ │ ├── FrameworkDialogsApi.cs │ │ ├── IFrameworkDialogsApi.cs │ │ ├── MessageBoxApiSettings.cs │ │ ├── OpenFileApiSettings.cs │ │ ├── OpenFolderApiSettings.cs │ │ └── SaveFileApiSettings.cs │ ├── DialogFactory.cs │ ├── DialogFactoryBase.cs │ ├── DialogManager.cs │ ├── DialogService.cs │ ├── DialogServiceExtensions.cs │ ├── GlobalUsings.cs │ ├── IDialogFactorySync.cs │ ├── IDialogManagerSync.cs │ ├── IDialogServiceSync.cs │ ├── IWindowSync.cs │ ├── MvvmDialogs.Wpf.csproj │ ├── Runtime/ │ │ └── NullableAttributes.cs │ ├── StrongViewLocator.cs │ ├── UiExtensions.cs │ ├── ViewLocatorBase.cs │ ├── ViewWrapper.cs │ └── Win32Window.cs ├── StrongName.snk └── public.key ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ # EditorConfig is awesome: https://EditorConfig.org # top-most EditorConfig file root = true dotnet_code_quality.CA1062.null_check_validation_methods = CheckNotNull|CheckNotNullOrEmpty # Don't use tabs for indentation. [*] indent_style = space # (Please don't specify an indent_size here; that has too many unintended consequences.) # Code files [*.{cs,csx,vb,vbx}] indent_size = 4 insert_final_newline = true charset = utf-8-bom # XML project files [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] indent_size = 2 # XML config files [*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] indent_size = 2 # JSON files [*.json] indent_size = 2 # Powershell files [*.ps1] indent_size = 2 # Shell script files [*.sh] end_of_line = lf indent_size = 2 # Dotnet code style settings: [*.{cs,vb}] # IDE0055: Fix formatting dotnet_diagnostic.IDE0055.severity = warning # Sort using and Import directives with System.* appearing first dotnet_sort_system_directives_first = true dotnet_separate_import_directive_groups = false # Avoid "this." and "Me." if not necessary dotnet_style_qualification_for_field = false:refactoring dotnet_style_qualification_for_property = false:refactoring dotnet_style_qualification_for_method = false:refactoring dotnet_style_qualification_for_event = false:refactoring # Use language keywords instead of framework type names for type references dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion dotnet_style_predefined_type_for_member_access = true:suggestion # Suggest more modern language features when available dotnet_style_object_initializer = true:suggestion dotnet_style_collection_initializer = true:suggestion dotnet_style_coalesce_expression = true:suggestion dotnet_style_null_propagation = true:suggestion dotnet_style_explicit_tuple_names = true:suggestion # Non-private static fields are PascalCase dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.severity = suggestion dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non_private_static_fields dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected dotnet_naming_symbols.non_private_static_fields.required_modifiers = static dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case # Non-private readonly fields are PascalCase dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.severity = suggestion dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.symbols = non_private_readonly_fields dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.style = non_private_readonly_field_style dotnet_naming_symbols.non_private_readonly_fields.applicable_kinds = field dotnet_naming_symbols.non_private_readonly_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected dotnet_naming_symbols.non_private_readonly_fields.required_modifiers = readonly dotnet_naming_style.non_private_readonly_field_style.capitalization = pascal_case # Constants are PascalCase dotnet_naming_rule.constants_should_be_pascal_case.severity = suggestion dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants dotnet_naming_rule.constants_should_be_pascal_case.style = constant_style dotnet_naming_symbols.constants.applicable_kinds = field, local dotnet_naming_symbols.constants.required_modifiers = const dotnet_naming_style.constant_style.capitalization = pascal_case # Static fields are camelCase and start with s_ dotnet_naming_rule.static_fields_should_be_camel_case.severity = suggestion dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields dotnet_naming_rule.static_fields_should_be_camel_case.style = static_field_style dotnet_naming_symbols.static_fields.applicable_kinds = field dotnet_naming_symbols.static_fields.required_modifiers = static dotnet_naming_style.static_field_style.capitalization = camel_case dotnet_naming_style.static_field_style.required_prefix = s_ # Instance fields are camelCase and start with _ dotnet_naming_rule.instance_fields_should_be_camel_case.severity = suggestion dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style dotnet_naming_symbols.instance_fields.applicable_kinds = field dotnet_naming_style.instance_field_style.capitalization = camel_case dotnet_naming_style.instance_field_style.required_prefix = _ # Locals and parameters are camelCase dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local dotnet_naming_style.camel_case_style.capitalization = camel_case # Local functions are PascalCase dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style dotnet_naming_symbols.local_functions.applicable_kinds = local_function dotnet_naming_style.local_function_style.capitalization = pascal_case # By default, name items with PascalCase dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style dotnet_naming_symbols.all_members.applicable_kinds = * dotnet_naming_style.pascal_case_style.capitalization = pascal_case # error RS2008: Enable analyzer release tracking for the analyzer project containing rule '{0}' dotnet_diagnostic.RS2008.severity = none # CSharp code style settings: [*.cs] # Newline settings csharp_new_line_before_open_brace = all csharp_new_line_before_else = true csharp_new_line_before_catch = true csharp_new_line_before_finally = true csharp_new_line_before_members_in_object_initializers = true csharp_new_line_before_members_in_anonymous_types = true csharp_new_line_between_query_expression_clauses = true # Indentation preferences csharp_indent_block_contents = true csharp_indent_braces = false csharp_indent_case_contents = true csharp_indent_case_contents_when_block = true csharp_indent_switch_labels = true csharp_indent_labels = flush_left # Prefer "var" everywhere csharp_style_var_for_built_in_types = true:suggestion csharp_style_var_when_type_is_apparent = true:suggestion csharp_style_var_elsewhere = true:suggestion # Prefer method-like constructs to have a block body csharp_style_expression_bodied_methods = false:none csharp_style_expression_bodied_constructors = false:none csharp_style_expression_bodied_operators = false:none # Prefer property-like constructs to have an expression-body csharp_style_expression_bodied_properties = true:none csharp_style_expression_bodied_indexers = true:none csharp_style_expression_bodied_accessors = true:none # Suggest more modern language features when available csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion csharp_style_pattern_matching_over_as_with_null_check = true:suggestion csharp_style_inlined_variable_declaration = true:suggestion csharp_style_throw_expression = true:suggestion csharp_style_conditional_delegate_call = true:suggestion # Space preferences csharp_space_after_cast = false csharp_space_after_colon_in_inheritance_clause = true csharp_space_after_comma = true csharp_space_after_dot = false csharp_space_after_keywords_in_control_flow_statements = true csharp_space_after_semicolon_in_for_statement = true csharp_space_around_binary_operators = before_and_after csharp_space_around_declaration_statements = do_not_ignore csharp_space_before_colon_in_inheritance_clause = true csharp_space_before_comma = false csharp_space_before_dot = false csharp_space_before_open_square_brackets = false csharp_space_before_semicolon_in_for_statement = false csharp_space_between_empty_square_brackets = false csharp_space_between_method_call_empty_parameter_list_parentheses = false csharp_space_between_method_call_name_and_opening_parenthesis = false csharp_space_between_method_call_parameter_list_parentheses = false csharp_space_between_method_declaration_empty_parameter_list_parentheses = false csharp_space_between_method_declaration_name_and_open_parenthesis = false csharp_space_between_method_declaration_parameter_list_parentheses = false csharp_space_between_parentheses = false csharp_space_between_square_brackets = false # Blocks are allowed csharp_prefer_braces = true:silent csharp_preserve_single_line_blocks = true csharp_preserve_single_line_statements = true # warning RS0037: PublicAPI.txt is missing '#nullable enable' dotnet_diagnostic.RS0037.severity = none [src/CodeStyle/**.{cs,vb}] # warning RS0005: Do not use generic CodeAction.Create to create CodeAction dotnet_diagnostic.RS0005.severity = none [src/{Analyzers,CodeStyle,Features,Workspaces}/**/*.{cs,vb}] # IDE0005: Remove unnecessary usings/imports dotnet_diagnostic.IDE0005.severity = warning ================================================ FILE: .gitattributes ================================================ # Auto detect text files and perform LF normalization * text=auto ================================================ 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 # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ bld/ [Bb]in/ [Oo]bj/ # Cache/options directory for Visual Studio, Visual Studio Code and JetBrains Rider .vs/ .vscode/ .idea/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # ASP.NET 5 project.lock.json artifacts/ # NuGet Packages *.nupkg *.snupkg **/packages/* # ReSharper src/_ReSharper.Caches/ # Cake build/tools/* # GhostDoc *.GhostDoc.xml ================================================ FILE: CHANGELOG.md ================================================ # Change Log All notable changes to this project will be documented in this file. ## 2.2 - 2026-03-05 - Updated all dependencies - Now compile for .NET 8, .NET 10 and .NET Standard 2.0 - Enhanced package management in source code - Updated demo projects to work with updated libraries ## 2.1 - 2023-12-30 This version introduces some breaking changes. - StrongViewLocator must now have its registrations in its constructor. [See updated documentation.](https://github.com/mysteryx93/HanumanInstitute.MvvmDialogs?tab=readme-ov-file#strongviewlocator). This change was required because 2 separate instances are created: one for `MvvmDialogs` and one for `Avalonia` defined in `App.axaml`. - Now apply picker `SuggestedStartLocation` and `SuggestedFileName`. The property names and types have been modified. - Complete overhaul and simplification of `FileSystem` classes. `IPathInfoFactory` and `IBookmarkFileSystem` have been removed. [See new documentation here.](https://github.com/mysteryx93/HanumanInstitute.MvvmDialogs?tab=readme-ov-file#cross-platform-file-access) `DialogStorageFile` got renamed to `DesktopDialogStorageFile` and `DesktopDialogStorageFactory` is available. Other changes: - Dialog show calls will now be ignored in design mode to avoid errors - Updated `CrossPlatform.Browser` to run - ViewLocatorBase now calls `CreateViewInstance` virtual method instead of `Activator.CreateInstance` for easier customization. Happy New Year!! May 2024 be the best year in a while ## 2.0 - 2023-06-14 - Updated for Avalonia v11.0.0 - Changed license to MIT - Removed AppSettings. Design was clumsy, and when it's actually needed, it doesn't work well with the modular design. - AllowConcurrentDialogs option has been moved to the DialogManager - Other options (in WPF) have been moved to the DialogFactory - Avalonia.MessageBox: added an option to display message boxes as windows or popups. Option is available when configuring the DialogFactory: new DialogFactory().AddMessageBox(MessageBoxMode.Popup) ## 2.0-rc1 - 2023-06-10 - ViewModel event handling is now supported for ViewModels shown in DialogHost, FluentContentDialog and FluentTaskDialog - DialogHost now supports mobile back button - DialogHost can now display any type of content: ViewModel, Control, or direct content. Renamed ContentViewModel property to Content. - Avalonia now targets .Net Standard 2.0 - Target Avalonia UI v2.0-rc1.1 ## 2.0-preview7 - 2023-03-18 - Automatically set MainWindow in Avalonia when showing the first window ## 2.0-preview6 - 2023-03-06 - Async close confirmation now works properly with mobile navigation - Added an application setting: AllowConcurrentDialogs. When False (default), it will wait for the previous dialog to close before showing the next one. If you call 3 message boxes at the same time, it will show the message boxes one after the other instead of 3 on top of each other. - Added support for DialogHost.Avalonia popup views. - Added support for Aura.UI message boxes for MvvmDialogs v1.4.1 as Aura.UI does not yet support Avalonia11. ## 2.0-preview5 - 2023-03-02 StrongViewLocator to register ViewModel-View combinations in a strongly-typed way to avoid the use of reflection. Useful if you want to use Assembly Trimming! Works for both desktop and mobile and selects the View accordingly. Sample ViewLocator registration: ``` locator = new StrongViewLocator() { ForceSinglePageNavigation = false } .Register() .Register() .Register(); build.RegisterLazySingleton(() => (IDialogService)new DialogService( new DialogManager(viewLocator: locator), viewModelFactory: x => Locator.Current.GetService(x))); ``` It could be done even better. This StaticViewLocatorGenerator (usage here) could be adapted to be more generic and serve for our needs. It would use a Source Generator to generate ViewModel-View mapping at compile-time using naming standards and removing the need for reflection. If someone has experience with Source Generators, contribution is welcomed! ## 2.0-preview4 - 2023-02-22 - Fixed file dialogs filters that were broken - Removed dependency on Reactive ## 2.0-preview3 - 2023-02-16 It now supports 'magic' mobile navigation on Android and iOS using the exact same API, allowing to convert MVVM desktop apps into mobile with very little efforts. Mobile back navigation is also automatically supported. Documentation has been updated. Supporting mobile navigation required extensive internal structural changes which resulted in very little changes to the API. I believe that these are the only minor breaking changes - The default ViewLocator now replaces ViewModel with Window on desktop and View on mobile. If you want the old standard of only replacing with View, you can easily create your ViewLocator with a single line to replace ViewModel with View. - File/folder dialogs now return IDialogStorageFile and IDialogStorageFolder instead of string. To get the same path string you had before (on desktop), simply add .LocalPath. Known limitations: - Mobile views are held in a weak cache, and non-visible views should be released from memory when memory is needed. The unit test to ensure this happens does not currently pass. Contribution is welcomed to find the problem. - Closing async cancellation does not yet work with mobile navigation ## 1.4.1 - 2022-09-03 - Renamed the new ViewLoaded/ViewClosing/ViewClosed methods to OnLoaded/OnClosing/OnClosed. Interface names remain the same. - Fixed a crash with FluentAvalonia TaskDialog when pressing escape. - When owner is null, it will now use the main window, or create a dummy window. ## 1.4.0 - 2022-08-29 Handling Loading, Closing and Closed events presents a few annoyances. Loading is a common business concern. Why would you have to write code in your View for it? Closing is generally used to display a confirmation before exit. Calling async code from the Closing event would require complex code, both in the ViewModel and the View. Closed cannot even call a command via an XAML behavior! As a simple solution, you can implement IViewLoaded, IViewClosing and/or IViewClosed from your ViewModel with no code required in your View. - IViewLoaded, IViewClosing and IViewClosed interfaces have been added. See documentation. - Owner parameters are now optional, it's up to the implementation as to whether or not it is supported - IWindow has been renamed to IView - Fixed a bug with Fluent TaskMessageBox ## 1.3.1 - 2022-07-01 - File dialog filters can now take extensions with or without the dot - FluentAvalonia TaskDialog now supports default buttons - Open/save file framework dialog settings are now more consistent in Avalonia and WPF ## 1.3.0 - 2022-06-16 - Calls will only be dispatched if not already on UI thread - Redesigned FrameworkDialogFactory to be simpler and more modular - MessageBox for Avalonia is now split into a separate assembly `HanumanInstitute.MvvmDialogs.Avalonia.MessageBox`, since Avalonia doesn't have built-in support for message boxes - `MvvmDialogs.Avalonia`, removed reference to MessageBox.Avalonia - Added preliminary support for FluentAvalonia `HanumanInstitute.MvvmDialogs.Avalonia.Fluent` TODO: - Support icons with Fluent MessageBox TaskDialogs - Support more complex usage of Fluent dialogs ## 1.2.3 - 2022-06-07 - Fixed an issue with thread-safety ## 1.2.2 - 2022-06-07 - DialogManager is now thread-safe, dispatching UI calls to the UI thread - Added optional `dispatcher` parameter to DialogManager ## 1.2.1 - 2022-05-29 Made the library more friendly for unit tests. One area that caused trouble is the creation of the dialog view model `new MyDialogViewModel()`. If it has dependencies, you might use `Locator.MyDialogViewModel`, but then that's not unit-test friendly. As a solution, you will now create the view model using `IDialogService.CreateViewModel`. It will call a ViewModelFactory function set in the DialogService constructor. - Added `viewModelFactory` parameter to DialogService constructor - Moved `viewLocator` constructor parameter from DialogService to DialogManager - Updated all demos to use correct constructor parameters - Updated all demos to use `IDialogService.CreateViewModel` - Added unit test sample project: `Demo.ModalDialog.Tests` ## 1.2.0 - 2022-05-28 - Logging is now done using standard `ILogger` interface. See doc - Revamped the whole logging mechanisms - All demos now output logs to the Debug window - Added `IWindow.RefObj`, which can be implemented like this for custom dialogs: `public object RefObj => this;` - `IDialogManager.ShowFrameworkDialogAsync` now takes an extra optional parameter `resultToString` to convert the result to string for logging. If null, it uses `object.ToString()`. - Bug fix: `WPF.DialogService.ShowDialog` (sync method) was not working ## 1.1.0 - 2022-05-26 BREAKING CHANGES - XAML registration is no longer required and must be removed If your convention is different than simply replacing 'ViewModel' with 'View': - You must add a ViewLocator to your project (see doc) - You must pass this ViewLocator to the DialogService constructor Adopting Avalonia's ViewLocator design greatly simplifies the code and avoids duplicating the design. - Internally, the following classes have been removed: `DialogTypeLocatorBase, DialogTypeLocatorCache, IDialogFactory, NamingConventionDialogTypeLocator, ReflectionDialogFactoryBase, ViewRegistration, DialogServiceViews, ReflectionDialogFactory` - Renamed `IDialogTypeLocator` to `IViewLocator` - Removed namespace `HanumanInstitute.MvvmDialogs.DialogTypeLocators` `MvvmDialogs.Avalonia` is no longer signed because dependency `ReactiveUI` is not signed. ## 1.0.0 - 2022-05-07 Fork from FantasticFiasco/mvvm-dialogs ### What's new: - Support for Avalonia and WPF - The core is now platform-agnostic ### TODO: - UWP support - Blazor support - WinUI support - Improving tests ================================================ FILE: Directory.Packages.props ================================================ true ================================================ FILE: LICENSE.md ================================================ MIT License Copyright (c) 2018-2022 Etienne Charland 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: MvvmDialogs.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 18 VisualStudioVersion = 18.3.11520.95 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{958591BB-32C1-48C4-B5FA-11A2C5686814}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{62592C78-61AA-44B4-A7C3-EAC678A568A2}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Wpf", "Wpf", "{0A8EF671-0277-4F7A-B03D-C6E227020E86}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.ActivateNonModalDialog", "samples\Wpf\Demo.ActivateNonModalDialog\Demo.ActivateNonModalDialog.csproj", "{ED5001B1-A78B-4881-9BD8-CB56DD930585}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.MessageBox", "samples\Wpf\Demo.MessageBox\Demo.MessageBox.csproj", "{A6ABFE78-566C-4534-947E-BEFB86BDA347}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.ModalCustomDialog", "samples\Wpf\Demo.ModalCustomDialog\Demo.ModalCustomDialog.csproj", "{AD1F57E0-055A-4838-91AD-B824BF17E481}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.ModalDialog", "samples\Wpf\Demo.ModalDialog\Demo.ModalDialog.csproj", "{F2CAA958-5A0E-4BB3-B624-B8360C5F2978}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.NonModalCustomDialog", "samples\Wpf\Demo.NonModalCustomDialog\Demo.NonModalCustomDialog.csproj", "{DD760082-E0FA-433F-A1D0-D05F5D91FFA9}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.NonModalDialog", "samples\Wpf\Demo.NonModalDialog\Demo.NonModalDialog.csproj", "{74041466-C4C6-4396-8B57-D176CF5C0FD9}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.OpenFileDialog", "samples\Wpf\Demo.OpenFileDialog\Demo.OpenFileDialog.csproj", "{33BC9402-331E-47B5-8EE8-4F15AF463D12}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.SaveFileDialog", "samples\Wpf\Demo.SaveFileDialog\Demo.SaveFileDialog.csproj", "{62E90DFE-FF71-4558-A33E-361BFE60BF9D}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.CloseNonModalDialog", "samples\Wpf\Demo.CloseNonModalDialog\Demo.CloseNonModalDialog.csproj", "{CABB5675-02EF-42A7-A2C9-E4F37D66D12B}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MvvmDialogs.Avalonia", "src\MvvmDialogs.Avalonia\MvvmDialogs.Avalonia.csproj", "{0848A1AE-3147-432C-B473-44EE2CBA2E57}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MvvmDialogs", "src\MvvmDialogs\MvvmDialogs.csproj", "{E14F830F-2A00-46D0-B25B-B3D675E86B02}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MvvmDialogs.Wpf", "src\MvvmDialogs.Wpf\MvvmDialogs.Wpf.csproj", "{32D9C89C-9D88-40F9-A05D-CD95F05F38D0}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Avalonia", "Avalonia", "{0CAFC532-721B-4CD0-B4CA-AF10F07BFD76}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.CloseNonModalDialog", "samples\Avalonia\Demo.CloseNonModalDialog\Demo.CloseNonModalDialog.csproj", "{26E80F33-67D7-4F29-87E4-DFA45FBCF6B3}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.MessageBox", "samples\Avalonia\Demo.MessageBox\Demo.MessageBox.csproj", "{ADB64CA1-52F9-47B9-AC03-975D2C9E4022}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.ModalCustomDialog", "samples\Avalonia\Demo.ModalCustomDialog\Demo.ModalCustomDialog.csproj", "{89BFF856-E543-4EB5-B443-78B30D818D57}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.ModalDialog", "samples\Avalonia\Demo.ModalDialog\Demo.ModalDialog.csproj", "{4D578475-512F-43C5-9AF4-F8A8578732CE}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.NonModalCustomDialog", "samples\Avalonia\Demo.NonModalCustomDialog\Demo.NonModalCustomDialog.csproj", "{61F454B7-9F32-4CBA-8FE5-02B44D5CF25C}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.NonModalDialog", "samples\Avalonia\Demo.NonModalDialog\Demo.NonModalDialog.csproj", "{1E02BE6D-9F98-4343-930C-588CCB9A1296}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.OpenFileDialog", "samples\Avalonia\Demo.OpenFileDialog\Demo.OpenFileDialog.csproj", "{3D4F7533-B6B3-4F96-8794-F80A96EAB34E}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.SaveFileDialog", "samples\Avalonia\Demo.SaveFileDialog\Demo.SaveFileDialog.csproj", "{CC35BEDB-96DB-452C-BDDB-3D90169F8313}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.OpenFolderDialog", "samples\Wpf\Demo.OpenFolderDialog\Demo.OpenFolderDialog.csproj", "{27684F10-FC43-4868-80B3-9D1840E4CF54}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.CustomOpenFolderDialog", "samples\Wpf\Demo.CustomOpenFolderDialog\Demo.CustomOpenFolderDialog.csproj", "{3562249C-10F4-42C8-BD49-CCF26C51ED8C}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.OpenFolderDialog", "samples\Avalonia\Demo.OpenFolderDialog\Demo.OpenFolderDialog.csproj", "{2EBBA423-F963-4CF4-9355-A5B2CE7C699A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.CustomOpenFolderDialog", "samples\Avalonia\Demo.CustomOpenFolderDialog\Demo.CustomOpenFolderDialog.csproj", "{F01E685B-AC00-44ED-AF05-D96633B1E31A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.ModalDialog.Tests", "samples\Avalonia\Demo.ModalDialog.Tests\Demo.ModalDialog.Tests.csproj", "{20C76953-78BF-493C-BF15-AB67DC620D82}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.ModalDialog.Tests", "samples\Wpf\Demo.ModalDialog.Tests\Demo.ModalDialog.Tests.csproj", "{743EA3B7-51AE-4055-AA6B-A0232142F0C6}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MvvmDialogs.Avalonia.MessageBox", "src\MvvmDialogs.Avalonia.MessageBox\MvvmDialogs.Avalonia.MessageBox.csproj", "{7958C69B-C7A0-4CC4-8340-5C375E7AA722}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MvvmDialogs.Avalonia.Fluent", "src\MvvmDialogs.Avalonia.Fluent\MvvmDialogs.Avalonia.Fluent.csproj", "{532FD258-141B-4FF9-8846-CD8396728E27}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.FluentContentDialog", "samples\Avalonia\Demo.FluentContentDialog\Demo.FluentContentDialog.csproj", "{3B8A071F-EAE4-427F-9CF5-09BFA4F856FE}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.FluentTaskDialog", "samples\Avalonia\Demo.FluentTaskDialog\Demo.FluentTaskDialog.csproj", "{23550E77-920B-47A2-AE2C-36204BFA9469}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.FluentMessageBoxContentDialog", "samples\Avalonia\Demo.FluentMessageBoxContentDialog\Demo.FluentMessageBoxContentDialog.csproj", "{339BEC27-FD38-494E-9D96-7A43DE9B36B4}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.FluentMessageBoxTaskDialog", "samples\Avalonia\Demo.FluentMessageBoxTaskDialog\Demo.FluentMessageBoxTaskDialog.csproj", "{30F209A6-028C-4AF4-A34D-D32B6C0D3572}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.ViewEvents", "samples\Avalonia\Demo.ViewEvents\Demo.ViewEvents.csproj", "{BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.ViewEvents", "samples\Wpf\Demo.ViewEvents\Demo.ViewEvents.csproj", "{1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CrossPlatform", "CrossPlatform", "{B90D3DCC-669D-4583-8BA0-682EB1F93BD2}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MvvmDialogs.Avalonia.Tests", "src\MvvmDialogs.Avalonia.Tests\MvvmDialogs.Avalonia.Tests.csproj", "{AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.CrossPlatform", "samples\Avalonia\CrossPlatform\Demo.CrossPlatform\Demo.CrossPlatform.csproj", "{24D92E73-9429-48AD-A805-25CE7AF84D50}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.CrossPlatform.Android", "samples\Avalonia\CrossPlatform\Demo.CrossPlatform.Android\Demo.CrossPlatform.Android.csproj", "{497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.CrossPlatform.iOS", "samples\Avalonia\CrossPlatform\Demo.CrossPlatform.iOS\Demo.CrossPlatform.iOS.csproj", "{08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.CrossPlatform.Desktop", "samples\Avalonia\CrossPlatform\Demo.CrossPlatform.Desktop\Demo.CrossPlatform.Desktop.csproj", "{DB400AC5-91AB-4621-9E12-6EF27BFE9D2B}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.CrossPlatform.Browser", "samples\Avalonia\CrossPlatform\Demo.CrossPlatform.Browser\Demo.CrossPlatform.Browser.csproj", "{A8ADB3BE-683C-44FD-9C59-53F5B6B60A26}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.StrongLocator", "samples\Avalonia\Demo.StrongLocator\Demo.StrongLocator.csproj", "{F03BD8DB-9247-4977-A4AB-C98FE071294A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.StrongLocator", "samples\Wpf\Demo.StrongLocator\Demo.StrongLocator.csproj", "{3D577143-DEEA-42A4-B261-9A0846E537EF}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MvvmDialogs.Avalonia.DialogHost", "src\MvvmDialogs.Avalonia.DialogHost\MvvmDialogs.Avalonia.DialogHost.csproj", "{C9971FF8-3695-457F-8A78-CBDD098617D7}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo.DialogHost", "samples\Avalonia\Demo.DialogHost\Demo.DialogHost.csproj", "{86D96E8C-F62A-4563-AFEF-1907F9280D7D}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DBF0AD8E-617C-43D4-86C7-C81F825D656C}" ProjectSection(SolutionItems) = preProject src\Directory.Build.props = src\Directory.Build.props Directory.Packages.props = Directory.Packages.props EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo.ActivateNonModalDialog.MvvmToolkit", "samples\Avalonia\Demo.ActivateNonModalDialog.MvvmToolkit\Demo.ActivateNonModalDialog.MvvmToolkit.csproj", "{84D06F7E-6381-7653-27C1-4FF4A0232C92}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|ARM = Debug|ARM Debug|ARM64 = Debug|ARM64 Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU Release|ARM = Release|ARM Release|ARM64 = Release|ARM64 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {ED5001B1-A78B-4881-9BD8-CB56DD930585}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {ED5001B1-A78B-4881-9BD8-CB56DD930585}.Debug|Any CPU.Build.0 = Debug|Any CPU {ED5001B1-A78B-4881-9BD8-CB56DD930585}.Debug|ARM.ActiveCfg = Debug|Any CPU {ED5001B1-A78B-4881-9BD8-CB56DD930585}.Debug|ARM.Build.0 = Debug|Any CPU {ED5001B1-A78B-4881-9BD8-CB56DD930585}.Debug|ARM64.ActiveCfg = Debug|Any CPU {ED5001B1-A78B-4881-9BD8-CB56DD930585}.Debug|ARM64.Build.0 = Debug|Any CPU {ED5001B1-A78B-4881-9BD8-CB56DD930585}.Debug|x64.ActiveCfg = Debug|Any CPU {ED5001B1-A78B-4881-9BD8-CB56DD930585}.Debug|x64.Build.0 = Debug|Any CPU {ED5001B1-A78B-4881-9BD8-CB56DD930585}.Debug|x86.ActiveCfg = Debug|Any CPU {ED5001B1-A78B-4881-9BD8-CB56DD930585}.Debug|x86.Build.0 = Debug|Any CPU {ED5001B1-A78B-4881-9BD8-CB56DD930585}.Release|Any CPU.ActiveCfg = Release|Any CPU {ED5001B1-A78B-4881-9BD8-CB56DD930585}.Release|Any CPU.Build.0 = Release|Any CPU {ED5001B1-A78B-4881-9BD8-CB56DD930585}.Release|ARM.ActiveCfg = Release|Any CPU {ED5001B1-A78B-4881-9BD8-CB56DD930585}.Release|ARM.Build.0 = Release|Any CPU {ED5001B1-A78B-4881-9BD8-CB56DD930585}.Release|ARM64.ActiveCfg = Release|Any CPU {ED5001B1-A78B-4881-9BD8-CB56DD930585}.Release|ARM64.Build.0 = Release|Any CPU {ED5001B1-A78B-4881-9BD8-CB56DD930585}.Release|x64.ActiveCfg = Release|Any CPU {ED5001B1-A78B-4881-9BD8-CB56DD930585}.Release|x64.Build.0 = Release|Any CPU {ED5001B1-A78B-4881-9BD8-CB56DD930585}.Release|x86.ActiveCfg = Release|Any CPU {ED5001B1-A78B-4881-9BD8-CB56DD930585}.Release|x86.Build.0 = Release|Any CPU {A6ABFE78-566C-4534-947E-BEFB86BDA347}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A6ABFE78-566C-4534-947E-BEFB86BDA347}.Debug|Any CPU.Build.0 = Debug|Any CPU {A6ABFE78-566C-4534-947E-BEFB86BDA347}.Debug|ARM.ActiveCfg = Debug|Any CPU {A6ABFE78-566C-4534-947E-BEFB86BDA347}.Debug|ARM.Build.0 = Debug|Any CPU {A6ABFE78-566C-4534-947E-BEFB86BDA347}.Debug|ARM64.ActiveCfg = Debug|Any CPU {A6ABFE78-566C-4534-947E-BEFB86BDA347}.Debug|ARM64.Build.0 = Debug|Any CPU {A6ABFE78-566C-4534-947E-BEFB86BDA347}.Debug|x64.ActiveCfg = Debug|Any CPU {A6ABFE78-566C-4534-947E-BEFB86BDA347}.Debug|x64.Build.0 = Debug|Any CPU {A6ABFE78-566C-4534-947E-BEFB86BDA347}.Debug|x86.ActiveCfg = Debug|Any CPU {A6ABFE78-566C-4534-947E-BEFB86BDA347}.Debug|x86.Build.0 = Debug|Any CPU {A6ABFE78-566C-4534-947E-BEFB86BDA347}.Release|Any CPU.ActiveCfg = Release|Any CPU {A6ABFE78-566C-4534-947E-BEFB86BDA347}.Release|Any CPU.Build.0 = Release|Any CPU {A6ABFE78-566C-4534-947E-BEFB86BDA347}.Release|ARM.ActiveCfg = Release|Any CPU {A6ABFE78-566C-4534-947E-BEFB86BDA347}.Release|ARM.Build.0 = Release|Any CPU {A6ABFE78-566C-4534-947E-BEFB86BDA347}.Release|ARM64.ActiveCfg = Release|Any CPU {A6ABFE78-566C-4534-947E-BEFB86BDA347}.Release|ARM64.Build.0 = Release|Any CPU {A6ABFE78-566C-4534-947E-BEFB86BDA347}.Release|x64.ActiveCfg = Release|Any CPU {A6ABFE78-566C-4534-947E-BEFB86BDA347}.Release|x64.Build.0 = Release|Any CPU {A6ABFE78-566C-4534-947E-BEFB86BDA347}.Release|x86.ActiveCfg = Release|Any CPU {A6ABFE78-566C-4534-947E-BEFB86BDA347}.Release|x86.Build.0 = Release|Any CPU {AD1F57E0-055A-4838-91AD-B824BF17E481}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AD1F57E0-055A-4838-91AD-B824BF17E481}.Debug|Any CPU.Build.0 = Debug|Any CPU {AD1F57E0-055A-4838-91AD-B824BF17E481}.Debug|ARM.ActiveCfg = Debug|Any CPU {AD1F57E0-055A-4838-91AD-B824BF17E481}.Debug|ARM.Build.0 = Debug|Any CPU {AD1F57E0-055A-4838-91AD-B824BF17E481}.Debug|ARM64.ActiveCfg = Debug|Any CPU {AD1F57E0-055A-4838-91AD-B824BF17E481}.Debug|ARM64.Build.0 = Debug|Any CPU {AD1F57E0-055A-4838-91AD-B824BF17E481}.Debug|x64.ActiveCfg = Debug|Any CPU {AD1F57E0-055A-4838-91AD-B824BF17E481}.Debug|x64.Build.0 = Debug|Any CPU {AD1F57E0-055A-4838-91AD-B824BF17E481}.Debug|x86.ActiveCfg = Debug|Any CPU {AD1F57E0-055A-4838-91AD-B824BF17E481}.Debug|x86.Build.0 = Debug|Any CPU {AD1F57E0-055A-4838-91AD-B824BF17E481}.Release|Any CPU.ActiveCfg = Release|Any CPU {AD1F57E0-055A-4838-91AD-B824BF17E481}.Release|Any CPU.Build.0 = Release|Any CPU {AD1F57E0-055A-4838-91AD-B824BF17E481}.Release|ARM.ActiveCfg = Release|Any CPU {AD1F57E0-055A-4838-91AD-B824BF17E481}.Release|ARM.Build.0 = Release|Any CPU {AD1F57E0-055A-4838-91AD-B824BF17E481}.Release|ARM64.ActiveCfg = Release|Any CPU {AD1F57E0-055A-4838-91AD-B824BF17E481}.Release|ARM64.Build.0 = Release|Any CPU {AD1F57E0-055A-4838-91AD-B824BF17E481}.Release|x64.ActiveCfg = Release|Any CPU {AD1F57E0-055A-4838-91AD-B824BF17E481}.Release|x64.Build.0 = Release|Any CPU {AD1F57E0-055A-4838-91AD-B824BF17E481}.Release|x86.ActiveCfg = Release|Any CPU {AD1F57E0-055A-4838-91AD-B824BF17E481}.Release|x86.Build.0 = Release|Any CPU {F2CAA958-5A0E-4BB3-B624-B8360C5F2978}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F2CAA958-5A0E-4BB3-B624-B8360C5F2978}.Debug|Any CPU.Build.0 = Debug|Any CPU {F2CAA958-5A0E-4BB3-B624-B8360C5F2978}.Debug|ARM.ActiveCfg = Debug|Any CPU {F2CAA958-5A0E-4BB3-B624-B8360C5F2978}.Debug|ARM.Build.0 = Debug|Any CPU {F2CAA958-5A0E-4BB3-B624-B8360C5F2978}.Debug|ARM64.ActiveCfg = Debug|Any CPU {F2CAA958-5A0E-4BB3-B624-B8360C5F2978}.Debug|ARM64.Build.0 = Debug|Any CPU {F2CAA958-5A0E-4BB3-B624-B8360C5F2978}.Debug|x64.ActiveCfg = Debug|Any CPU {F2CAA958-5A0E-4BB3-B624-B8360C5F2978}.Debug|x64.Build.0 = Debug|Any CPU {F2CAA958-5A0E-4BB3-B624-B8360C5F2978}.Debug|x86.ActiveCfg = Debug|Any CPU {F2CAA958-5A0E-4BB3-B624-B8360C5F2978}.Debug|x86.Build.0 = Debug|Any CPU {F2CAA958-5A0E-4BB3-B624-B8360C5F2978}.Release|Any CPU.ActiveCfg = Release|Any CPU {F2CAA958-5A0E-4BB3-B624-B8360C5F2978}.Release|Any CPU.Build.0 = Release|Any CPU {F2CAA958-5A0E-4BB3-B624-B8360C5F2978}.Release|ARM.ActiveCfg = Release|Any CPU {F2CAA958-5A0E-4BB3-B624-B8360C5F2978}.Release|ARM.Build.0 = Release|Any CPU {F2CAA958-5A0E-4BB3-B624-B8360C5F2978}.Release|ARM64.ActiveCfg = Release|Any CPU {F2CAA958-5A0E-4BB3-B624-B8360C5F2978}.Release|ARM64.Build.0 = Release|Any CPU {F2CAA958-5A0E-4BB3-B624-B8360C5F2978}.Release|x64.ActiveCfg = Release|Any CPU {F2CAA958-5A0E-4BB3-B624-B8360C5F2978}.Release|x64.Build.0 = Release|Any CPU {F2CAA958-5A0E-4BB3-B624-B8360C5F2978}.Release|x86.ActiveCfg = Release|Any CPU {F2CAA958-5A0E-4BB3-B624-B8360C5F2978}.Release|x86.Build.0 = Release|Any CPU {DD760082-E0FA-433F-A1D0-D05F5D91FFA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DD760082-E0FA-433F-A1D0-D05F5D91FFA9}.Debug|Any CPU.Build.0 = Debug|Any CPU {DD760082-E0FA-433F-A1D0-D05F5D91FFA9}.Debug|ARM.ActiveCfg = Debug|Any CPU {DD760082-E0FA-433F-A1D0-D05F5D91FFA9}.Debug|ARM.Build.0 = Debug|Any CPU {DD760082-E0FA-433F-A1D0-D05F5D91FFA9}.Debug|ARM64.ActiveCfg = Debug|Any CPU {DD760082-E0FA-433F-A1D0-D05F5D91FFA9}.Debug|ARM64.Build.0 = Debug|Any CPU {DD760082-E0FA-433F-A1D0-D05F5D91FFA9}.Debug|x64.ActiveCfg = Debug|Any CPU {DD760082-E0FA-433F-A1D0-D05F5D91FFA9}.Debug|x64.Build.0 = Debug|Any CPU {DD760082-E0FA-433F-A1D0-D05F5D91FFA9}.Debug|x86.ActiveCfg = Debug|Any CPU {DD760082-E0FA-433F-A1D0-D05F5D91FFA9}.Debug|x86.Build.0 = Debug|Any CPU {DD760082-E0FA-433F-A1D0-D05F5D91FFA9}.Release|Any CPU.ActiveCfg = Release|Any CPU {DD760082-E0FA-433F-A1D0-D05F5D91FFA9}.Release|Any CPU.Build.0 = Release|Any CPU {DD760082-E0FA-433F-A1D0-D05F5D91FFA9}.Release|ARM.ActiveCfg = Release|Any CPU {DD760082-E0FA-433F-A1D0-D05F5D91FFA9}.Release|ARM.Build.0 = Release|Any CPU {DD760082-E0FA-433F-A1D0-D05F5D91FFA9}.Release|ARM64.ActiveCfg = Release|Any CPU {DD760082-E0FA-433F-A1D0-D05F5D91FFA9}.Release|ARM64.Build.0 = Release|Any CPU {DD760082-E0FA-433F-A1D0-D05F5D91FFA9}.Release|x64.ActiveCfg = Release|Any CPU {DD760082-E0FA-433F-A1D0-D05F5D91FFA9}.Release|x64.Build.0 = Release|Any CPU {DD760082-E0FA-433F-A1D0-D05F5D91FFA9}.Release|x86.ActiveCfg = Release|Any CPU {DD760082-E0FA-433F-A1D0-D05F5D91FFA9}.Release|x86.Build.0 = Release|Any CPU {74041466-C4C6-4396-8B57-D176CF5C0FD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {74041466-C4C6-4396-8B57-D176CF5C0FD9}.Debug|Any CPU.Build.0 = Debug|Any CPU {74041466-C4C6-4396-8B57-D176CF5C0FD9}.Debug|ARM.ActiveCfg = Debug|Any CPU {74041466-C4C6-4396-8B57-D176CF5C0FD9}.Debug|ARM.Build.0 = Debug|Any CPU {74041466-C4C6-4396-8B57-D176CF5C0FD9}.Debug|ARM64.ActiveCfg = Debug|Any CPU {74041466-C4C6-4396-8B57-D176CF5C0FD9}.Debug|ARM64.Build.0 = Debug|Any CPU {74041466-C4C6-4396-8B57-D176CF5C0FD9}.Debug|x64.ActiveCfg = Debug|Any CPU {74041466-C4C6-4396-8B57-D176CF5C0FD9}.Debug|x64.Build.0 = Debug|Any CPU {74041466-C4C6-4396-8B57-D176CF5C0FD9}.Debug|x86.ActiveCfg = Debug|Any CPU {74041466-C4C6-4396-8B57-D176CF5C0FD9}.Debug|x86.Build.0 = Debug|Any CPU {74041466-C4C6-4396-8B57-D176CF5C0FD9}.Release|Any CPU.ActiveCfg = Release|Any CPU {74041466-C4C6-4396-8B57-D176CF5C0FD9}.Release|Any CPU.Build.0 = Release|Any CPU {74041466-C4C6-4396-8B57-D176CF5C0FD9}.Release|ARM.ActiveCfg = Release|Any CPU {74041466-C4C6-4396-8B57-D176CF5C0FD9}.Release|ARM.Build.0 = Release|Any CPU {74041466-C4C6-4396-8B57-D176CF5C0FD9}.Release|ARM64.ActiveCfg = Release|Any CPU {74041466-C4C6-4396-8B57-D176CF5C0FD9}.Release|ARM64.Build.0 = Release|Any CPU {74041466-C4C6-4396-8B57-D176CF5C0FD9}.Release|x64.ActiveCfg = Release|Any CPU {74041466-C4C6-4396-8B57-D176CF5C0FD9}.Release|x64.Build.0 = Release|Any CPU {74041466-C4C6-4396-8B57-D176CF5C0FD9}.Release|x86.ActiveCfg = Release|Any CPU {74041466-C4C6-4396-8B57-D176CF5C0FD9}.Release|x86.Build.0 = Release|Any CPU {33BC9402-331E-47B5-8EE8-4F15AF463D12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {33BC9402-331E-47B5-8EE8-4F15AF463D12}.Debug|Any CPU.Build.0 = Debug|Any CPU {33BC9402-331E-47B5-8EE8-4F15AF463D12}.Debug|ARM.ActiveCfg = Debug|Any CPU {33BC9402-331E-47B5-8EE8-4F15AF463D12}.Debug|ARM.Build.0 = Debug|Any CPU {33BC9402-331E-47B5-8EE8-4F15AF463D12}.Debug|ARM64.ActiveCfg = Debug|Any CPU {33BC9402-331E-47B5-8EE8-4F15AF463D12}.Debug|ARM64.Build.0 = Debug|Any CPU {33BC9402-331E-47B5-8EE8-4F15AF463D12}.Debug|x64.ActiveCfg = Debug|Any CPU {33BC9402-331E-47B5-8EE8-4F15AF463D12}.Debug|x64.Build.0 = Debug|Any CPU {33BC9402-331E-47B5-8EE8-4F15AF463D12}.Debug|x86.ActiveCfg = Debug|Any CPU {33BC9402-331E-47B5-8EE8-4F15AF463D12}.Debug|x86.Build.0 = Debug|Any CPU {33BC9402-331E-47B5-8EE8-4F15AF463D12}.Release|Any CPU.ActiveCfg = Release|Any CPU {33BC9402-331E-47B5-8EE8-4F15AF463D12}.Release|Any CPU.Build.0 = Release|Any CPU {33BC9402-331E-47B5-8EE8-4F15AF463D12}.Release|ARM.ActiveCfg = Release|Any CPU {33BC9402-331E-47B5-8EE8-4F15AF463D12}.Release|ARM.Build.0 = Release|Any CPU {33BC9402-331E-47B5-8EE8-4F15AF463D12}.Release|ARM64.ActiveCfg = Release|Any CPU {33BC9402-331E-47B5-8EE8-4F15AF463D12}.Release|ARM64.Build.0 = Release|Any CPU {33BC9402-331E-47B5-8EE8-4F15AF463D12}.Release|x64.ActiveCfg = Release|Any CPU {33BC9402-331E-47B5-8EE8-4F15AF463D12}.Release|x64.Build.0 = Release|Any CPU {33BC9402-331E-47B5-8EE8-4F15AF463D12}.Release|x86.ActiveCfg = Release|Any CPU {33BC9402-331E-47B5-8EE8-4F15AF463D12}.Release|x86.Build.0 = Release|Any CPU {62E90DFE-FF71-4558-A33E-361BFE60BF9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {62E90DFE-FF71-4558-A33E-361BFE60BF9D}.Debug|Any CPU.Build.0 = Debug|Any CPU {62E90DFE-FF71-4558-A33E-361BFE60BF9D}.Debug|ARM.ActiveCfg = Debug|Any CPU {62E90DFE-FF71-4558-A33E-361BFE60BF9D}.Debug|ARM.Build.0 = Debug|Any CPU {62E90DFE-FF71-4558-A33E-361BFE60BF9D}.Debug|ARM64.ActiveCfg = Debug|Any CPU {62E90DFE-FF71-4558-A33E-361BFE60BF9D}.Debug|ARM64.Build.0 = Debug|Any CPU {62E90DFE-FF71-4558-A33E-361BFE60BF9D}.Debug|x64.ActiveCfg = Debug|Any CPU {62E90DFE-FF71-4558-A33E-361BFE60BF9D}.Debug|x64.Build.0 = Debug|Any CPU {62E90DFE-FF71-4558-A33E-361BFE60BF9D}.Debug|x86.ActiveCfg = Debug|Any CPU {62E90DFE-FF71-4558-A33E-361BFE60BF9D}.Debug|x86.Build.0 = Debug|Any CPU {62E90DFE-FF71-4558-A33E-361BFE60BF9D}.Release|Any CPU.ActiveCfg = Release|Any CPU {62E90DFE-FF71-4558-A33E-361BFE60BF9D}.Release|Any CPU.Build.0 = Release|Any CPU {62E90DFE-FF71-4558-A33E-361BFE60BF9D}.Release|ARM.ActiveCfg = Release|Any CPU {62E90DFE-FF71-4558-A33E-361BFE60BF9D}.Release|ARM.Build.0 = Release|Any CPU {62E90DFE-FF71-4558-A33E-361BFE60BF9D}.Release|ARM64.ActiveCfg = Release|Any CPU {62E90DFE-FF71-4558-A33E-361BFE60BF9D}.Release|ARM64.Build.0 = Release|Any CPU {62E90DFE-FF71-4558-A33E-361BFE60BF9D}.Release|x64.ActiveCfg = Release|Any CPU {62E90DFE-FF71-4558-A33E-361BFE60BF9D}.Release|x64.Build.0 = Release|Any CPU {62E90DFE-FF71-4558-A33E-361BFE60BF9D}.Release|x86.ActiveCfg = Release|Any CPU {62E90DFE-FF71-4558-A33E-361BFE60BF9D}.Release|x86.Build.0 = Release|Any CPU {CABB5675-02EF-42A7-A2C9-E4F37D66D12B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CABB5675-02EF-42A7-A2C9-E4F37D66D12B}.Debug|Any CPU.Build.0 = Debug|Any CPU {CABB5675-02EF-42A7-A2C9-E4F37D66D12B}.Debug|ARM.ActiveCfg = Debug|Any CPU {CABB5675-02EF-42A7-A2C9-E4F37D66D12B}.Debug|ARM.Build.0 = Debug|Any CPU {CABB5675-02EF-42A7-A2C9-E4F37D66D12B}.Debug|ARM64.ActiveCfg = Debug|Any CPU {CABB5675-02EF-42A7-A2C9-E4F37D66D12B}.Debug|ARM64.Build.0 = Debug|Any CPU {CABB5675-02EF-42A7-A2C9-E4F37D66D12B}.Debug|x64.ActiveCfg = Debug|Any CPU {CABB5675-02EF-42A7-A2C9-E4F37D66D12B}.Debug|x64.Build.0 = Debug|Any CPU {CABB5675-02EF-42A7-A2C9-E4F37D66D12B}.Debug|x86.ActiveCfg = Debug|Any CPU {CABB5675-02EF-42A7-A2C9-E4F37D66D12B}.Debug|x86.Build.0 = Debug|Any CPU {CABB5675-02EF-42A7-A2C9-E4F37D66D12B}.Release|Any CPU.ActiveCfg = Release|Any CPU {CABB5675-02EF-42A7-A2C9-E4F37D66D12B}.Release|Any CPU.Build.0 = Release|Any CPU {CABB5675-02EF-42A7-A2C9-E4F37D66D12B}.Release|ARM.ActiveCfg = Release|Any CPU {CABB5675-02EF-42A7-A2C9-E4F37D66D12B}.Release|ARM.Build.0 = Release|Any CPU {CABB5675-02EF-42A7-A2C9-E4F37D66D12B}.Release|ARM64.ActiveCfg = Release|Any CPU {CABB5675-02EF-42A7-A2C9-E4F37D66D12B}.Release|ARM64.Build.0 = Release|Any CPU {CABB5675-02EF-42A7-A2C9-E4F37D66D12B}.Release|x64.ActiveCfg = Release|Any CPU {CABB5675-02EF-42A7-A2C9-E4F37D66D12B}.Release|x64.Build.0 = Release|Any CPU {CABB5675-02EF-42A7-A2C9-E4F37D66D12B}.Release|x86.ActiveCfg = Release|Any CPU {CABB5675-02EF-42A7-A2C9-E4F37D66D12B}.Release|x86.Build.0 = Release|Any CPU {0848A1AE-3147-432C-B473-44EE2CBA2E57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0848A1AE-3147-432C-B473-44EE2CBA2E57}.Debug|Any CPU.Build.0 = Debug|Any CPU {0848A1AE-3147-432C-B473-44EE2CBA2E57}.Debug|ARM.ActiveCfg = Debug|Any CPU {0848A1AE-3147-432C-B473-44EE2CBA2E57}.Debug|ARM.Build.0 = Debug|Any CPU {0848A1AE-3147-432C-B473-44EE2CBA2E57}.Debug|ARM64.ActiveCfg = Debug|Any CPU {0848A1AE-3147-432C-B473-44EE2CBA2E57}.Debug|ARM64.Build.0 = Debug|Any CPU {0848A1AE-3147-432C-B473-44EE2CBA2E57}.Debug|x64.ActiveCfg = Debug|Any CPU {0848A1AE-3147-432C-B473-44EE2CBA2E57}.Debug|x64.Build.0 = Debug|Any CPU {0848A1AE-3147-432C-B473-44EE2CBA2E57}.Debug|x86.ActiveCfg = Debug|Any CPU {0848A1AE-3147-432C-B473-44EE2CBA2E57}.Debug|x86.Build.0 = Debug|Any CPU {0848A1AE-3147-432C-B473-44EE2CBA2E57}.Release|Any CPU.ActiveCfg = Release|Any CPU {0848A1AE-3147-432C-B473-44EE2CBA2E57}.Release|Any CPU.Build.0 = Release|Any CPU {0848A1AE-3147-432C-B473-44EE2CBA2E57}.Release|ARM.ActiveCfg = Release|Any CPU {0848A1AE-3147-432C-B473-44EE2CBA2E57}.Release|ARM.Build.0 = Release|Any CPU {0848A1AE-3147-432C-B473-44EE2CBA2E57}.Release|ARM64.ActiveCfg = Release|Any CPU {0848A1AE-3147-432C-B473-44EE2CBA2E57}.Release|ARM64.Build.0 = Release|Any CPU {0848A1AE-3147-432C-B473-44EE2CBA2E57}.Release|x64.ActiveCfg = Release|Any CPU {0848A1AE-3147-432C-B473-44EE2CBA2E57}.Release|x64.Build.0 = Release|Any CPU {0848A1AE-3147-432C-B473-44EE2CBA2E57}.Release|x86.ActiveCfg = Release|Any CPU {0848A1AE-3147-432C-B473-44EE2CBA2E57}.Release|x86.Build.0 = Release|Any CPU {E14F830F-2A00-46D0-B25B-B3D675E86B02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E14F830F-2A00-46D0-B25B-B3D675E86B02}.Debug|Any CPU.Build.0 = Debug|Any CPU {E14F830F-2A00-46D0-B25B-B3D675E86B02}.Debug|ARM.ActiveCfg = Debug|Any CPU {E14F830F-2A00-46D0-B25B-B3D675E86B02}.Debug|ARM.Build.0 = Debug|Any CPU {E14F830F-2A00-46D0-B25B-B3D675E86B02}.Debug|ARM64.ActiveCfg = Debug|Any CPU {E14F830F-2A00-46D0-B25B-B3D675E86B02}.Debug|ARM64.Build.0 = Debug|Any CPU {E14F830F-2A00-46D0-B25B-B3D675E86B02}.Debug|x64.ActiveCfg = Debug|Any CPU {E14F830F-2A00-46D0-B25B-B3D675E86B02}.Debug|x64.Build.0 = Debug|Any CPU {E14F830F-2A00-46D0-B25B-B3D675E86B02}.Debug|x86.ActiveCfg = Debug|Any CPU {E14F830F-2A00-46D0-B25B-B3D675E86B02}.Debug|x86.Build.0 = Debug|Any CPU {E14F830F-2A00-46D0-B25B-B3D675E86B02}.Release|Any CPU.ActiveCfg = Release|Any CPU {E14F830F-2A00-46D0-B25B-B3D675E86B02}.Release|Any CPU.Build.0 = Release|Any CPU {E14F830F-2A00-46D0-B25B-B3D675E86B02}.Release|ARM.ActiveCfg = Release|Any CPU {E14F830F-2A00-46D0-B25B-B3D675E86B02}.Release|ARM.Build.0 = Release|Any CPU {E14F830F-2A00-46D0-B25B-B3D675E86B02}.Release|ARM64.ActiveCfg = Release|Any CPU {E14F830F-2A00-46D0-B25B-B3D675E86B02}.Release|ARM64.Build.0 = Release|Any CPU {E14F830F-2A00-46D0-B25B-B3D675E86B02}.Release|x64.ActiveCfg = Release|Any CPU {E14F830F-2A00-46D0-B25B-B3D675E86B02}.Release|x64.Build.0 = Release|Any CPU {E14F830F-2A00-46D0-B25B-B3D675E86B02}.Release|x86.ActiveCfg = Release|Any CPU {E14F830F-2A00-46D0-B25B-B3D675E86B02}.Release|x86.Build.0 = Release|Any CPU {32D9C89C-9D88-40F9-A05D-CD95F05F38D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {32D9C89C-9D88-40F9-A05D-CD95F05F38D0}.Debug|Any CPU.Build.0 = Debug|Any CPU {32D9C89C-9D88-40F9-A05D-CD95F05F38D0}.Debug|ARM.ActiveCfg = Debug|Any CPU {32D9C89C-9D88-40F9-A05D-CD95F05F38D0}.Debug|ARM.Build.0 = Debug|Any CPU {32D9C89C-9D88-40F9-A05D-CD95F05F38D0}.Debug|ARM64.ActiveCfg = Debug|Any CPU {32D9C89C-9D88-40F9-A05D-CD95F05F38D0}.Debug|ARM64.Build.0 = Debug|Any CPU {32D9C89C-9D88-40F9-A05D-CD95F05F38D0}.Debug|x64.ActiveCfg = Debug|Any CPU {32D9C89C-9D88-40F9-A05D-CD95F05F38D0}.Debug|x64.Build.0 = Debug|Any CPU {32D9C89C-9D88-40F9-A05D-CD95F05F38D0}.Debug|x86.ActiveCfg = Debug|Any CPU {32D9C89C-9D88-40F9-A05D-CD95F05F38D0}.Debug|x86.Build.0 = Debug|Any CPU {32D9C89C-9D88-40F9-A05D-CD95F05F38D0}.Release|Any CPU.ActiveCfg = Release|Any CPU {32D9C89C-9D88-40F9-A05D-CD95F05F38D0}.Release|Any CPU.Build.0 = Release|Any CPU {32D9C89C-9D88-40F9-A05D-CD95F05F38D0}.Release|ARM.ActiveCfg = Release|Any CPU {32D9C89C-9D88-40F9-A05D-CD95F05F38D0}.Release|ARM.Build.0 = Release|Any CPU {32D9C89C-9D88-40F9-A05D-CD95F05F38D0}.Release|ARM64.ActiveCfg = Release|Any CPU {32D9C89C-9D88-40F9-A05D-CD95F05F38D0}.Release|ARM64.Build.0 = Release|Any CPU {32D9C89C-9D88-40F9-A05D-CD95F05F38D0}.Release|x64.ActiveCfg = Release|Any CPU {32D9C89C-9D88-40F9-A05D-CD95F05F38D0}.Release|x64.Build.0 = Release|Any CPU {32D9C89C-9D88-40F9-A05D-CD95F05F38D0}.Release|x86.ActiveCfg = Release|Any CPU {32D9C89C-9D88-40F9-A05D-CD95F05F38D0}.Release|x86.Build.0 = Release|Any CPU {26E80F33-67D7-4F29-87E4-DFA45FBCF6B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {26E80F33-67D7-4F29-87E4-DFA45FBCF6B3}.Debug|Any CPU.Build.0 = Debug|Any CPU {26E80F33-67D7-4F29-87E4-DFA45FBCF6B3}.Debug|ARM.ActiveCfg = Debug|Any CPU {26E80F33-67D7-4F29-87E4-DFA45FBCF6B3}.Debug|ARM.Build.0 = Debug|Any CPU {26E80F33-67D7-4F29-87E4-DFA45FBCF6B3}.Debug|ARM64.ActiveCfg = Debug|Any CPU {26E80F33-67D7-4F29-87E4-DFA45FBCF6B3}.Debug|ARM64.Build.0 = Debug|Any CPU {26E80F33-67D7-4F29-87E4-DFA45FBCF6B3}.Debug|x64.ActiveCfg = Debug|Any CPU {26E80F33-67D7-4F29-87E4-DFA45FBCF6B3}.Debug|x64.Build.0 = Debug|Any CPU {26E80F33-67D7-4F29-87E4-DFA45FBCF6B3}.Debug|x86.ActiveCfg = Debug|Any CPU {26E80F33-67D7-4F29-87E4-DFA45FBCF6B3}.Debug|x86.Build.0 = Debug|Any CPU {26E80F33-67D7-4F29-87E4-DFA45FBCF6B3}.Release|Any CPU.ActiveCfg = Release|Any CPU {26E80F33-67D7-4F29-87E4-DFA45FBCF6B3}.Release|Any CPU.Build.0 = Release|Any CPU {26E80F33-67D7-4F29-87E4-DFA45FBCF6B3}.Release|ARM.ActiveCfg = Release|Any CPU {26E80F33-67D7-4F29-87E4-DFA45FBCF6B3}.Release|ARM.Build.0 = Release|Any CPU {26E80F33-67D7-4F29-87E4-DFA45FBCF6B3}.Release|ARM64.ActiveCfg = Release|Any CPU {26E80F33-67D7-4F29-87E4-DFA45FBCF6B3}.Release|ARM64.Build.0 = Release|Any CPU {26E80F33-67D7-4F29-87E4-DFA45FBCF6B3}.Release|x64.ActiveCfg = Release|Any CPU {26E80F33-67D7-4F29-87E4-DFA45FBCF6B3}.Release|x64.Build.0 = Release|Any CPU {26E80F33-67D7-4F29-87E4-DFA45FBCF6B3}.Release|x86.ActiveCfg = Release|Any CPU {26E80F33-67D7-4F29-87E4-DFA45FBCF6B3}.Release|x86.Build.0 = Release|Any CPU {ADB64CA1-52F9-47B9-AC03-975D2C9E4022}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {ADB64CA1-52F9-47B9-AC03-975D2C9E4022}.Debug|Any CPU.Build.0 = Debug|Any CPU {ADB64CA1-52F9-47B9-AC03-975D2C9E4022}.Debug|ARM.ActiveCfg = Debug|Any CPU {ADB64CA1-52F9-47B9-AC03-975D2C9E4022}.Debug|ARM.Build.0 = Debug|Any CPU {ADB64CA1-52F9-47B9-AC03-975D2C9E4022}.Debug|ARM64.ActiveCfg = Debug|Any CPU {ADB64CA1-52F9-47B9-AC03-975D2C9E4022}.Debug|ARM64.Build.0 = Debug|Any CPU {ADB64CA1-52F9-47B9-AC03-975D2C9E4022}.Debug|x64.ActiveCfg = Debug|Any CPU {ADB64CA1-52F9-47B9-AC03-975D2C9E4022}.Debug|x64.Build.0 = Debug|Any CPU {ADB64CA1-52F9-47B9-AC03-975D2C9E4022}.Debug|x86.ActiveCfg = Debug|Any CPU {ADB64CA1-52F9-47B9-AC03-975D2C9E4022}.Debug|x86.Build.0 = Debug|Any CPU {ADB64CA1-52F9-47B9-AC03-975D2C9E4022}.Release|Any CPU.ActiveCfg = Release|Any CPU {ADB64CA1-52F9-47B9-AC03-975D2C9E4022}.Release|Any CPU.Build.0 = Release|Any CPU {ADB64CA1-52F9-47B9-AC03-975D2C9E4022}.Release|ARM.ActiveCfg = Release|Any CPU {ADB64CA1-52F9-47B9-AC03-975D2C9E4022}.Release|ARM.Build.0 = Release|Any CPU {ADB64CA1-52F9-47B9-AC03-975D2C9E4022}.Release|ARM64.ActiveCfg = Release|Any CPU {ADB64CA1-52F9-47B9-AC03-975D2C9E4022}.Release|ARM64.Build.0 = Release|Any CPU {ADB64CA1-52F9-47B9-AC03-975D2C9E4022}.Release|x64.ActiveCfg = Release|Any CPU {ADB64CA1-52F9-47B9-AC03-975D2C9E4022}.Release|x64.Build.0 = Release|Any CPU {ADB64CA1-52F9-47B9-AC03-975D2C9E4022}.Release|x86.ActiveCfg = Release|Any CPU {ADB64CA1-52F9-47B9-AC03-975D2C9E4022}.Release|x86.Build.0 = Release|Any CPU {89BFF856-E543-4EB5-B443-78B30D818D57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {89BFF856-E543-4EB5-B443-78B30D818D57}.Debug|Any CPU.Build.0 = Debug|Any CPU {89BFF856-E543-4EB5-B443-78B30D818D57}.Debug|ARM.ActiveCfg = Debug|Any CPU {89BFF856-E543-4EB5-B443-78B30D818D57}.Debug|ARM.Build.0 = Debug|Any CPU {89BFF856-E543-4EB5-B443-78B30D818D57}.Debug|ARM64.ActiveCfg = Debug|Any CPU {89BFF856-E543-4EB5-B443-78B30D818D57}.Debug|ARM64.Build.0 = Debug|Any CPU {89BFF856-E543-4EB5-B443-78B30D818D57}.Debug|x64.ActiveCfg = Debug|Any CPU {89BFF856-E543-4EB5-B443-78B30D818D57}.Debug|x64.Build.0 = Debug|Any CPU {89BFF856-E543-4EB5-B443-78B30D818D57}.Debug|x86.ActiveCfg = Debug|Any CPU {89BFF856-E543-4EB5-B443-78B30D818D57}.Debug|x86.Build.0 = Debug|Any CPU {89BFF856-E543-4EB5-B443-78B30D818D57}.Release|Any CPU.ActiveCfg = Release|Any CPU {89BFF856-E543-4EB5-B443-78B30D818D57}.Release|Any CPU.Build.0 = Release|Any CPU {89BFF856-E543-4EB5-B443-78B30D818D57}.Release|ARM.ActiveCfg = Release|Any CPU {89BFF856-E543-4EB5-B443-78B30D818D57}.Release|ARM.Build.0 = Release|Any CPU {89BFF856-E543-4EB5-B443-78B30D818D57}.Release|ARM64.ActiveCfg = Release|Any CPU {89BFF856-E543-4EB5-B443-78B30D818D57}.Release|ARM64.Build.0 = Release|Any CPU {89BFF856-E543-4EB5-B443-78B30D818D57}.Release|x64.ActiveCfg = Release|Any CPU {89BFF856-E543-4EB5-B443-78B30D818D57}.Release|x64.Build.0 = Release|Any CPU {89BFF856-E543-4EB5-B443-78B30D818D57}.Release|x86.ActiveCfg = Release|Any CPU {89BFF856-E543-4EB5-B443-78B30D818D57}.Release|x86.Build.0 = Release|Any CPU {4D578475-512F-43C5-9AF4-F8A8578732CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4D578475-512F-43C5-9AF4-F8A8578732CE}.Debug|Any CPU.Build.0 = Debug|Any CPU {4D578475-512F-43C5-9AF4-F8A8578732CE}.Debug|ARM.ActiveCfg = Debug|Any CPU {4D578475-512F-43C5-9AF4-F8A8578732CE}.Debug|ARM.Build.0 = Debug|Any CPU {4D578475-512F-43C5-9AF4-F8A8578732CE}.Debug|ARM64.ActiveCfg = Debug|Any CPU {4D578475-512F-43C5-9AF4-F8A8578732CE}.Debug|ARM64.Build.0 = Debug|Any CPU {4D578475-512F-43C5-9AF4-F8A8578732CE}.Debug|x64.ActiveCfg = Debug|Any CPU {4D578475-512F-43C5-9AF4-F8A8578732CE}.Debug|x64.Build.0 = Debug|Any CPU {4D578475-512F-43C5-9AF4-F8A8578732CE}.Debug|x86.ActiveCfg = Debug|Any CPU {4D578475-512F-43C5-9AF4-F8A8578732CE}.Debug|x86.Build.0 = Debug|Any CPU {4D578475-512F-43C5-9AF4-F8A8578732CE}.Release|Any CPU.ActiveCfg = Release|Any CPU {4D578475-512F-43C5-9AF4-F8A8578732CE}.Release|Any CPU.Build.0 = Release|Any CPU {4D578475-512F-43C5-9AF4-F8A8578732CE}.Release|ARM.ActiveCfg = Release|Any CPU {4D578475-512F-43C5-9AF4-F8A8578732CE}.Release|ARM.Build.0 = Release|Any CPU {4D578475-512F-43C5-9AF4-F8A8578732CE}.Release|ARM64.ActiveCfg = Release|Any CPU {4D578475-512F-43C5-9AF4-F8A8578732CE}.Release|ARM64.Build.0 = Release|Any CPU {4D578475-512F-43C5-9AF4-F8A8578732CE}.Release|x64.ActiveCfg = Release|Any CPU {4D578475-512F-43C5-9AF4-F8A8578732CE}.Release|x64.Build.0 = Release|Any CPU {4D578475-512F-43C5-9AF4-F8A8578732CE}.Release|x86.ActiveCfg = Release|Any CPU {4D578475-512F-43C5-9AF4-F8A8578732CE}.Release|x86.Build.0 = Release|Any CPU {61F454B7-9F32-4CBA-8FE5-02B44D5CF25C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {61F454B7-9F32-4CBA-8FE5-02B44D5CF25C}.Debug|Any CPU.Build.0 = Debug|Any CPU {61F454B7-9F32-4CBA-8FE5-02B44D5CF25C}.Debug|ARM.ActiveCfg = Debug|Any CPU {61F454B7-9F32-4CBA-8FE5-02B44D5CF25C}.Debug|ARM.Build.0 = Debug|Any CPU {61F454B7-9F32-4CBA-8FE5-02B44D5CF25C}.Debug|ARM64.ActiveCfg = Debug|Any CPU {61F454B7-9F32-4CBA-8FE5-02B44D5CF25C}.Debug|ARM64.Build.0 = Debug|Any CPU {61F454B7-9F32-4CBA-8FE5-02B44D5CF25C}.Debug|x64.ActiveCfg = Debug|Any CPU {61F454B7-9F32-4CBA-8FE5-02B44D5CF25C}.Debug|x64.Build.0 = Debug|Any CPU {61F454B7-9F32-4CBA-8FE5-02B44D5CF25C}.Debug|x86.ActiveCfg = Debug|Any CPU {61F454B7-9F32-4CBA-8FE5-02B44D5CF25C}.Debug|x86.Build.0 = Debug|Any CPU {61F454B7-9F32-4CBA-8FE5-02B44D5CF25C}.Release|Any CPU.ActiveCfg = Release|Any CPU {61F454B7-9F32-4CBA-8FE5-02B44D5CF25C}.Release|Any CPU.Build.0 = Release|Any CPU {61F454B7-9F32-4CBA-8FE5-02B44D5CF25C}.Release|ARM.ActiveCfg = Release|Any CPU {61F454B7-9F32-4CBA-8FE5-02B44D5CF25C}.Release|ARM.Build.0 = Release|Any CPU {61F454B7-9F32-4CBA-8FE5-02B44D5CF25C}.Release|ARM64.ActiveCfg = Release|Any CPU {61F454B7-9F32-4CBA-8FE5-02B44D5CF25C}.Release|ARM64.Build.0 = Release|Any CPU {61F454B7-9F32-4CBA-8FE5-02B44D5CF25C}.Release|x64.ActiveCfg = Release|Any CPU {61F454B7-9F32-4CBA-8FE5-02B44D5CF25C}.Release|x64.Build.0 = Release|Any CPU {61F454B7-9F32-4CBA-8FE5-02B44D5CF25C}.Release|x86.ActiveCfg = Release|Any CPU {61F454B7-9F32-4CBA-8FE5-02B44D5CF25C}.Release|x86.Build.0 = Release|Any CPU {1E02BE6D-9F98-4343-930C-588CCB9A1296}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1E02BE6D-9F98-4343-930C-588CCB9A1296}.Debug|Any CPU.Build.0 = Debug|Any CPU {1E02BE6D-9F98-4343-930C-588CCB9A1296}.Debug|ARM.ActiveCfg = Debug|Any CPU {1E02BE6D-9F98-4343-930C-588CCB9A1296}.Debug|ARM.Build.0 = Debug|Any CPU {1E02BE6D-9F98-4343-930C-588CCB9A1296}.Debug|ARM64.ActiveCfg = Debug|Any CPU {1E02BE6D-9F98-4343-930C-588CCB9A1296}.Debug|ARM64.Build.0 = Debug|Any CPU {1E02BE6D-9F98-4343-930C-588CCB9A1296}.Debug|x64.ActiveCfg = Debug|Any CPU {1E02BE6D-9F98-4343-930C-588CCB9A1296}.Debug|x64.Build.0 = Debug|Any CPU {1E02BE6D-9F98-4343-930C-588CCB9A1296}.Debug|x86.ActiveCfg = Debug|Any CPU {1E02BE6D-9F98-4343-930C-588CCB9A1296}.Debug|x86.Build.0 = Debug|Any CPU {1E02BE6D-9F98-4343-930C-588CCB9A1296}.Release|Any CPU.ActiveCfg = Release|Any CPU {1E02BE6D-9F98-4343-930C-588CCB9A1296}.Release|Any CPU.Build.0 = Release|Any CPU {1E02BE6D-9F98-4343-930C-588CCB9A1296}.Release|ARM.ActiveCfg = Release|Any CPU {1E02BE6D-9F98-4343-930C-588CCB9A1296}.Release|ARM.Build.0 = Release|Any CPU {1E02BE6D-9F98-4343-930C-588CCB9A1296}.Release|ARM64.ActiveCfg = Release|Any CPU {1E02BE6D-9F98-4343-930C-588CCB9A1296}.Release|ARM64.Build.0 = Release|Any CPU {1E02BE6D-9F98-4343-930C-588CCB9A1296}.Release|x64.ActiveCfg = Release|Any CPU {1E02BE6D-9F98-4343-930C-588CCB9A1296}.Release|x64.Build.0 = Release|Any CPU {1E02BE6D-9F98-4343-930C-588CCB9A1296}.Release|x86.ActiveCfg = Release|Any CPU {1E02BE6D-9F98-4343-930C-588CCB9A1296}.Release|x86.Build.0 = Release|Any CPU {3D4F7533-B6B3-4F96-8794-F80A96EAB34E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3D4F7533-B6B3-4F96-8794-F80A96EAB34E}.Debug|Any CPU.Build.0 = Debug|Any CPU {3D4F7533-B6B3-4F96-8794-F80A96EAB34E}.Debug|ARM.ActiveCfg = Debug|Any CPU {3D4F7533-B6B3-4F96-8794-F80A96EAB34E}.Debug|ARM.Build.0 = Debug|Any CPU {3D4F7533-B6B3-4F96-8794-F80A96EAB34E}.Debug|ARM64.ActiveCfg = Debug|Any CPU {3D4F7533-B6B3-4F96-8794-F80A96EAB34E}.Debug|ARM64.Build.0 = Debug|Any CPU {3D4F7533-B6B3-4F96-8794-F80A96EAB34E}.Debug|x64.ActiveCfg = Debug|Any CPU {3D4F7533-B6B3-4F96-8794-F80A96EAB34E}.Debug|x64.Build.0 = Debug|Any CPU {3D4F7533-B6B3-4F96-8794-F80A96EAB34E}.Debug|x86.ActiveCfg = Debug|Any CPU {3D4F7533-B6B3-4F96-8794-F80A96EAB34E}.Debug|x86.Build.0 = Debug|Any CPU {3D4F7533-B6B3-4F96-8794-F80A96EAB34E}.Release|Any CPU.ActiveCfg = Release|Any CPU {3D4F7533-B6B3-4F96-8794-F80A96EAB34E}.Release|Any CPU.Build.0 = Release|Any CPU {3D4F7533-B6B3-4F96-8794-F80A96EAB34E}.Release|ARM.ActiveCfg = Release|Any CPU {3D4F7533-B6B3-4F96-8794-F80A96EAB34E}.Release|ARM.Build.0 = Release|Any CPU {3D4F7533-B6B3-4F96-8794-F80A96EAB34E}.Release|ARM64.ActiveCfg = Release|Any CPU {3D4F7533-B6B3-4F96-8794-F80A96EAB34E}.Release|ARM64.Build.0 = Release|Any CPU {3D4F7533-B6B3-4F96-8794-F80A96EAB34E}.Release|x64.ActiveCfg = Release|Any CPU {3D4F7533-B6B3-4F96-8794-F80A96EAB34E}.Release|x64.Build.0 = Release|Any CPU {3D4F7533-B6B3-4F96-8794-F80A96EAB34E}.Release|x86.ActiveCfg = Release|Any CPU {3D4F7533-B6B3-4F96-8794-F80A96EAB34E}.Release|x86.Build.0 = Release|Any CPU {CC35BEDB-96DB-452C-BDDB-3D90169F8313}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CC35BEDB-96DB-452C-BDDB-3D90169F8313}.Debug|Any CPU.Build.0 = Debug|Any CPU {CC35BEDB-96DB-452C-BDDB-3D90169F8313}.Debug|ARM.ActiveCfg = Debug|Any CPU {CC35BEDB-96DB-452C-BDDB-3D90169F8313}.Debug|ARM.Build.0 = Debug|Any CPU {CC35BEDB-96DB-452C-BDDB-3D90169F8313}.Debug|ARM64.ActiveCfg = Debug|Any CPU {CC35BEDB-96DB-452C-BDDB-3D90169F8313}.Debug|ARM64.Build.0 = Debug|Any CPU {CC35BEDB-96DB-452C-BDDB-3D90169F8313}.Debug|x64.ActiveCfg = Debug|Any CPU {CC35BEDB-96DB-452C-BDDB-3D90169F8313}.Debug|x64.Build.0 = Debug|Any CPU {CC35BEDB-96DB-452C-BDDB-3D90169F8313}.Debug|x86.ActiveCfg = Debug|Any CPU {CC35BEDB-96DB-452C-BDDB-3D90169F8313}.Debug|x86.Build.0 = Debug|Any CPU {CC35BEDB-96DB-452C-BDDB-3D90169F8313}.Release|Any CPU.ActiveCfg = Release|Any CPU {CC35BEDB-96DB-452C-BDDB-3D90169F8313}.Release|Any CPU.Build.0 = Release|Any CPU {CC35BEDB-96DB-452C-BDDB-3D90169F8313}.Release|ARM.ActiveCfg = Release|Any CPU {CC35BEDB-96DB-452C-BDDB-3D90169F8313}.Release|ARM.Build.0 = Release|Any CPU {CC35BEDB-96DB-452C-BDDB-3D90169F8313}.Release|ARM64.ActiveCfg = Release|Any CPU {CC35BEDB-96DB-452C-BDDB-3D90169F8313}.Release|ARM64.Build.0 = Release|Any CPU {CC35BEDB-96DB-452C-BDDB-3D90169F8313}.Release|x64.ActiveCfg = Release|Any CPU {CC35BEDB-96DB-452C-BDDB-3D90169F8313}.Release|x64.Build.0 = Release|Any CPU {CC35BEDB-96DB-452C-BDDB-3D90169F8313}.Release|x86.ActiveCfg = Release|Any CPU {CC35BEDB-96DB-452C-BDDB-3D90169F8313}.Release|x86.Build.0 = Release|Any CPU {27684F10-FC43-4868-80B3-9D1840E4CF54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {27684F10-FC43-4868-80B3-9D1840E4CF54}.Debug|Any CPU.Build.0 = Debug|Any CPU {27684F10-FC43-4868-80B3-9D1840E4CF54}.Debug|ARM.ActiveCfg = Debug|Any CPU {27684F10-FC43-4868-80B3-9D1840E4CF54}.Debug|ARM.Build.0 = Debug|Any CPU {27684F10-FC43-4868-80B3-9D1840E4CF54}.Debug|ARM64.ActiveCfg = Debug|Any CPU {27684F10-FC43-4868-80B3-9D1840E4CF54}.Debug|ARM64.Build.0 = Debug|Any CPU {27684F10-FC43-4868-80B3-9D1840E4CF54}.Debug|x64.ActiveCfg = Debug|Any CPU {27684F10-FC43-4868-80B3-9D1840E4CF54}.Debug|x64.Build.0 = Debug|Any CPU {27684F10-FC43-4868-80B3-9D1840E4CF54}.Debug|x86.ActiveCfg = Debug|Any CPU {27684F10-FC43-4868-80B3-9D1840E4CF54}.Debug|x86.Build.0 = Debug|Any CPU {27684F10-FC43-4868-80B3-9D1840E4CF54}.Release|Any CPU.ActiveCfg = Release|Any CPU {27684F10-FC43-4868-80B3-9D1840E4CF54}.Release|Any CPU.Build.0 = Release|Any CPU {27684F10-FC43-4868-80B3-9D1840E4CF54}.Release|ARM.ActiveCfg = Release|Any CPU {27684F10-FC43-4868-80B3-9D1840E4CF54}.Release|ARM.Build.0 = Release|Any CPU {27684F10-FC43-4868-80B3-9D1840E4CF54}.Release|ARM64.ActiveCfg = Release|Any CPU {27684F10-FC43-4868-80B3-9D1840E4CF54}.Release|ARM64.Build.0 = Release|Any CPU {27684F10-FC43-4868-80B3-9D1840E4CF54}.Release|x64.ActiveCfg = Release|Any CPU {27684F10-FC43-4868-80B3-9D1840E4CF54}.Release|x64.Build.0 = Release|Any CPU {27684F10-FC43-4868-80B3-9D1840E4CF54}.Release|x86.ActiveCfg = Release|Any CPU {27684F10-FC43-4868-80B3-9D1840E4CF54}.Release|x86.Build.0 = Release|Any CPU {3562249C-10F4-42C8-BD49-CCF26C51ED8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3562249C-10F4-42C8-BD49-CCF26C51ED8C}.Debug|Any CPU.Build.0 = Debug|Any CPU {3562249C-10F4-42C8-BD49-CCF26C51ED8C}.Debug|ARM.ActiveCfg = Debug|Any CPU {3562249C-10F4-42C8-BD49-CCF26C51ED8C}.Debug|ARM.Build.0 = Debug|Any CPU {3562249C-10F4-42C8-BD49-CCF26C51ED8C}.Debug|ARM64.ActiveCfg = Debug|Any CPU {3562249C-10F4-42C8-BD49-CCF26C51ED8C}.Debug|ARM64.Build.0 = Debug|Any CPU {3562249C-10F4-42C8-BD49-CCF26C51ED8C}.Debug|x64.ActiveCfg = Debug|Any CPU {3562249C-10F4-42C8-BD49-CCF26C51ED8C}.Debug|x64.Build.0 = Debug|Any CPU {3562249C-10F4-42C8-BD49-CCF26C51ED8C}.Debug|x86.ActiveCfg = Debug|Any CPU {3562249C-10F4-42C8-BD49-CCF26C51ED8C}.Debug|x86.Build.0 = Debug|Any CPU {3562249C-10F4-42C8-BD49-CCF26C51ED8C}.Release|Any CPU.ActiveCfg = Release|Any CPU {3562249C-10F4-42C8-BD49-CCF26C51ED8C}.Release|Any CPU.Build.0 = Release|Any CPU {3562249C-10F4-42C8-BD49-CCF26C51ED8C}.Release|ARM.ActiveCfg = Release|Any CPU {3562249C-10F4-42C8-BD49-CCF26C51ED8C}.Release|ARM.Build.0 = Release|Any CPU {3562249C-10F4-42C8-BD49-CCF26C51ED8C}.Release|ARM64.ActiveCfg = Release|Any CPU {3562249C-10F4-42C8-BD49-CCF26C51ED8C}.Release|ARM64.Build.0 = Release|Any CPU {3562249C-10F4-42C8-BD49-CCF26C51ED8C}.Release|x64.ActiveCfg = Release|Any CPU {3562249C-10F4-42C8-BD49-CCF26C51ED8C}.Release|x64.Build.0 = Release|Any CPU {3562249C-10F4-42C8-BD49-CCF26C51ED8C}.Release|x86.ActiveCfg = Release|Any CPU {3562249C-10F4-42C8-BD49-CCF26C51ED8C}.Release|x86.Build.0 = Release|Any CPU {2EBBA423-F963-4CF4-9355-A5B2CE7C699A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2EBBA423-F963-4CF4-9355-A5B2CE7C699A}.Debug|Any CPU.Build.0 = Debug|Any CPU {2EBBA423-F963-4CF4-9355-A5B2CE7C699A}.Debug|ARM.ActiveCfg = Debug|Any CPU {2EBBA423-F963-4CF4-9355-A5B2CE7C699A}.Debug|ARM.Build.0 = Debug|Any CPU {2EBBA423-F963-4CF4-9355-A5B2CE7C699A}.Debug|ARM64.ActiveCfg = Debug|Any CPU {2EBBA423-F963-4CF4-9355-A5B2CE7C699A}.Debug|ARM64.Build.0 = Debug|Any CPU {2EBBA423-F963-4CF4-9355-A5B2CE7C699A}.Debug|x64.ActiveCfg = Debug|Any CPU {2EBBA423-F963-4CF4-9355-A5B2CE7C699A}.Debug|x64.Build.0 = Debug|Any CPU {2EBBA423-F963-4CF4-9355-A5B2CE7C699A}.Debug|x86.ActiveCfg = Debug|Any CPU {2EBBA423-F963-4CF4-9355-A5B2CE7C699A}.Debug|x86.Build.0 = Debug|Any CPU {2EBBA423-F963-4CF4-9355-A5B2CE7C699A}.Release|Any CPU.ActiveCfg = Release|Any CPU {2EBBA423-F963-4CF4-9355-A5B2CE7C699A}.Release|Any CPU.Build.0 = Release|Any CPU {2EBBA423-F963-4CF4-9355-A5B2CE7C699A}.Release|ARM.ActiveCfg = Release|Any CPU {2EBBA423-F963-4CF4-9355-A5B2CE7C699A}.Release|ARM.Build.0 = Release|Any CPU {2EBBA423-F963-4CF4-9355-A5B2CE7C699A}.Release|ARM64.ActiveCfg = Release|Any CPU {2EBBA423-F963-4CF4-9355-A5B2CE7C699A}.Release|ARM64.Build.0 = Release|Any CPU {2EBBA423-F963-4CF4-9355-A5B2CE7C699A}.Release|x64.ActiveCfg = Release|Any CPU {2EBBA423-F963-4CF4-9355-A5B2CE7C699A}.Release|x64.Build.0 = Release|Any CPU {2EBBA423-F963-4CF4-9355-A5B2CE7C699A}.Release|x86.ActiveCfg = Release|Any CPU {2EBBA423-F963-4CF4-9355-A5B2CE7C699A}.Release|x86.Build.0 = Release|Any CPU {F01E685B-AC00-44ED-AF05-D96633B1E31A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F01E685B-AC00-44ED-AF05-D96633B1E31A}.Debug|Any CPU.Build.0 = Debug|Any CPU {F01E685B-AC00-44ED-AF05-D96633B1E31A}.Debug|ARM.ActiveCfg = Debug|Any CPU {F01E685B-AC00-44ED-AF05-D96633B1E31A}.Debug|ARM.Build.0 = Debug|Any CPU {F01E685B-AC00-44ED-AF05-D96633B1E31A}.Debug|ARM64.ActiveCfg = Debug|Any CPU {F01E685B-AC00-44ED-AF05-D96633B1E31A}.Debug|ARM64.Build.0 = Debug|Any CPU {F01E685B-AC00-44ED-AF05-D96633B1E31A}.Debug|x64.ActiveCfg = Debug|Any CPU {F01E685B-AC00-44ED-AF05-D96633B1E31A}.Debug|x64.Build.0 = Debug|Any CPU {F01E685B-AC00-44ED-AF05-D96633B1E31A}.Debug|x86.ActiveCfg = Debug|Any CPU {F01E685B-AC00-44ED-AF05-D96633B1E31A}.Debug|x86.Build.0 = Debug|Any CPU {F01E685B-AC00-44ED-AF05-D96633B1E31A}.Release|Any CPU.ActiveCfg = Release|Any CPU {F01E685B-AC00-44ED-AF05-D96633B1E31A}.Release|Any CPU.Build.0 = Release|Any CPU {F01E685B-AC00-44ED-AF05-D96633B1E31A}.Release|ARM.ActiveCfg = Release|Any CPU {F01E685B-AC00-44ED-AF05-D96633B1E31A}.Release|ARM.Build.0 = Release|Any CPU {F01E685B-AC00-44ED-AF05-D96633B1E31A}.Release|ARM64.ActiveCfg = Release|Any CPU {F01E685B-AC00-44ED-AF05-D96633B1E31A}.Release|ARM64.Build.0 = Release|Any CPU {F01E685B-AC00-44ED-AF05-D96633B1E31A}.Release|x64.ActiveCfg = Release|Any CPU {F01E685B-AC00-44ED-AF05-D96633B1E31A}.Release|x64.Build.0 = Release|Any CPU {F01E685B-AC00-44ED-AF05-D96633B1E31A}.Release|x86.ActiveCfg = Release|Any CPU {F01E685B-AC00-44ED-AF05-D96633B1E31A}.Release|x86.Build.0 = Release|Any CPU {20C76953-78BF-493C-BF15-AB67DC620D82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {20C76953-78BF-493C-BF15-AB67DC620D82}.Debug|Any CPU.Build.0 = Debug|Any CPU {20C76953-78BF-493C-BF15-AB67DC620D82}.Debug|ARM.ActiveCfg = Debug|Any CPU {20C76953-78BF-493C-BF15-AB67DC620D82}.Debug|ARM.Build.0 = Debug|Any CPU {20C76953-78BF-493C-BF15-AB67DC620D82}.Debug|ARM64.ActiveCfg = Debug|Any CPU {20C76953-78BF-493C-BF15-AB67DC620D82}.Debug|ARM64.Build.0 = Debug|Any CPU {20C76953-78BF-493C-BF15-AB67DC620D82}.Debug|x64.ActiveCfg = Debug|Any CPU {20C76953-78BF-493C-BF15-AB67DC620D82}.Debug|x64.Build.0 = Debug|Any CPU {20C76953-78BF-493C-BF15-AB67DC620D82}.Debug|x86.ActiveCfg = Debug|Any CPU {20C76953-78BF-493C-BF15-AB67DC620D82}.Debug|x86.Build.0 = Debug|Any CPU {20C76953-78BF-493C-BF15-AB67DC620D82}.Release|Any CPU.ActiveCfg = Release|Any CPU {20C76953-78BF-493C-BF15-AB67DC620D82}.Release|Any CPU.Build.0 = Release|Any CPU {20C76953-78BF-493C-BF15-AB67DC620D82}.Release|ARM.ActiveCfg = Release|Any CPU {20C76953-78BF-493C-BF15-AB67DC620D82}.Release|ARM.Build.0 = Release|Any CPU {20C76953-78BF-493C-BF15-AB67DC620D82}.Release|ARM64.ActiveCfg = Release|Any CPU {20C76953-78BF-493C-BF15-AB67DC620D82}.Release|ARM64.Build.0 = Release|Any CPU {20C76953-78BF-493C-BF15-AB67DC620D82}.Release|x64.ActiveCfg = Release|Any CPU {20C76953-78BF-493C-BF15-AB67DC620D82}.Release|x64.Build.0 = Release|Any CPU {20C76953-78BF-493C-BF15-AB67DC620D82}.Release|x86.ActiveCfg = Release|Any CPU {20C76953-78BF-493C-BF15-AB67DC620D82}.Release|x86.Build.0 = Release|Any CPU {743EA3B7-51AE-4055-AA6B-A0232142F0C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {743EA3B7-51AE-4055-AA6B-A0232142F0C6}.Debug|Any CPU.Build.0 = Debug|Any CPU {743EA3B7-51AE-4055-AA6B-A0232142F0C6}.Debug|ARM.ActiveCfg = Debug|Any CPU {743EA3B7-51AE-4055-AA6B-A0232142F0C6}.Debug|ARM.Build.0 = Debug|Any CPU {743EA3B7-51AE-4055-AA6B-A0232142F0C6}.Debug|ARM64.ActiveCfg = Debug|Any CPU {743EA3B7-51AE-4055-AA6B-A0232142F0C6}.Debug|ARM64.Build.0 = Debug|Any CPU {743EA3B7-51AE-4055-AA6B-A0232142F0C6}.Debug|x64.ActiveCfg = Debug|Any CPU {743EA3B7-51AE-4055-AA6B-A0232142F0C6}.Debug|x64.Build.0 = Debug|Any CPU {743EA3B7-51AE-4055-AA6B-A0232142F0C6}.Debug|x86.ActiveCfg = Debug|Any CPU {743EA3B7-51AE-4055-AA6B-A0232142F0C6}.Debug|x86.Build.0 = Debug|Any CPU {743EA3B7-51AE-4055-AA6B-A0232142F0C6}.Release|Any CPU.ActiveCfg = Release|Any CPU {743EA3B7-51AE-4055-AA6B-A0232142F0C6}.Release|Any CPU.Build.0 = Release|Any CPU {743EA3B7-51AE-4055-AA6B-A0232142F0C6}.Release|ARM.ActiveCfg = Release|Any CPU {743EA3B7-51AE-4055-AA6B-A0232142F0C6}.Release|ARM.Build.0 = Release|Any CPU {743EA3B7-51AE-4055-AA6B-A0232142F0C6}.Release|ARM64.ActiveCfg = Release|Any CPU {743EA3B7-51AE-4055-AA6B-A0232142F0C6}.Release|ARM64.Build.0 = Release|Any CPU {743EA3B7-51AE-4055-AA6B-A0232142F0C6}.Release|x64.ActiveCfg = Release|Any CPU {743EA3B7-51AE-4055-AA6B-A0232142F0C6}.Release|x64.Build.0 = Release|Any CPU {743EA3B7-51AE-4055-AA6B-A0232142F0C6}.Release|x86.ActiveCfg = Release|Any CPU {743EA3B7-51AE-4055-AA6B-A0232142F0C6}.Release|x86.Build.0 = Release|Any CPU {7958C69B-C7A0-4CC4-8340-5C375E7AA722}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7958C69B-C7A0-4CC4-8340-5C375E7AA722}.Debug|Any CPU.Build.0 = Debug|Any CPU {7958C69B-C7A0-4CC4-8340-5C375E7AA722}.Debug|ARM.ActiveCfg = Debug|Any CPU {7958C69B-C7A0-4CC4-8340-5C375E7AA722}.Debug|ARM.Build.0 = Debug|Any CPU {7958C69B-C7A0-4CC4-8340-5C375E7AA722}.Debug|ARM64.ActiveCfg = Debug|Any CPU {7958C69B-C7A0-4CC4-8340-5C375E7AA722}.Debug|ARM64.Build.0 = Debug|Any CPU {7958C69B-C7A0-4CC4-8340-5C375E7AA722}.Debug|x64.ActiveCfg = Debug|Any CPU {7958C69B-C7A0-4CC4-8340-5C375E7AA722}.Debug|x64.Build.0 = Debug|Any CPU {7958C69B-C7A0-4CC4-8340-5C375E7AA722}.Debug|x86.ActiveCfg = Debug|Any CPU {7958C69B-C7A0-4CC4-8340-5C375E7AA722}.Debug|x86.Build.0 = Debug|Any CPU {7958C69B-C7A0-4CC4-8340-5C375E7AA722}.Release|Any CPU.ActiveCfg = Release|Any CPU {7958C69B-C7A0-4CC4-8340-5C375E7AA722}.Release|Any CPU.Build.0 = Release|Any CPU {7958C69B-C7A0-4CC4-8340-5C375E7AA722}.Release|ARM.ActiveCfg = Release|Any CPU {7958C69B-C7A0-4CC4-8340-5C375E7AA722}.Release|ARM.Build.0 = Release|Any CPU {7958C69B-C7A0-4CC4-8340-5C375E7AA722}.Release|ARM64.ActiveCfg = Release|Any CPU {7958C69B-C7A0-4CC4-8340-5C375E7AA722}.Release|ARM64.Build.0 = Release|Any CPU {7958C69B-C7A0-4CC4-8340-5C375E7AA722}.Release|x64.ActiveCfg = Release|Any CPU {7958C69B-C7A0-4CC4-8340-5C375E7AA722}.Release|x64.Build.0 = Release|Any CPU {7958C69B-C7A0-4CC4-8340-5C375E7AA722}.Release|x86.ActiveCfg = Release|Any CPU {7958C69B-C7A0-4CC4-8340-5C375E7AA722}.Release|x86.Build.0 = Release|Any CPU {532FD258-141B-4FF9-8846-CD8396728E27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {532FD258-141B-4FF9-8846-CD8396728E27}.Debug|Any CPU.Build.0 = Debug|Any CPU {532FD258-141B-4FF9-8846-CD8396728E27}.Debug|ARM.ActiveCfg = Debug|Any CPU {532FD258-141B-4FF9-8846-CD8396728E27}.Debug|ARM.Build.0 = Debug|Any CPU {532FD258-141B-4FF9-8846-CD8396728E27}.Debug|ARM64.ActiveCfg = Debug|Any CPU {532FD258-141B-4FF9-8846-CD8396728E27}.Debug|ARM64.Build.0 = Debug|Any CPU {532FD258-141B-4FF9-8846-CD8396728E27}.Debug|x64.ActiveCfg = Debug|Any CPU {532FD258-141B-4FF9-8846-CD8396728E27}.Debug|x64.Build.0 = Debug|Any CPU {532FD258-141B-4FF9-8846-CD8396728E27}.Debug|x86.ActiveCfg = Debug|Any CPU {532FD258-141B-4FF9-8846-CD8396728E27}.Debug|x86.Build.0 = Debug|Any CPU {532FD258-141B-4FF9-8846-CD8396728E27}.Release|Any CPU.ActiveCfg = Release|Any CPU {532FD258-141B-4FF9-8846-CD8396728E27}.Release|Any CPU.Build.0 = Release|Any CPU {532FD258-141B-4FF9-8846-CD8396728E27}.Release|ARM.ActiveCfg = Release|Any CPU {532FD258-141B-4FF9-8846-CD8396728E27}.Release|ARM.Build.0 = Release|Any CPU {532FD258-141B-4FF9-8846-CD8396728E27}.Release|ARM64.ActiveCfg = Release|Any CPU {532FD258-141B-4FF9-8846-CD8396728E27}.Release|ARM64.Build.0 = Release|Any CPU {532FD258-141B-4FF9-8846-CD8396728E27}.Release|x64.ActiveCfg = Release|Any CPU {532FD258-141B-4FF9-8846-CD8396728E27}.Release|x64.Build.0 = Release|Any CPU {532FD258-141B-4FF9-8846-CD8396728E27}.Release|x86.ActiveCfg = Release|Any CPU {532FD258-141B-4FF9-8846-CD8396728E27}.Release|x86.Build.0 = Release|Any CPU {3B8A071F-EAE4-427F-9CF5-09BFA4F856FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3B8A071F-EAE4-427F-9CF5-09BFA4F856FE}.Debug|Any CPU.Build.0 = Debug|Any CPU {3B8A071F-EAE4-427F-9CF5-09BFA4F856FE}.Debug|ARM.ActiveCfg = Debug|Any CPU {3B8A071F-EAE4-427F-9CF5-09BFA4F856FE}.Debug|ARM.Build.0 = Debug|Any CPU {3B8A071F-EAE4-427F-9CF5-09BFA4F856FE}.Debug|ARM64.ActiveCfg = Debug|Any CPU {3B8A071F-EAE4-427F-9CF5-09BFA4F856FE}.Debug|ARM64.Build.0 = Debug|Any CPU {3B8A071F-EAE4-427F-9CF5-09BFA4F856FE}.Debug|x64.ActiveCfg = Debug|Any CPU {3B8A071F-EAE4-427F-9CF5-09BFA4F856FE}.Debug|x64.Build.0 = Debug|Any CPU {3B8A071F-EAE4-427F-9CF5-09BFA4F856FE}.Debug|x86.ActiveCfg = Debug|Any CPU {3B8A071F-EAE4-427F-9CF5-09BFA4F856FE}.Debug|x86.Build.0 = Debug|Any CPU {3B8A071F-EAE4-427F-9CF5-09BFA4F856FE}.Release|Any CPU.ActiveCfg = Release|Any CPU {3B8A071F-EAE4-427F-9CF5-09BFA4F856FE}.Release|Any CPU.Build.0 = Release|Any CPU {3B8A071F-EAE4-427F-9CF5-09BFA4F856FE}.Release|ARM.ActiveCfg = Release|Any CPU {3B8A071F-EAE4-427F-9CF5-09BFA4F856FE}.Release|ARM.Build.0 = Release|Any CPU {3B8A071F-EAE4-427F-9CF5-09BFA4F856FE}.Release|ARM64.ActiveCfg = Release|Any CPU {3B8A071F-EAE4-427F-9CF5-09BFA4F856FE}.Release|ARM64.Build.0 = Release|Any CPU {3B8A071F-EAE4-427F-9CF5-09BFA4F856FE}.Release|x64.ActiveCfg = Release|Any CPU {3B8A071F-EAE4-427F-9CF5-09BFA4F856FE}.Release|x64.Build.0 = Release|Any CPU {3B8A071F-EAE4-427F-9CF5-09BFA4F856FE}.Release|x86.ActiveCfg = Release|Any CPU {3B8A071F-EAE4-427F-9CF5-09BFA4F856FE}.Release|x86.Build.0 = Release|Any CPU {23550E77-920B-47A2-AE2C-36204BFA9469}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {23550E77-920B-47A2-AE2C-36204BFA9469}.Debug|Any CPU.Build.0 = Debug|Any CPU {23550E77-920B-47A2-AE2C-36204BFA9469}.Debug|ARM.ActiveCfg = Debug|Any CPU {23550E77-920B-47A2-AE2C-36204BFA9469}.Debug|ARM.Build.0 = Debug|Any CPU {23550E77-920B-47A2-AE2C-36204BFA9469}.Debug|ARM64.ActiveCfg = Debug|Any CPU {23550E77-920B-47A2-AE2C-36204BFA9469}.Debug|ARM64.Build.0 = Debug|Any CPU {23550E77-920B-47A2-AE2C-36204BFA9469}.Debug|x64.ActiveCfg = Debug|Any CPU {23550E77-920B-47A2-AE2C-36204BFA9469}.Debug|x64.Build.0 = Debug|Any CPU {23550E77-920B-47A2-AE2C-36204BFA9469}.Debug|x86.ActiveCfg = Debug|Any CPU {23550E77-920B-47A2-AE2C-36204BFA9469}.Debug|x86.Build.0 = Debug|Any CPU {23550E77-920B-47A2-AE2C-36204BFA9469}.Release|Any CPU.ActiveCfg = Release|Any CPU {23550E77-920B-47A2-AE2C-36204BFA9469}.Release|Any CPU.Build.0 = Release|Any CPU {23550E77-920B-47A2-AE2C-36204BFA9469}.Release|ARM.ActiveCfg = Release|Any CPU {23550E77-920B-47A2-AE2C-36204BFA9469}.Release|ARM.Build.0 = Release|Any CPU {23550E77-920B-47A2-AE2C-36204BFA9469}.Release|ARM64.ActiveCfg = Release|Any CPU {23550E77-920B-47A2-AE2C-36204BFA9469}.Release|ARM64.Build.0 = Release|Any CPU {23550E77-920B-47A2-AE2C-36204BFA9469}.Release|x64.ActiveCfg = Release|Any CPU {23550E77-920B-47A2-AE2C-36204BFA9469}.Release|x64.Build.0 = Release|Any CPU {23550E77-920B-47A2-AE2C-36204BFA9469}.Release|x86.ActiveCfg = Release|Any CPU {23550E77-920B-47A2-AE2C-36204BFA9469}.Release|x86.Build.0 = Release|Any CPU {339BEC27-FD38-494E-9D96-7A43DE9B36B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {339BEC27-FD38-494E-9D96-7A43DE9B36B4}.Debug|Any CPU.Build.0 = Debug|Any CPU {339BEC27-FD38-494E-9D96-7A43DE9B36B4}.Debug|ARM.ActiveCfg = Debug|Any CPU {339BEC27-FD38-494E-9D96-7A43DE9B36B4}.Debug|ARM.Build.0 = Debug|Any CPU {339BEC27-FD38-494E-9D96-7A43DE9B36B4}.Debug|ARM64.ActiveCfg = Debug|Any CPU {339BEC27-FD38-494E-9D96-7A43DE9B36B4}.Debug|ARM64.Build.0 = Debug|Any CPU {339BEC27-FD38-494E-9D96-7A43DE9B36B4}.Debug|x64.ActiveCfg = Debug|Any CPU {339BEC27-FD38-494E-9D96-7A43DE9B36B4}.Debug|x64.Build.0 = Debug|Any CPU {339BEC27-FD38-494E-9D96-7A43DE9B36B4}.Debug|x86.ActiveCfg = Debug|Any CPU {339BEC27-FD38-494E-9D96-7A43DE9B36B4}.Debug|x86.Build.0 = Debug|Any CPU {339BEC27-FD38-494E-9D96-7A43DE9B36B4}.Release|Any CPU.ActiveCfg = Release|Any CPU {339BEC27-FD38-494E-9D96-7A43DE9B36B4}.Release|Any CPU.Build.0 = Release|Any CPU {339BEC27-FD38-494E-9D96-7A43DE9B36B4}.Release|ARM.ActiveCfg = Release|Any CPU {339BEC27-FD38-494E-9D96-7A43DE9B36B4}.Release|ARM.Build.0 = Release|Any CPU {339BEC27-FD38-494E-9D96-7A43DE9B36B4}.Release|ARM64.ActiveCfg = Release|Any CPU {339BEC27-FD38-494E-9D96-7A43DE9B36B4}.Release|ARM64.Build.0 = Release|Any CPU {339BEC27-FD38-494E-9D96-7A43DE9B36B4}.Release|x64.ActiveCfg = Release|Any CPU {339BEC27-FD38-494E-9D96-7A43DE9B36B4}.Release|x64.Build.0 = Release|Any CPU {339BEC27-FD38-494E-9D96-7A43DE9B36B4}.Release|x86.ActiveCfg = Release|Any CPU {339BEC27-FD38-494E-9D96-7A43DE9B36B4}.Release|x86.Build.0 = Release|Any CPU {30F209A6-028C-4AF4-A34D-D32B6C0D3572}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {30F209A6-028C-4AF4-A34D-D32B6C0D3572}.Debug|Any CPU.Build.0 = Debug|Any CPU {30F209A6-028C-4AF4-A34D-D32B6C0D3572}.Debug|ARM.ActiveCfg = Debug|Any CPU {30F209A6-028C-4AF4-A34D-D32B6C0D3572}.Debug|ARM.Build.0 = Debug|Any CPU {30F209A6-028C-4AF4-A34D-D32B6C0D3572}.Debug|ARM64.ActiveCfg = Debug|Any CPU {30F209A6-028C-4AF4-A34D-D32B6C0D3572}.Debug|ARM64.Build.0 = Debug|Any CPU {30F209A6-028C-4AF4-A34D-D32B6C0D3572}.Debug|x64.ActiveCfg = Debug|Any CPU {30F209A6-028C-4AF4-A34D-D32B6C0D3572}.Debug|x64.Build.0 = Debug|Any CPU {30F209A6-028C-4AF4-A34D-D32B6C0D3572}.Debug|x86.ActiveCfg = Debug|Any CPU {30F209A6-028C-4AF4-A34D-D32B6C0D3572}.Debug|x86.Build.0 = Debug|Any CPU {30F209A6-028C-4AF4-A34D-D32B6C0D3572}.Release|Any CPU.ActiveCfg = Release|Any CPU {30F209A6-028C-4AF4-A34D-D32B6C0D3572}.Release|Any CPU.Build.0 = Release|Any CPU {30F209A6-028C-4AF4-A34D-D32B6C0D3572}.Release|ARM.ActiveCfg = Release|Any CPU {30F209A6-028C-4AF4-A34D-D32B6C0D3572}.Release|ARM.Build.0 = Release|Any CPU {30F209A6-028C-4AF4-A34D-D32B6C0D3572}.Release|ARM64.ActiveCfg = Release|Any CPU {30F209A6-028C-4AF4-A34D-D32B6C0D3572}.Release|ARM64.Build.0 = Release|Any CPU {30F209A6-028C-4AF4-A34D-D32B6C0D3572}.Release|x64.ActiveCfg = Release|Any CPU {30F209A6-028C-4AF4-A34D-D32B6C0D3572}.Release|x64.Build.0 = Release|Any CPU {30F209A6-028C-4AF4-A34D-D32B6C0D3572}.Release|x86.ActiveCfg = Release|Any CPU {30F209A6-028C-4AF4-A34D-D32B6C0D3572}.Release|x86.Build.0 = Release|Any CPU {BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7}.Debug|Any CPU.Build.0 = Debug|Any CPU {BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7}.Debug|ARM.ActiveCfg = Debug|Any CPU {BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7}.Debug|ARM.Build.0 = Debug|Any CPU {BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7}.Debug|ARM64.ActiveCfg = Debug|Any CPU {BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7}.Debug|ARM64.Build.0 = Debug|Any CPU {BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7}.Debug|x64.ActiveCfg = Debug|Any CPU {BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7}.Debug|x64.Build.0 = Debug|Any CPU {BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7}.Debug|x86.ActiveCfg = Debug|Any CPU {BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7}.Debug|x86.Build.0 = Debug|Any CPU {BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7}.Release|Any CPU.ActiveCfg = Release|Any CPU {BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7}.Release|Any CPU.Build.0 = Release|Any CPU {BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7}.Release|ARM.ActiveCfg = Release|Any CPU {BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7}.Release|ARM.Build.0 = Release|Any CPU {BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7}.Release|ARM64.ActiveCfg = Release|Any CPU {BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7}.Release|ARM64.Build.0 = Release|Any CPU {BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7}.Release|x64.ActiveCfg = Release|Any CPU {BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7}.Release|x64.Build.0 = Release|Any CPU {BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7}.Release|x86.ActiveCfg = Release|Any CPU {BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7}.Release|x86.Build.0 = Release|Any CPU {1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5}.Debug|Any CPU.Build.0 = Debug|Any CPU {1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5}.Debug|ARM.ActiveCfg = Debug|Any CPU {1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5}.Debug|ARM.Build.0 = Debug|Any CPU {1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5}.Debug|ARM64.ActiveCfg = Debug|Any CPU {1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5}.Debug|ARM64.Build.0 = Debug|Any CPU {1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5}.Debug|x64.ActiveCfg = Debug|Any CPU {1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5}.Debug|x64.Build.0 = Debug|Any CPU {1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5}.Debug|x86.ActiveCfg = Debug|Any CPU {1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5}.Debug|x86.Build.0 = Debug|Any CPU {1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5}.Release|Any CPU.ActiveCfg = Release|Any CPU {1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5}.Release|Any CPU.Build.0 = Release|Any CPU {1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5}.Release|ARM.ActiveCfg = Release|Any CPU {1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5}.Release|ARM.Build.0 = Release|Any CPU {1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5}.Release|ARM64.ActiveCfg = Release|Any CPU {1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5}.Release|ARM64.Build.0 = Release|Any CPU {1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5}.Release|x64.ActiveCfg = Release|Any CPU {1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5}.Release|x64.Build.0 = Release|Any CPU {1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5}.Release|x86.ActiveCfg = Release|Any CPU {1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5}.Release|x86.Build.0 = Release|Any CPU {AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE}.Debug|Any CPU.Build.0 = Debug|Any CPU {AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE}.Debug|ARM.ActiveCfg = Debug|Any CPU {AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE}.Debug|ARM.Build.0 = Debug|Any CPU {AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE}.Debug|ARM64.ActiveCfg = Debug|Any CPU {AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE}.Debug|ARM64.Build.0 = Debug|Any CPU {AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE}.Debug|x64.ActiveCfg = Debug|Any CPU {AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE}.Debug|x64.Build.0 = Debug|Any CPU {AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE}.Debug|x86.ActiveCfg = Debug|Any CPU {AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE}.Debug|x86.Build.0 = Debug|Any CPU {AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE}.Release|Any CPU.ActiveCfg = Release|Any CPU {AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE}.Release|Any CPU.Build.0 = Release|Any CPU {AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE}.Release|ARM.ActiveCfg = Release|Any CPU {AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE}.Release|ARM.Build.0 = Release|Any CPU {AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE}.Release|ARM64.ActiveCfg = Release|Any CPU {AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE}.Release|ARM64.Build.0 = Release|Any CPU {AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE}.Release|x64.ActiveCfg = Release|Any CPU {AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE}.Release|x64.Build.0 = Release|Any CPU {AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE}.Release|x86.ActiveCfg = Release|Any CPU {AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE}.Release|x86.Build.0 = Release|Any CPU {24D92E73-9429-48AD-A805-25CE7AF84D50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {24D92E73-9429-48AD-A805-25CE7AF84D50}.Debug|Any CPU.Build.0 = Debug|Any CPU {24D92E73-9429-48AD-A805-25CE7AF84D50}.Debug|ARM.ActiveCfg = Debug|Any CPU {24D92E73-9429-48AD-A805-25CE7AF84D50}.Debug|ARM.Build.0 = Debug|Any CPU {24D92E73-9429-48AD-A805-25CE7AF84D50}.Debug|ARM64.ActiveCfg = Debug|Any CPU {24D92E73-9429-48AD-A805-25CE7AF84D50}.Debug|ARM64.Build.0 = Debug|Any CPU {24D92E73-9429-48AD-A805-25CE7AF84D50}.Debug|x64.ActiveCfg = Debug|Any CPU {24D92E73-9429-48AD-A805-25CE7AF84D50}.Debug|x64.Build.0 = Debug|Any CPU {24D92E73-9429-48AD-A805-25CE7AF84D50}.Debug|x86.ActiveCfg = Debug|Any CPU {24D92E73-9429-48AD-A805-25CE7AF84D50}.Debug|x86.Build.0 = Debug|Any CPU {24D92E73-9429-48AD-A805-25CE7AF84D50}.Release|Any CPU.ActiveCfg = Release|Any CPU {24D92E73-9429-48AD-A805-25CE7AF84D50}.Release|Any CPU.Build.0 = Release|Any CPU {24D92E73-9429-48AD-A805-25CE7AF84D50}.Release|ARM.ActiveCfg = Release|Any CPU {24D92E73-9429-48AD-A805-25CE7AF84D50}.Release|ARM.Build.0 = Release|Any CPU {24D92E73-9429-48AD-A805-25CE7AF84D50}.Release|ARM64.ActiveCfg = Release|Any CPU {24D92E73-9429-48AD-A805-25CE7AF84D50}.Release|ARM64.Build.0 = Release|Any CPU {24D92E73-9429-48AD-A805-25CE7AF84D50}.Release|x64.ActiveCfg = Release|Any CPU {24D92E73-9429-48AD-A805-25CE7AF84D50}.Release|x64.Build.0 = Release|Any CPU {24D92E73-9429-48AD-A805-25CE7AF84D50}.Release|x86.ActiveCfg = Release|Any CPU {24D92E73-9429-48AD-A805-25CE7AF84D50}.Release|x86.Build.0 = Release|Any CPU {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}.Debug|Any CPU.Build.0 = Debug|Any CPU {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}.Debug|Any CPU.Deploy.0 = Debug|Any CPU {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}.Debug|ARM.ActiveCfg = Debug|Any CPU {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}.Debug|ARM.Build.0 = Debug|Any CPU {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}.Debug|ARM64.ActiveCfg = Debug|Any CPU {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}.Debug|ARM64.Build.0 = Debug|Any CPU {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}.Debug|x64.ActiveCfg = Debug|Any CPU {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}.Debug|x64.Build.0 = Debug|Any CPU {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}.Debug|x86.ActiveCfg = Debug|Any CPU {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}.Debug|x86.Build.0 = Debug|Any CPU {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}.Release|Any CPU.ActiveCfg = Release|Any CPU {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}.Release|Any CPU.Build.0 = Release|Any CPU {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}.Release|ARM.ActiveCfg = Release|Any CPU {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}.Release|ARM.Build.0 = Release|Any CPU {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}.Release|ARM64.ActiveCfg = Release|Any CPU {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}.Release|ARM64.Build.0 = Release|Any CPU {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}.Release|x64.ActiveCfg = Release|Any CPU {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}.Release|x64.Build.0 = Release|Any CPU {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}.Release|x86.ActiveCfg = Release|Any CPU {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0}.Release|x86.Build.0 = Release|Any CPU {08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5}.Debug|Any CPU.Build.0 = Debug|Any CPU {08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5}.Debug|ARM.ActiveCfg = Debug|Any CPU {08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5}.Debug|ARM.Build.0 = Debug|Any CPU {08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5}.Debug|ARM64.ActiveCfg = Debug|Any CPU {08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5}.Debug|ARM64.Build.0 = Debug|Any CPU {08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5}.Debug|x64.ActiveCfg = Debug|Any CPU {08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5}.Debug|x64.Build.0 = Debug|Any CPU {08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5}.Debug|x86.ActiveCfg = Debug|Any CPU {08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5}.Debug|x86.Build.0 = Debug|Any CPU {08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5}.Release|Any CPU.ActiveCfg = Release|Any CPU {08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5}.Release|Any CPU.Build.0 = Release|Any CPU {08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5}.Release|ARM.ActiveCfg = Release|Any CPU {08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5}.Release|ARM.Build.0 = Release|Any CPU {08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5}.Release|ARM64.ActiveCfg = Release|Any CPU {08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5}.Release|ARM64.Build.0 = Release|Any CPU {08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5}.Release|x64.ActiveCfg = Release|Any CPU {08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5}.Release|x64.Build.0 = Release|Any CPU {08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5}.Release|x86.ActiveCfg = Release|Any CPU {08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5}.Release|x86.Build.0 = Release|Any CPU {DB400AC5-91AB-4621-9E12-6EF27BFE9D2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DB400AC5-91AB-4621-9E12-6EF27BFE9D2B}.Debug|Any CPU.Build.0 = Debug|Any CPU {DB400AC5-91AB-4621-9E12-6EF27BFE9D2B}.Debug|ARM.ActiveCfg = Debug|Any CPU {DB400AC5-91AB-4621-9E12-6EF27BFE9D2B}.Debug|ARM.Build.0 = Debug|Any CPU {DB400AC5-91AB-4621-9E12-6EF27BFE9D2B}.Debug|ARM64.ActiveCfg = Debug|Any CPU {DB400AC5-91AB-4621-9E12-6EF27BFE9D2B}.Debug|ARM64.Build.0 = Debug|Any CPU {DB400AC5-91AB-4621-9E12-6EF27BFE9D2B}.Debug|x64.ActiveCfg = Debug|Any CPU {DB400AC5-91AB-4621-9E12-6EF27BFE9D2B}.Debug|x64.Build.0 = Debug|Any CPU {DB400AC5-91AB-4621-9E12-6EF27BFE9D2B}.Debug|x86.ActiveCfg = Debug|Any CPU {DB400AC5-91AB-4621-9E12-6EF27BFE9D2B}.Debug|x86.Build.0 = Debug|Any CPU {DB400AC5-91AB-4621-9E12-6EF27BFE9D2B}.Release|Any CPU.ActiveCfg = Release|Any CPU {DB400AC5-91AB-4621-9E12-6EF27BFE9D2B}.Release|Any CPU.Build.0 = Release|Any CPU {DB400AC5-91AB-4621-9E12-6EF27BFE9D2B}.Release|ARM.ActiveCfg = Release|Any CPU {DB400AC5-91AB-4621-9E12-6EF27BFE9D2B}.Release|ARM.Build.0 = Release|Any CPU {DB400AC5-91AB-4621-9E12-6EF27BFE9D2B}.Release|ARM64.ActiveCfg = Release|Any CPU {DB400AC5-91AB-4621-9E12-6EF27BFE9D2B}.Release|ARM64.Build.0 = Release|Any CPU {DB400AC5-91AB-4621-9E12-6EF27BFE9D2B}.Release|x64.ActiveCfg = Release|Any CPU {DB400AC5-91AB-4621-9E12-6EF27BFE9D2B}.Release|x64.Build.0 = Release|Any CPU {DB400AC5-91AB-4621-9E12-6EF27BFE9D2B}.Release|x86.ActiveCfg = Release|Any CPU {DB400AC5-91AB-4621-9E12-6EF27BFE9D2B}.Release|x86.Build.0 = Release|Any CPU {A8ADB3BE-683C-44FD-9C59-53F5B6B60A26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A8ADB3BE-683C-44FD-9C59-53F5B6B60A26}.Debug|Any CPU.Build.0 = Debug|Any CPU {A8ADB3BE-683C-44FD-9C59-53F5B6B60A26}.Debug|ARM.ActiveCfg = Debug|Any CPU {A8ADB3BE-683C-44FD-9C59-53F5B6B60A26}.Debug|ARM.Build.0 = Debug|Any CPU {A8ADB3BE-683C-44FD-9C59-53F5B6B60A26}.Debug|ARM64.ActiveCfg = Debug|Any CPU {A8ADB3BE-683C-44FD-9C59-53F5B6B60A26}.Debug|ARM64.Build.0 = Debug|Any CPU {A8ADB3BE-683C-44FD-9C59-53F5B6B60A26}.Debug|x64.ActiveCfg = Debug|Any CPU {A8ADB3BE-683C-44FD-9C59-53F5B6B60A26}.Debug|x64.Build.0 = Debug|Any CPU {A8ADB3BE-683C-44FD-9C59-53F5B6B60A26}.Debug|x86.ActiveCfg = Debug|Any CPU {A8ADB3BE-683C-44FD-9C59-53F5B6B60A26}.Debug|x86.Build.0 = Debug|Any CPU {A8ADB3BE-683C-44FD-9C59-53F5B6B60A26}.Release|Any CPU.ActiveCfg = Release|Any CPU {A8ADB3BE-683C-44FD-9C59-53F5B6B60A26}.Release|Any CPU.Build.0 = Release|Any CPU {A8ADB3BE-683C-44FD-9C59-53F5B6B60A26}.Release|ARM.ActiveCfg = Release|Any CPU {A8ADB3BE-683C-44FD-9C59-53F5B6B60A26}.Release|ARM.Build.0 = Release|Any CPU {A8ADB3BE-683C-44FD-9C59-53F5B6B60A26}.Release|ARM64.ActiveCfg = Release|Any CPU {A8ADB3BE-683C-44FD-9C59-53F5B6B60A26}.Release|ARM64.Build.0 = Release|Any CPU {A8ADB3BE-683C-44FD-9C59-53F5B6B60A26}.Release|x64.ActiveCfg = Release|Any CPU {A8ADB3BE-683C-44FD-9C59-53F5B6B60A26}.Release|x64.Build.0 = Release|Any CPU {A8ADB3BE-683C-44FD-9C59-53F5B6B60A26}.Release|x86.ActiveCfg = Release|Any CPU {A8ADB3BE-683C-44FD-9C59-53F5B6B60A26}.Release|x86.Build.0 = Release|Any CPU {F03BD8DB-9247-4977-A4AB-C98FE071294A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F03BD8DB-9247-4977-A4AB-C98FE071294A}.Debug|Any CPU.Build.0 = Debug|Any CPU {F03BD8DB-9247-4977-A4AB-C98FE071294A}.Debug|ARM.ActiveCfg = Debug|Any CPU {F03BD8DB-9247-4977-A4AB-C98FE071294A}.Debug|ARM.Build.0 = Debug|Any CPU {F03BD8DB-9247-4977-A4AB-C98FE071294A}.Debug|ARM64.ActiveCfg = Debug|Any CPU {F03BD8DB-9247-4977-A4AB-C98FE071294A}.Debug|ARM64.Build.0 = Debug|Any CPU {F03BD8DB-9247-4977-A4AB-C98FE071294A}.Debug|x64.ActiveCfg = Debug|Any CPU {F03BD8DB-9247-4977-A4AB-C98FE071294A}.Debug|x64.Build.0 = Debug|Any CPU {F03BD8DB-9247-4977-A4AB-C98FE071294A}.Debug|x86.ActiveCfg = Debug|Any CPU {F03BD8DB-9247-4977-A4AB-C98FE071294A}.Debug|x86.Build.0 = Debug|Any CPU {F03BD8DB-9247-4977-A4AB-C98FE071294A}.Release|Any CPU.ActiveCfg = Release|Any CPU {F03BD8DB-9247-4977-A4AB-C98FE071294A}.Release|Any CPU.Build.0 = Release|Any CPU {F03BD8DB-9247-4977-A4AB-C98FE071294A}.Release|ARM.ActiveCfg = Release|Any CPU {F03BD8DB-9247-4977-A4AB-C98FE071294A}.Release|ARM.Build.0 = Release|Any CPU {F03BD8DB-9247-4977-A4AB-C98FE071294A}.Release|ARM64.ActiveCfg = Release|Any CPU {F03BD8DB-9247-4977-A4AB-C98FE071294A}.Release|ARM64.Build.0 = Release|Any CPU {F03BD8DB-9247-4977-A4AB-C98FE071294A}.Release|x64.ActiveCfg = Release|Any CPU {F03BD8DB-9247-4977-A4AB-C98FE071294A}.Release|x64.Build.0 = Release|Any CPU {F03BD8DB-9247-4977-A4AB-C98FE071294A}.Release|x86.ActiveCfg = Release|Any CPU {F03BD8DB-9247-4977-A4AB-C98FE071294A}.Release|x86.Build.0 = Release|Any CPU {3D577143-DEEA-42A4-B261-9A0846E537EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3D577143-DEEA-42A4-B261-9A0846E537EF}.Debug|Any CPU.Build.0 = Debug|Any CPU {3D577143-DEEA-42A4-B261-9A0846E537EF}.Debug|ARM.ActiveCfg = Debug|Any CPU {3D577143-DEEA-42A4-B261-9A0846E537EF}.Debug|ARM.Build.0 = Debug|Any CPU {3D577143-DEEA-42A4-B261-9A0846E537EF}.Debug|ARM64.ActiveCfg = Debug|Any CPU {3D577143-DEEA-42A4-B261-9A0846E537EF}.Debug|ARM64.Build.0 = Debug|Any CPU {3D577143-DEEA-42A4-B261-9A0846E537EF}.Debug|x64.ActiveCfg = Debug|Any CPU {3D577143-DEEA-42A4-B261-9A0846E537EF}.Debug|x64.Build.0 = Debug|Any CPU {3D577143-DEEA-42A4-B261-9A0846E537EF}.Debug|x86.ActiveCfg = Debug|Any CPU {3D577143-DEEA-42A4-B261-9A0846E537EF}.Debug|x86.Build.0 = Debug|Any CPU {3D577143-DEEA-42A4-B261-9A0846E537EF}.Release|Any CPU.ActiveCfg = Release|Any CPU {3D577143-DEEA-42A4-B261-9A0846E537EF}.Release|Any CPU.Build.0 = Release|Any CPU {3D577143-DEEA-42A4-B261-9A0846E537EF}.Release|ARM.ActiveCfg = Release|Any CPU {3D577143-DEEA-42A4-B261-9A0846E537EF}.Release|ARM.Build.0 = Release|Any CPU {3D577143-DEEA-42A4-B261-9A0846E537EF}.Release|ARM64.ActiveCfg = Release|Any CPU {3D577143-DEEA-42A4-B261-9A0846E537EF}.Release|ARM64.Build.0 = Release|Any CPU {3D577143-DEEA-42A4-B261-9A0846E537EF}.Release|x64.ActiveCfg = Release|Any CPU {3D577143-DEEA-42A4-B261-9A0846E537EF}.Release|x64.Build.0 = Release|Any CPU {3D577143-DEEA-42A4-B261-9A0846E537EF}.Release|x86.ActiveCfg = Release|Any CPU {3D577143-DEEA-42A4-B261-9A0846E537EF}.Release|x86.Build.0 = Release|Any CPU {C9971FF8-3695-457F-8A78-CBDD098617D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C9971FF8-3695-457F-8A78-CBDD098617D7}.Debug|Any CPU.Build.0 = Debug|Any CPU {C9971FF8-3695-457F-8A78-CBDD098617D7}.Debug|ARM.ActiveCfg = Debug|Any CPU {C9971FF8-3695-457F-8A78-CBDD098617D7}.Debug|ARM.Build.0 = Debug|Any CPU {C9971FF8-3695-457F-8A78-CBDD098617D7}.Debug|ARM64.ActiveCfg = Debug|Any CPU {C9971FF8-3695-457F-8A78-CBDD098617D7}.Debug|ARM64.Build.0 = Debug|Any CPU {C9971FF8-3695-457F-8A78-CBDD098617D7}.Debug|x64.ActiveCfg = Debug|Any CPU {C9971FF8-3695-457F-8A78-CBDD098617D7}.Debug|x64.Build.0 = Debug|Any CPU {C9971FF8-3695-457F-8A78-CBDD098617D7}.Debug|x86.ActiveCfg = Debug|Any CPU {C9971FF8-3695-457F-8A78-CBDD098617D7}.Debug|x86.Build.0 = Debug|Any CPU {C9971FF8-3695-457F-8A78-CBDD098617D7}.Release|Any CPU.ActiveCfg = Release|Any CPU {C9971FF8-3695-457F-8A78-CBDD098617D7}.Release|Any CPU.Build.0 = Release|Any CPU {C9971FF8-3695-457F-8A78-CBDD098617D7}.Release|ARM.ActiveCfg = Release|Any CPU {C9971FF8-3695-457F-8A78-CBDD098617D7}.Release|ARM.Build.0 = Release|Any CPU {C9971FF8-3695-457F-8A78-CBDD098617D7}.Release|ARM64.ActiveCfg = Release|Any CPU {C9971FF8-3695-457F-8A78-CBDD098617D7}.Release|ARM64.Build.0 = Release|Any CPU {C9971FF8-3695-457F-8A78-CBDD098617D7}.Release|x64.ActiveCfg = Release|Any CPU {C9971FF8-3695-457F-8A78-CBDD098617D7}.Release|x64.Build.0 = Release|Any CPU {C9971FF8-3695-457F-8A78-CBDD098617D7}.Release|x86.ActiveCfg = Release|Any CPU {C9971FF8-3695-457F-8A78-CBDD098617D7}.Release|x86.Build.0 = Release|Any CPU {86D96E8C-F62A-4563-AFEF-1907F9280D7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {86D96E8C-F62A-4563-AFEF-1907F9280D7D}.Debug|Any CPU.Build.0 = Debug|Any CPU {86D96E8C-F62A-4563-AFEF-1907F9280D7D}.Debug|ARM.ActiveCfg = Debug|Any CPU {86D96E8C-F62A-4563-AFEF-1907F9280D7D}.Debug|ARM.Build.0 = Debug|Any CPU {86D96E8C-F62A-4563-AFEF-1907F9280D7D}.Debug|ARM64.ActiveCfg = Debug|Any CPU {86D96E8C-F62A-4563-AFEF-1907F9280D7D}.Debug|ARM64.Build.0 = Debug|Any CPU {86D96E8C-F62A-4563-AFEF-1907F9280D7D}.Debug|x64.ActiveCfg = Debug|Any CPU {86D96E8C-F62A-4563-AFEF-1907F9280D7D}.Debug|x64.Build.0 = Debug|Any CPU {86D96E8C-F62A-4563-AFEF-1907F9280D7D}.Debug|x86.ActiveCfg = Debug|Any CPU {86D96E8C-F62A-4563-AFEF-1907F9280D7D}.Debug|x86.Build.0 = Debug|Any CPU {86D96E8C-F62A-4563-AFEF-1907F9280D7D}.Release|Any CPU.ActiveCfg = Release|Any CPU {86D96E8C-F62A-4563-AFEF-1907F9280D7D}.Release|Any CPU.Build.0 = Release|Any CPU {86D96E8C-F62A-4563-AFEF-1907F9280D7D}.Release|ARM.ActiveCfg = Release|Any CPU {86D96E8C-F62A-4563-AFEF-1907F9280D7D}.Release|ARM.Build.0 = Release|Any CPU {86D96E8C-F62A-4563-AFEF-1907F9280D7D}.Release|ARM64.ActiveCfg = Release|Any CPU {86D96E8C-F62A-4563-AFEF-1907F9280D7D}.Release|ARM64.Build.0 = Release|Any CPU {86D96E8C-F62A-4563-AFEF-1907F9280D7D}.Release|x64.ActiveCfg = Release|Any CPU {86D96E8C-F62A-4563-AFEF-1907F9280D7D}.Release|x64.Build.0 = Release|Any CPU {86D96E8C-F62A-4563-AFEF-1907F9280D7D}.Release|x86.ActiveCfg = Release|Any CPU {86D96E8C-F62A-4563-AFEF-1907F9280D7D}.Release|x86.Build.0 = Release|Any CPU {84D06F7E-6381-7653-27C1-4FF4A0232C92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {84D06F7E-6381-7653-27C1-4FF4A0232C92}.Debug|Any CPU.Build.0 = Debug|Any CPU {84D06F7E-6381-7653-27C1-4FF4A0232C92}.Debug|ARM.ActiveCfg = Debug|Any CPU {84D06F7E-6381-7653-27C1-4FF4A0232C92}.Debug|ARM.Build.0 = Debug|Any CPU {84D06F7E-6381-7653-27C1-4FF4A0232C92}.Debug|ARM64.ActiveCfg = Debug|Any CPU {84D06F7E-6381-7653-27C1-4FF4A0232C92}.Debug|ARM64.Build.0 = Debug|Any CPU {84D06F7E-6381-7653-27C1-4FF4A0232C92}.Debug|x64.ActiveCfg = Debug|Any CPU {84D06F7E-6381-7653-27C1-4FF4A0232C92}.Debug|x64.Build.0 = Debug|Any CPU {84D06F7E-6381-7653-27C1-4FF4A0232C92}.Debug|x86.ActiveCfg = Debug|Any CPU {84D06F7E-6381-7653-27C1-4FF4A0232C92}.Debug|x86.Build.0 = Debug|Any CPU {84D06F7E-6381-7653-27C1-4FF4A0232C92}.Release|Any CPU.ActiveCfg = Release|Any CPU {84D06F7E-6381-7653-27C1-4FF4A0232C92}.Release|Any CPU.Build.0 = Release|Any CPU {84D06F7E-6381-7653-27C1-4FF4A0232C92}.Release|ARM.ActiveCfg = Release|Any CPU {84D06F7E-6381-7653-27C1-4FF4A0232C92}.Release|ARM.Build.0 = Release|Any CPU {84D06F7E-6381-7653-27C1-4FF4A0232C92}.Release|ARM64.ActiveCfg = Release|Any CPU {84D06F7E-6381-7653-27C1-4FF4A0232C92}.Release|ARM64.Build.0 = Release|Any CPU {84D06F7E-6381-7653-27C1-4FF4A0232C92}.Release|x64.ActiveCfg = Release|Any CPU {84D06F7E-6381-7653-27C1-4FF4A0232C92}.Release|x64.Build.0 = Release|Any CPU {84D06F7E-6381-7653-27C1-4FF4A0232C92}.Release|x86.ActiveCfg = Release|Any CPU {84D06F7E-6381-7653-27C1-4FF4A0232C92}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {0A8EF671-0277-4F7A-B03D-C6E227020E86} = {62592C78-61AA-44B4-A7C3-EAC678A568A2} {ED5001B1-A78B-4881-9BD8-CB56DD930585} = {0A8EF671-0277-4F7A-B03D-C6E227020E86} {A6ABFE78-566C-4534-947E-BEFB86BDA347} = {0A8EF671-0277-4F7A-B03D-C6E227020E86} {AD1F57E0-055A-4838-91AD-B824BF17E481} = {0A8EF671-0277-4F7A-B03D-C6E227020E86} {F2CAA958-5A0E-4BB3-B624-B8360C5F2978} = {0A8EF671-0277-4F7A-B03D-C6E227020E86} {DD760082-E0FA-433F-A1D0-D05F5D91FFA9} = {0A8EF671-0277-4F7A-B03D-C6E227020E86} {74041466-C4C6-4396-8B57-D176CF5C0FD9} = {0A8EF671-0277-4F7A-B03D-C6E227020E86} {33BC9402-331E-47B5-8EE8-4F15AF463D12} = {0A8EF671-0277-4F7A-B03D-C6E227020E86} {62E90DFE-FF71-4558-A33E-361BFE60BF9D} = {0A8EF671-0277-4F7A-B03D-C6E227020E86} {CABB5675-02EF-42A7-A2C9-E4F37D66D12B} = {0A8EF671-0277-4F7A-B03D-C6E227020E86} {0848A1AE-3147-432C-B473-44EE2CBA2E57} = {958591BB-32C1-48C4-B5FA-11A2C5686814} {E14F830F-2A00-46D0-B25B-B3D675E86B02} = {958591BB-32C1-48C4-B5FA-11A2C5686814} {32D9C89C-9D88-40F9-A05D-CD95F05F38D0} = {958591BB-32C1-48C4-B5FA-11A2C5686814} {0CAFC532-721B-4CD0-B4CA-AF10F07BFD76} = {62592C78-61AA-44B4-A7C3-EAC678A568A2} {26E80F33-67D7-4F29-87E4-DFA45FBCF6B3} = {0CAFC532-721B-4CD0-B4CA-AF10F07BFD76} {ADB64CA1-52F9-47B9-AC03-975D2C9E4022} = {0CAFC532-721B-4CD0-B4CA-AF10F07BFD76} {89BFF856-E543-4EB5-B443-78B30D818D57} = {0CAFC532-721B-4CD0-B4CA-AF10F07BFD76} {4D578475-512F-43C5-9AF4-F8A8578732CE} = {0CAFC532-721B-4CD0-B4CA-AF10F07BFD76} {61F454B7-9F32-4CBA-8FE5-02B44D5CF25C} = {0CAFC532-721B-4CD0-B4CA-AF10F07BFD76} {1E02BE6D-9F98-4343-930C-588CCB9A1296} = {0CAFC532-721B-4CD0-B4CA-AF10F07BFD76} {3D4F7533-B6B3-4F96-8794-F80A96EAB34E} = {0CAFC532-721B-4CD0-B4CA-AF10F07BFD76} {CC35BEDB-96DB-452C-BDDB-3D90169F8313} = {0CAFC532-721B-4CD0-B4CA-AF10F07BFD76} {27684F10-FC43-4868-80B3-9D1840E4CF54} = {0A8EF671-0277-4F7A-B03D-C6E227020E86} {3562249C-10F4-42C8-BD49-CCF26C51ED8C} = {0A8EF671-0277-4F7A-B03D-C6E227020E86} {2EBBA423-F963-4CF4-9355-A5B2CE7C699A} = {0CAFC532-721B-4CD0-B4CA-AF10F07BFD76} {F01E685B-AC00-44ED-AF05-D96633B1E31A} = {0CAFC532-721B-4CD0-B4CA-AF10F07BFD76} {20C76953-78BF-493C-BF15-AB67DC620D82} = {0CAFC532-721B-4CD0-B4CA-AF10F07BFD76} {743EA3B7-51AE-4055-AA6B-A0232142F0C6} = {0A8EF671-0277-4F7A-B03D-C6E227020E86} {7958C69B-C7A0-4CC4-8340-5C375E7AA722} = {958591BB-32C1-48C4-B5FA-11A2C5686814} {532FD258-141B-4FF9-8846-CD8396728E27} = {958591BB-32C1-48C4-B5FA-11A2C5686814} {3B8A071F-EAE4-427F-9CF5-09BFA4F856FE} = {0CAFC532-721B-4CD0-B4CA-AF10F07BFD76} {23550E77-920B-47A2-AE2C-36204BFA9469} = {0CAFC532-721B-4CD0-B4CA-AF10F07BFD76} {339BEC27-FD38-494E-9D96-7A43DE9B36B4} = {0CAFC532-721B-4CD0-B4CA-AF10F07BFD76} {30F209A6-028C-4AF4-A34D-D32B6C0D3572} = {0CAFC532-721B-4CD0-B4CA-AF10F07BFD76} {BA8764EF-2FA6-43C8-8FAA-ABBA8CFA1CD7} = {0CAFC532-721B-4CD0-B4CA-AF10F07BFD76} {1FA1B0CC-DC5D-4327-B7B9-FEC7C12F88D5} = {0A8EF671-0277-4F7A-B03D-C6E227020E86} {B90D3DCC-669D-4583-8BA0-682EB1F93BD2} = {62592C78-61AA-44B4-A7C3-EAC678A568A2} {AD2BE2F7-5D94-4E1C-AA4F-5F69B160B4CE} = {958591BB-32C1-48C4-B5FA-11A2C5686814} {24D92E73-9429-48AD-A805-25CE7AF84D50} = {B90D3DCC-669D-4583-8BA0-682EB1F93BD2} {497C1B3B-3326-45DB-BC0B-76C3EDAA26E0} = {B90D3DCC-669D-4583-8BA0-682EB1F93BD2} {08A1F54A-676B-4A9A-BE41-9BE1A21EC2C5} = {B90D3DCC-669D-4583-8BA0-682EB1F93BD2} {DB400AC5-91AB-4621-9E12-6EF27BFE9D2B} = {B90D3DCC-669D-4583-8BA0-682EB1F93BD2} {A8ADB3BE-683C-44FD-9C59-53F5B6B60A26} = {B90D3DCC-669D-4583-8BA0-682EB1F93BD2} {F03BD8DB-9247-4977-A4AB-C98FE071294A} = {0CAFC532-721B-4CD0-B4CA-AF10F07BFD76} {3D577143-DEEA-42A4-B261-9A0846E537EF} = {0A8EF671-0277-4F7A-B03D-C6E227020E86} {C9971FF8-3695-457F-8A78-CBDD098617D7} = {958591BB-32C1-48C4-B5FA-11A2C5686814} {86D96E8C-F62A-4563-AFEF-1907F9280D7D} = {0CAFC532-721B-4CD0-B4CA-AF10F07BFD76} {84D06F7E-6381-7653-27C1-4FF4A0232C92} = {0CAFC532-721B-4CD0-B4CA-AF10F07BFD76} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {983A22B3-AE5B-4B67-A798-F6A6697B82A8} EndGlobalSection EndGlobal ================================================ FILE: MvvmDialogs.sln.DotSettings ================================================  True True True False SOLUTION True SUGGESTION HINT HINT HINT ERROR ERROR ERROR ERROR ERROR ERROR ERROR HINT WARNING SUGGESTION ERROR ERROR ERROR ERROR ERROR ERROR ERROR WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ERROR DO_NOT_SHOW SUGGESTION SUGGESTION HINT ERROR ERROR SUGGESTION False False False False False False NEXT_LINE 0 0 0 0 0 0 NEXT_LINE 1 NEXT_LINE 1 1 False 1 NEVER False False NEVER NEVER False False LINE_BREAK False True True False False True True True CHOP_IF_LONG 180 CHOP_IF_LONG True True False 140 True Automatic property True False False CF IO OK UI <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="I" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="T" Suffix="" Style="AaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"><ElementKinds><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /></Policy> <Policy><Descriptor Staticness="Any" AccessRightKinds="Private" Description="Constant fields (private)"><ElementKinds><Kind Name="CONSTANT_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /></Policy> <Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Type parameters"><ElementKinds><Kind Name="TYPE_PARAMETER" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="T" Suffix="" Style="AaBb" /></Policy> <Policy><Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"><ElementKinds><Kind Name="FIELD" /><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aaBb" /></Policy> <Policy><Descriptor Staticness="Instance" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Instance fields (not private)"><ElementKinds><Kind Name="FIELD" /><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /></Policy> <Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Local variables"><ElementKinds><Kind Name="LOCAL_VARIABLE" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aaBb" /></Policy> <Policy><Descriptor Staticness="Any" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Constant fields (not private)"><ElementKinds><Kind Name="CONSTANT_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /></Policy> <Policy><Descriptor Staticness="Static" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Static fields (not private)"><ElementKinds><Kind Name="FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /></Policy> <Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Parameters"><ElementKinds><Kind Name="PARAMETER" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aaBb" /></Policy> <Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Enum members"><ElementKinds><Kind Name="ENUM_MEMBER" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /></Policy> <Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Types and namespaces"><ElementKinds><Kind Name="NAMESPACE" /><Kind Name="CLASS" /><Kind Name="STRUCT" /><Kind Name="ENUM" /><Kind Name="DELEGATE" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /></Policy> <Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Local constants"><ElementKinds><Kind Name="LOCAL_CONSTANT" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aaBb" /></Policy> <Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Interfaces"><ElementKinds><Kind Name="INTERFACE" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="I" Suffix="" Style="AaBb" /></Policy> <Policy><Descriptor Staticness="Static" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Static readonly fields (not private)"><ElementKinds><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /></Policy> <Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static fields (private)"><ElementKinds><Kind Name="FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aaBb" /></Policy> <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> True True True True True True True True True True True True True True True True False <data /> <data><IncludeFilters /><ExcludeFilters /></data> True tag 10 False False True using False True True Creates a new interactivity behaviors block in XAML. True behaviors True <interactivity:Interaction.Behaviors> </interactivity:Interaction.Behaviors> True InXmlFile True True Imported 2013-06-19 Creates a Rhino Mocks mock. True 0 True 1 True True *Test.cs InFileWithMask mock True $FIELD$ = MockRepository.GenerateMock<$INTERFACE$>(); True True True True True True ================================================ FILE: README.md ================================================


MVVM Dialogs
MVVM Dialogs

Library simplifying the concept of opening dialogs from a view model when using MVVM

Cross-platform solution derived from FantasticFiasco/mvvm-dialogs

UI Frameworks currently supported: - WPF (Windows Presentation Foundation) - [Avalonia](https://avaloniaui.net/) (mature cross-platform UI framework with WPF-like syntax, including mobile/browser support) UI Frameworks that can easily be added through community efforts: - WinUI 3 (promising Android/iOS support but won't support Linux) - Blazor (full app in web browser) - UWP (Universal Windows Platform, this thing is dead) ## Table of contents - [Introduction](#introduction) - [Generic Usage](#generic-usage) - [WPF Usage](#wpf-usage) - [Avalonia Usage](#avalonia-usage) - [StrongViewLocator](#strongviewlocator) - [Framework Dialogs](#framework-dialogs) - [Cross-Platform File Access](#cross-platform-file-access) - [IModalDialogViewModel / ICloseable / IActivable](#imodaldialogviewmodel--icloseable--iactivable) - [IViewLoaded / IViewClosing / IViewClosed](#iviewloaded--iviewclosing--iviewclosed) - [Custom Windows](#custom-windows) - [Custom Framework Dialogs](#custom-framework-dialogs) - [Unit Testing](#unit-testing) - [Logging](#logging) - [Thread Safety](#thread-safety) - [Differences from FantasticFiasco/mvvm-dialogs](#differences-from-fantasticfiascomvvm-dialogs) - [Contributions Are Welcomed](#contributions-are-welcomed) --- ## Introduction MVVM Dialogs is a library simplifying the concept of opening dialogs from a view model when using MVVM. It enables the developer to easily write unit tests for view models in the same manner unit tests are written for other classes. The library has built in support for the following dialogs: - Modal window - Non-modal window - Message box - Open file dialog - Save file dialog - Open folder dialog v2 adds supports for 'magic' mobile navigation with the same API. [Here's a tutorial for building modern cross-platform applications.](https://github.com/mysteryx93/Modern.Net-Tutorial) ## Generic Usage The interface `IDialogService` provides a platform-agnostic way of managing dialogs: ```c# using HanumanInstitute.MvvmDialogs public class ModalDialogTabContentViewModel : INotifyPropertyChanged { private readonly IDialogService dialogService; public ModalDialogTabContentViewModel(IDialogService dialogService) { this.dialogService = dialogService; } ... private async Task ShowDialogAsync() { var dialogViewModel = dialogService.CreateViewModel(); bool? success = await dialogService.ShowDialogAsync(this, dialogViewModel); if (success == true) { Texts.Add(dialogViewModel.Text); } } } ``` The recommended way of accessing your dialogs is to create a `DialogExtensions` class containing strongly-typed access to all your dialogs. ```c# public static class DialogExtensions { public static async Task ShowLoadPresetViewAsync(this IDialogService dialog, INotifyPropertyChanged ownerViewModel) { dialog.CheckNotNull(nameof(dialog)); // using HanumanInstitute.Validators var viewModel = dialog.CreateViewModel(); viewModel.Load(false); var result = await dialog.ShowDialogAsync(ownerViewModel, viewModel).ConfigureAwait(true); return result == true ? viewModel.SelectedItem : null; } public static async Task ShowSavePresetViewAsync(this IDialogService dialog, INotifyPropertyChanged ownerViewModel) { dialog.CheckNotNull(nameof(dialog)); var viewModel = dialog.CreateViewModel(); viewModel.Load(true); var result = await dialog.ShowDialogAsync(ownerViewModel, viewModel).ConfigureAwait(true); return result == true ? viewModel.PresetName : null; } } ``` To make your code testable, use `IDialogService.CreateViewModel` to create your dialog view models. It will call `viewModelFactory` function that you set in `DialogService` constructor. Then the usage is super *sexy*! (a long way from ReactiveUI [Interactions](https://www.reactiveui.net/docs/handbook/interactions/)...) ```c# private async Task SavePreset() { var presetName = await dialogService.ShowSavePresetViewAsync(this); if (presetName != null) { ... } return presetName; } ``` Meanwhile... - You can use IDialogService within class libraries that have no reference to Avalonia nor Wpf (referencing only `HanumanInstitute.MvvmDialogs`) - It is friendly for unit tests ### XAML Registrations XAML registrations are no longer required as of v1.1 and these lines must be removed. md:DialogServiceViews.IsRegistered="True" ## WPF Usage Add a reference to `HanumanInstitute.MvvmDialogs.Wpf` DialogService must be registered in the DependencyInjection container of your choice. Note that IDialogService is defined in `HanumanInstitute.MvvmDialogs` and DialogService is defined in `HanumanInstitute.MvvmDialogs.Wpf`. To customize ViewModels to Views naming convention, in the constructor, you must pass a ViewLocator. ```c# public partial class App { // Registering in CommunityToolkit.Mvvm protected override void OnStartup(StartupEventArgs e) { Ioc.Default.ConfigureServices( new ServiceCollection() .AddSingleton(new DialogService( new DialogManager(viewLocator: new ViewLocator()), viewModelFactory: x => Ioc.Default.GetService(x))) .AddTransient() .BuildServiceProvider()); } } ``` To associate view models with views, the default naming convention is to replace "ViewModel" with "View". To specify your own convention, create `ViewLocator.cs` with this, inheriting from [ViewLocatorBase](src/MvvmDialogs.Wpf/ViewLocatorBase.cs). You can also use the `StrongViewLocator` to avoid using reflection. Alternatively, you can create your custom class that inherits `IViewLocator`. ```c# using HanumanInstitute.MvvmDialogs.Wpf; namespace MyDemoApp; /// /// Maps view models to views. /// public class ViewLocator : ViewLocatorBase { /// protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", "View"); } ``` `IDialogService` exposes platform-agnostic async methods. For WPF (only), sync methods are also available. If you plan to ever use the ViewModel with a different UI framework, it is recommended to use the async methods. ```c# private bool? ShowDialog() { var dialogViewModel = dialogService.CreateViewModel(); return dialogService.ShowDialog(this, dialogViewModel); // Sync } } ``` ### AppDialogSettings When creating DialogService, you can pass AppDialogSettings with application-wide settings. #### bool MessageBoxRightToLeft Gets or sets whether message boxes are displayed right-to-left (RightAlign+RtlReading). #### bool MessageBoxDefaultDesktopOnly Gets or sets whether to display on the default desktop of the interactive window station. Specifies that the message box is displayed from a .NET Windows Service application in order to notify the user of an event. #### bool MessageBoxServiceNotification Gets or sets whether to display on the currently active desktop even if a user is not logged on to the computer. Specifies that the message box is displayed from a .NET Windows Service application in order to notify the user of an event. #### bool AllowConcurrentDialogs Gets or sets whether multiple dialogs can be shown at the same time. If false (default), it will wait for the previous dialog to close before showing the next one. ## Avalonia Usage Add a reference to `HanumanInstitute.MvvmDialogs.Avalonia` DialogService must be registered in the DependencyInjection container of your choice. Note that IDialogService is defined in `HanumanInstitute.MvvmDialogs` and DialogService is defined in `HanumanInstitute.MvvmDialogs.Wpf`. In the constructor, you must pass the ViewLocator from the Avalonia project template. ```c# public class App : Application { // Registering in ReactiveUI/Splat public override void Initialize() { AvaloniaXamlLoader.Load(this); var build = Locator.CurrentMutable; build.RegisterLazySingleton(() => (IDialogService)new DialogService( new DialogManager( viewLocator: new ViewLocator(), dialogFactory: new DialogFactory().AddMessageBox()), viewModelFactory: x => Locator.Current.GetService(x))); SplatRegistrations.Register(); SplatRegistrations.Register(); SplatRegistrations.SetupIOC(); } ``` To associate view models with views, the default naming convention (as of v2) is to replace folder "ViewModels" with "Views", and then change suffix from "ViewModel" to "Window" for desktop mode and "View" for mobile/navigation mode. Very often, Window simply contains the View. To specify your own convention, replace `ViewLocator.cs` with this, inheriting from [ViewLocatorBase](src/MvvmDialogs.Avalonia/ViewLocatorBase.cs). You can also use the `StrongViewLocator` to avoid using reflection. Alternatively, you can create your custom class that inherits `IDataTemplate` (for Avalonia), `IViewLocator` and `IViewLocatorNavigation` (for MvvmDialogs). You can use `UseSinglePageNavigation` to know whether the app is running in desktop or navigation mode. ```c# using HanumanInstitute.MvvmDialogs.Avalonia; namespace MyDemoApp; /// /// Maps view models to views. /// public class ViewLocator : ViewLocatorBase { /// protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", ""); } ``` ### AppDialogSettings #### bool AllowConcurrentDialogs Gets or sets whether multiple dialogs can be shown at the same time. If false (default), it will wait for the previous dialog to close before showing the next one. ### Mobile/Web Applications Avalonia11 supports Android, iOS and Web Assembly. To support it, MvvmDialogs v2 went through considerable structural changes that resulted in very minor API changes. For mobile devices and web browsers, the application is composed of a single root view, and you navigate between views. You can also force this mode on desktop by setting `viewLocator: new ViewLocatorBase() { ForceSinglePageNavigation = true }` in the `DialogManager` constructor. The philosophy is this. We maintain a navigation history of view models only, and a weak cache of views. Views can be garbage collected and recreated when needed from the view models. You get the same navigation functionalities as a desktop app, but in a navigation mode. All the magic is done automatically, which means that your view model doesn't need to know whether it runs on mobile or desktop, and can support both modes. Mobile back button is also supported automatically. ### Avalonia.MessageBox Avalonia has no built-in support for message boxes. This extension handles message box requests using [MessageBox.Avalonia](https://github.com/AvaloniaCommunity/MessageBox.Avalonia) library. `Mode=Window` only supports desktop mode. `Mode=Popup` is cross-platform. 1. Add a reference to `HanumanInstitute.MvvmDialogs.Avalonia.MessageBox` 2. Register the MessageBox handler on IDialogService like this: ```c# new DialogService(new DialogManager(dialogFactory: new DialogFactory().AddMessageBox(MessageBoxMode.Popup))) ``` ### Avalonia.Fluent [FluentAvalonia](https://github.com/amwx/FluentAvalonia/) brings more of Fluent design and WinUI controls into Avalonia. 1. Add a reference to `HanumanInstitute.MvvmDialogs.Avalonia.Fluent` 2. Register the handlers on IDialogService like this: ```c# new DialogService(new DialogManager(dialogFactory: new DialogFactory().AddFluent(FluentMessageBoxType.ContentDialog))) ``` It will add `IDialogService.ShowContentDialogAsync` and `IDialogService.ShowTaskDialogAsync`. Additionally, `AddFluent` takes a parameter specifying whether to handle `IDialogService.ShowMessageBoxAsync` calls with ContentDialog or with TaskDialog. ### Avalonia.AuraUI This extension handles message box requests using [Aura.UI](https://github.com/PieroCastillo/Aura.UI) library. 1. Add a reference to `HanumanInstitute.MvvmDialogs.Avalonia.AuraUI` 2. Register the MessageBox handler on IDialogService like this: ```c# new DialogService(new DialogManager(dialogFactory: new DialogFactory().AddMessageBoxAuraUI())) ``` Note: Aura.UI does not yet support Avalonia11 and is thus only available for MvvmDialogs v1.4.1 ### Avalonia.DialogHost [DialogHost.Avalonia](https://github.com/AvaloniaUtils/DialogHost.Avalonia) allows displaying views as popup overlays. FluentAvalonia brings WinUI3's ContentDialog that has title, content and button. On the other hand, DialogHost purely shows your view while giving you full control. 1. Add a reference to `HanumanInstitute.MvvmDialogs.Avalonia.DialogHost` 2. Register the handlers on IDialogService like this: ```c# new DialogService(new DialogManager(dialogFactory: new DialogFactory().AddDialogHost())) ``` It will add `IDialogService.ShowDialogHostAsync` that takes the following settings. **ContentViewModel**: The view model of the view to show. The view will be resolved through Avalonia's ViewLocator. **ClosingHandler**: A handler that will be called when the view is closing, allowing to cancel the close. **CloseOnClickAway**: Whether to close the view when clicking elsewhere in the parent container. **CloseOnClickAwayParameter**: The close value to set when closing by clicking away. **PopupPositioner**: A class allowing to customize the positioning of the dialog. You can then create extension methods for your views like this ```c# public static async Task AskTextAsync(this IDialogService service, INotifyPropertyChanged ownerViewModel, AppDialogSettingsBase? appSettings = null) { if (ownerViewModel == null) throw new ArgumentNullException(nameof(ownerViewModel)); var vm = service.CreateViewModel(); var settings = new DialogHostSettings() { ContentViewModel = vm, CloseOnClickAway = true }; return (string?)await service.ShowDialogHostAsync(ownerViewModel, settings, appSettings); } ``` [See sample project here](https://github.com/mysteryx93/HanumanInstitute.MvvmDialogs/tree/master/samples/Avalonia/Demo.DialogHost) ## StrongViewLocator Instead of resolving views via reflection and naming conventions, you can also configure ViewModel-View pairs manually using the `StrongViewLocator`. This will be necessary if you want to use Assembly Trimming, otherwise it will trim your View classes for a lack of hard references. Create your View Locator like this, then pass it to your Dialog Manager as explained above. ```c# public class ViewLocator : StrongViewLocator { public ViewLocator() { Register() Register() Register(); } } ``` ## Framework Dialogs `IDialogService` provides the following standard framework dialog methods: - `bool? ShowMessageBoxAsync` - `IDialogStorageFile? ShowOpenFileDialogAsync` - `IDialogStorageFile? ShowSaveFileDialogAsync` - `IDialogStorageFolder? ShowOpenFolderDialogAsync` - `IReadOnlyList ShowOpenFilesDialogAsync` - `IReadOnlyList ShowOpenFoldersDialogAsync` As of v2, files and folders are returned as `IDialogStorageFile` and `IDialogStorageFolder` instead of `string`. To get the path as a string like before (on desktop), simply add `.LocalPath`. Note that mobile and web have different path formats. For extra dialog options, see Custom Framework Dialogs section. ## Cross-Platform File Access To access files and folders across desktop, mobile and web, `IDialogStorageFile` and `IDialogStorageFolder` provide various standard methods. Instead of having direct access to files, you'll often use URIs, relative paths and bookmarks. They copy Avalonia's `IStorageFile` and `IStorageFolder` [documented here](https://docs.avaloniaui.net/docs/concepts/services/storage-provider/storage-item). The reasons to copy those interfaces are to allow you to write platform-agnostic code, and to have consistency between WPF and Avalonia. Avalonia provides various methods in `IStorageProvider` to get `IStorageFile` and `IStorageFolder` instances, as [documented here](https://docs.avaloniaui.net/docs/concepts/services/storage-provider/). You can convert them to the `MvvmDialogs` interface using the `ToDialog()` extension method. Here's a example of a service that returns the Documents folder. ```c# public class StorageService : IStorageService { protected virtual IStorageProvider Storage => _storage ??= GetTopLevel()?.StorageProvider ?? throw new NullReferenceException("No StorageProvider found."); private IStorageProvider? _storage; public async Task GetDocumentsFolderAsync() { var result = await Storage.TryGetWellKnownFolderAsync(WellKnownFolder.Documents); return result?.ToDialog(); } private TopLevel? GetTopLevel() { if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { return desktop.MainWindow; } if (Application.Current?.ApplicationLifetime is ISingleViewApplicationLifetime viewApp) { var visualRoot = viewApp.MainView?.GetVisualRoot(); return visualRoot as TopLevel; } return null; } } ``` Using your `StorageService` class, you can show a SaveDialog with default location set to Documents. ```c# var _storage = new StorageService(); var settings = new SaveFileDialogSettings { SuggestedStartLocation = await _storage.GetDocumentsFolderAsync() }; var file = await _dialogService.ShowSaveFileDialogAsync(this, settings); ``` On desktop platforms, you can convert a file path to `IDialogStorageFile` using either `HanumanInstitute.MvvmDialogs.FileSystem.DesktopDialogStorageFile` or `Avalonia.Platform.Storage.FileIO.BclStorageFile` which are nearly the same. `DesktopDialogStorageFile` has these differences: it accepts a string path in the constructor instead of only a `FileInfo`, it is of type `IDialogStorageFile` instead of `IStorageFile`, and it is available in non-Avalonia projects. `IDesktopDialogStorageFactory` is also available for easier unit test mocking. ## IModalDialogViewModel / ICloseable / IActivable All dialog ViewModels must implement `IModalDialogViewModel` to set `DialogResult` with the result of the dialog. In your ViewModel, implement `ICloseable` to add `RequestClose` event which will automatically close the View when raised. In your ViewModel, implement `IActivable` to add `RequestActivate` event which will automatically activate the View when raised. ## IViewLoaded / IViewClosing / IViewClosed Handling Loading, Closing and Closed events presents a few annoyances. Loading is a common business concern. Why would you have to write code in your View for it? Closing is generally used to display a confirmation before exit. Calling async code from the Closing event would require complex code, both in the ViewModel and the View. Closed cannot even call a command via an XAML behavior! Yet you need it to unregister some events to avoid memory leaks. As a simple solution, you can implement `IViewLoaded`, `IViewClosing` and/or `IViewClosed` from your ViewModel with no code required in your View. **IViewLoaded** `void OnLoaded();` Called when the view is loaded. **IViewClosed** `void RaiseClosed();` Called when the view is closed. **IViewClosing** `void RaiseClosing(CancelEventArgs e);` Called when closing the view. `Task OnClosingAsync(CancelEventArgs e);` Called if `e.Cancel` has been set to True in `OnClosing` Setting `e.Cancel = true` in `OnClosing` will... 1. Cancel the close 2. Call OnClosingAsync 3. Setting `e.Cancel = false` in `OnClosingAsync` will close the view See [Wpf/Demo.ViewEvents](samples/Wpf/Demo.ViewEvents/MainWindowViewModel.cs) for a sample implementation. **IMPORTANT**: To use these added features in your main ViewModel, your main window must be initialized via `IDialogService`. Initializing your main window in WPF in `App.xaml.cs` ```c# protected override void OnStartup(StartupEventArgs e) { // ... var dialogService = Ioc.Default.GetRequiredService(); var vm = dialogService.CreateViewModel(); dialogService.Show(null, vm); Application.Current.MainWindow = Application.Current.Windows[0]; } ``` Initializing your main window in Avalonia in `App.axaml.cs` ```c# public override void OnFrameworkInitializationCompleted() { GC.KeepAlive(typeof(DialogService)); DialogService.Show(null, MainWindow); base.OnFrameworkInitializationCompleted(); } public static MainWindowViewModel MainWindow => Locator.Current.GetService()!; public static IDialogService DialogService => Locator.Current.GetService()!; ``` ## Custom Windows To display custom dialogs that are not of type `Window` or `ContentDialog`, your dialog class must implement [IView](src/MvvmDialogs/IView.cs) ([sample](samples/Wpf/Demo.ModalCustomDialog/AddTextCustomDialog.cs)). The usage will be the same as a standard `Window`. ## Custom Framework Dialogs This part is the most different from the FantasticFiasco version and will require some work to port. The implementation further changed as of v1.3 to be simpler and more modular. First, create a custom DialogFactory like this. Note that you can create entirely new methods by adding new settings types. For new methods, you can customize the return type, but to override standard methods, you must specify the expected return type. ```c# public class CustomDialogFactory : DialogFactoryBase { public CustomDialogFactory(IDialogFactory? chain = null) : base(chain) { } public override async Task ShowDialogAsync(WindowWrapper owner, TSettings settings, AppDialogSettings appSettings) => settings switch { OpenFolderDialogSettings s => await ShowOpenFolderDialogAsync(owner, s, appSettings), _ => base.ShowDialogAsync(owner, settings, appSettings) }; private async Task ShowOpenFolderDialogAsync(WindowWrapper owner, OpenFolderDialogSettings settings, AppDialogSettings appSettings) => "Action here"; } ``` Second, create an extension method to facilitate registration of the new Dialog Factory. ```c# public static class DialogFactoryExtensions { public static IDialogFactory AddCustomOpenFolder(this IDialogFactory factory) => new CustomDialogFactory(factory); } ``` Third, you must register DialogFactory when creating the DialogService. You can form a chain of DialogFactory where each instance handles some types and passes unhandled requests to the next DialogFactory in the chain. The extension method facilitates the creation of such chain. In this example, our new class handles OpenFolder, and all other requests fallback to the default implementation. ```c# new DialogService(dialogManager: new DialogManager( dialogFactory: new DialogFactory().AddCustomOpenFolder())) ``` Finally, if you're creating a new method, you must create a new extension method on `IDialogService` ```c# namespace HanumanInstitute.MvvmDialogs; public static class Extensions { public static Task ShowTaskMessageBoxAsync( this IDialogService service, INotifyPropertyChanged ownerViewModel, string text, string title = "") { var settings = new TaskMessageBoxSettings(text, title); return ShowTaskMessageBoxAsync(service, ownerViewModel, settings); } public static Task ShowTaskMessageBoxAsync(this IDialogService service, INotifyPropertyChanged ownerViewModel, TaskMessageBoxSettings? settings = null) { if (ownerViewModel == null) throw new ArgumentNullException(nameof(ownerViewModel)); DialogLogger.Write($"TASK Caption: {settings?.Title}; Message: {settings?.Text}"); return service.DialogManager.ShowFrameworkDialogAsync( ownerViewModel, settings ?? new MessageBoxSettings()); } } ``` [Sample demo here](samples/Wpf/Demo.CustomMessageBox/) [MvvmDialogs.Avalonia.MessageBox is an example of custom implementation](src/MvvmDialogs.Avalonia.MessageBox) You could create a class library providing a new set of `IDialogService` methods. ### RunUiAsync There is a useful extension method in `HanumanInstitute.MvvmDialogs.Wpf` and `HanumanInstitute.MvvmDialogs.Avalonia` to run a synchronous UI method as an async method: ```c# UiExtensions.RunUiAsync(func) ``` ## Unit Testing To unit-test your project, mock [IDialogManager](src/MvvmDialogs/DialogTypeLocators/IDialogManager.cs). All UI interactions pass through `DialogManager`. Pass your mock when creating your `DialogService`. ```c# // Using Moq var dialogManagerMock = new Mock(); new DialogService(dialogManager: dialogManagerMock.Object); ``` From here you can configure your mock to validate calls to `Show`, `ShowDialogAsync` and `ShowFrameworkDialogAsync`. One problem you may face with unit testing dialogs is with the creation of your view model if it has dependencies. In the `DialogService` constructor, pass `viewModelFactory` new DialogService(viewModelFactory: x => Locator.Current.GetService(x)) Create your view model instances using `IDialogService.CreateViewModel` var vm = dialogService.CreateViewModel(); *This* can easily be mocked. [Here's a sample unit test](samples/Avalonia/Demo.ModalDialog.Tests/MainWindowViewModelTests.cs) ## Logging To enable logging, create a `DialogManager` and pass an `ILogger` to its constructor. ```c# var loggerFactory = LoggerFactory.Create(builder => builder.AddDebug()); var dialogService = new DialogService( new DialogManager(logger: loggerFactory.CreateLogger())); ``` ## Thread Safety All methods to show windows and dialogs are thread-safe and can be called from background threads. `IDialogService.Activate` and `IDialogService.Close` are NOT thread-safe and must be called from the UI thread. ## Differences from FantasticFiasco/mvvm-dialogs It is very easy to port an application from `FantasticFiasco/mvvm-dialogs` to `HanumanInstitute.MvvmDialogs`, yet there are also differences due to the fact that this library's API is framework-agnostic. The internal code structure is completely different, while the public API remains mostly compatible. Here are the differences: - Namespace changed from `MvvmDialogs` to `HanumanInstitute.MvvmDialogs` - Platform-specific code is in separate Wpf/Avalonia assembly - XAML registration is no longer required - All dialogs are shown using async methods. For WPF (only), sync methods remain available for compatibility. - Custom dialogs are treated the same way as standard dialogs - ICloseable / IActivable allow easily closing and activating the View from the ViewModel. - Framework dialogs use framework-agnostic settings classes. - There is no longer a separate namespace for each framework dialog. - Framework dialog methods return the selected value instead of bool. - FolderBrowserDialog has been renamed to OpenFolderDialog. - Factory classes are implemented differently. - Default naming convention, for `ViewModels/MainViewModel`, FantasticFiasco looks for `Views/Main`. This version looks for `Views/MainView`. - Maps view models to views using Avalonia's ViewLocator design that is easily customizable. - Logging is done using standard ILogging interface - Supports view navigation on mobile devices with Avalonia! ## Contributions Are Welcomed TODO: - Implement for WinUI 3 (I'll leave this task to someone who is going to use it) - Implement for UWP (this thing is dead... not worth implementing IMO) - Implement for Blazor? - Ensure that non-visible views can be released from memory - Adapt this [StaticViewLocatorGenerator](https://github.com/zkSNACKs/WalletWasabi/blob/1b8d142d0ec6892f13f6c50c3fec5d7ceb7f06ce/WalletWasabi.Fluent.Generators/StaticViewLocatorGenerator.cs#L12) ([usage here](https://github.com/zkSNACKs/WalletWasabi/blob/1b8d142d0ec6892f13f6c50c3fec5d7ceb7f06ce/WalletWasabi.Fluent/ViewLocator.cs#L7)) to replace the default naming convention ViewLocator with Source Generator instead of Reflection ### Author Brought to you by [Etienne Charland aka Hanuman](https://www.spiritualselftransformation.com/). Made by a Lightworker in his spare time. ================================================ FILE: deletebin.sh ================================================ #!/bin/bash find . -type d -name bin -prune -exec rm -rf {} \; find . -type d -name obj -prune -exec rm -rf {} \; ================================================ FILE: nuget.config ================================================ ================================================ FILE: samples/Avalonia/CrossPlatform/.gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files *.rsuser *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Mono auto generated files mono_crash.* # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ [Ww][Ii][Nn]32/ [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ [Ll]ogs/ # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # Visual Studio 2017 auto generated files Generated\ Files/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUnit *.VisualState.xml TestResult.xml nunit-*.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # Benchmark Results BenchmarkDotNet.Artifacts/ # .NET Core project.lock.json project.fragment.lock.json artifacts/ # Tye .tye/ # ASP.NET Scaffolding ScaffoldingReadMe.txt # StyleCop StyleCopReport.xml # Files built by Visual Studio *_i.c *_p.c *_h.h *.ilk *.meta *.obj *.iobj *.pch *.pdb *.ipdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *_wpftmp.csproj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile *.VC.db *.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx *.sap # Visual Studio Trace Files *.e2e # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # AxoCover is a Code Coverage Tool .axoCover/* !.axoCover/settings.json # Coverlet is a free, cross platform Code Coverage Tool coverage*.json coverage*.xml coverage*.info # Visual Studio code coverage results *.coverage *.coveragexml # 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 # Note: 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 # Microsoft Azure Web App publish settings. Comment the next line if you want to # checkin your Azure Web App publish settings, but sensitive information contained # in these scripts will be unencrypted PublishScripts/ # NuGet Packages *.nupkg # NuGet Symbol Packages *.snupkg # The packages folder can be ignored because of Package Restore **/[Pp]ackages/* # except build/, which is used as an MSBuild target. !**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/[Pp]ackages/repositories.config # NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets # Microsoft Azure Build Output csx/ *.build.csdef # Microsoft Azure Emulator ecf/ rcf/ # Windows Store app package directories and files AppPackages/ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt *.appx *.appxbundle *.appxupload # 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/ ~$* *~ *.dbmdl *.dbproj.schemaview *.jfm *.pfx *.publishsettings orleans.codegen.cs # Including strong name files can present a security risk # (https://github.com/github/gitignore/pull/2483#issue-259490424) #*.snk # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ # 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 ServiceFabricBackup/ *.rptproj.bak # SQL Server files *.mdf *.ldf *.ndf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings *.rptproj.rsuser *- [Bb]ackup.rdl *- [Bb]ackup ([0-9]).rdl *- [Bb]ackup ([0-9][0-9]).rdl # Microsoft Fakes FakesAssemblies/ # GhostDoc plugin setting file *.GhostDoc.xml # Node.js Tools for Visual Studio .ntvs_analysis.dat node_modules/ # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw # 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 paket-files/ # FAKE - F# Make .fake/ # CodeRush personal settings .cr/personal # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc # Cake - Uncomment if you are using it # tools/** # !tools/packages.config # Tabs Studio *.tss # Telerik's JustMock configuration file *.jmconfig # BizTalk build output *.btp.cs *.btm.cs *.odx.cs *.xsd.cs # OpenCover UI analysis results OpenCover/ # Azure Stream Analytics local run output ASALocalRun/ # MSBuild Binary and Structured Log *.binlog # NVidia Nsight GPU debugger configuration file *.nvuser # MFractors (Xamarin productivity tool) working folder .mfractor/ # Local History for Visual Studio .localhistory/ # BeatPulse healthcheck temp database healthchecksdb # Backup folder for Package Reference Convert tool in Visual Studio 2017 MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ # Fody - auto-generated XML schema FodyWeavers.xsd ## ## Visual studio for Mac ## # globs Makefile.in *.userprefs *.usertasks config.make config.status aclocal.m4 install-sh autom4te.cache/ *.tar.gz tarballs/ test-results/ # Mac bundle stuff *.dmg *.app # content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore # General .DS_Store .AppleDouble .LSOverride # Icon must end with two \r Icon # Thumbnails ._* # Files that might appear in the root of a volume .DocumentRevisions-V100 .fseventsd .Spotlight-V100 .TemporaryItems .Trashes .VolumeIcon.icns .com.apple.timemachine.donotpresent # Directories potentially created on remote AFP share .AppleDB .AppleDesktop Network Trash Folder Temporary Items .apdisk # content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore # Windows thumbnail cache files Thumbs.db ehthumbs.db ehthumbs_vista.db # Dump file *.stackdump # Folder config file [Dd]esktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ # Windows Installer files *.cab *.msi *.msix *.msm *.msp # Windows shortcuts *.lnk # JetBrains Rider .idea/ *.sln.iml ## ## Visual Studio Code ## .vscode/* !.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json ================================================ FILE: samples/Avalonia/CrossPlatform/Demo.CrossPlatform/App.axaml ================================================ ================================================ FILE: samples/Avalonia/CrossPlatform/Demo.CrossPlatform/App.axaml.cs ================================================ using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; using Demo.CrossPlatform.Services; using Demo.CrossPlatform.ViewModels; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.Avalonia; using Microsoft.Extensions.Logging; using Splat; namespace Demo.CrossPlatform; public partial class App : Application { public override void Initialize() { AvaloniaXamlLoader.Load(this); var build = Locator.CurrentMutable; var loggerFactory = LoggerFactory.Create(builder => builder.AddFilter(logLevel => true).AddDebug()); build.RegisterLazySingleton(() => (IDialogService)new DialogService( new DialogManager( viewLocator: new ViewLocator(), logger: loggerFactory.CreateLogger(), dialogFactory: new DialogFactory().AddFluent(messageBoxType: FluentMessageBoxType.ContentDialog)), viewModelFactory: x => Locator.Current.GetService(x))); SplatRegistrations.Register(); SplatRegistrations.Register(); SplatRegistrations.Register(); SplatRegistrations.Register(); SplatRegistrations.SetupIOC(); } public override void OnFrameworkInitializationCompleted() { DialogService.Show(null, MainViewModel); base.OnFrameworkInitializationCompleted(); } public static MainViewModel MainViewModel => Locator.Current.GetService()!; public static CurrentTimeViewModel CurrentTimeViewModel => Locator.Current.GetService()!; public static ConfirmCloseViewModel ConfirmCloseViewModel => Locator.Current.GetService()!; private static IDialogService DialogService => Locator.Current.GetService()!; public static StrongViewLocator ViewLocator { get; private set; } = default!; } ================================================ FILE: samples/Avalonia/CrossPlatform/Demo.CrossPlatform/Business/StreamExtensions.cs ================================================ using System.IO; using System.Threading; using System.Threading.Tasks; namespace Demo.CrossPlatform.Business; public static class StreamExtensions { public static async Task CopyToAsync(this Stream source, Stream destination, IProgress progress, CancellationToken cancellationToken = default(CancellationToken), int bufferSize = 0x1000) { var buffer = new byte[bufferSize]; int bytesRead; long totalRead = 0; while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken)) > 0) { await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken); cancellationToken.ThrowIfCancellationRequested(); totalRead += bytesRead; //Thread.Sleep(10); progress.Report(totalRead); } } } ================================================ FILE: samples/Avalonia/CrossPlatform/Demo.CrossPlatform/Business/SynchronousProgress.cs ================================================ namespace Demo.CrossPlatform.Business; public sealed class SynchronousProgress(Action callback) : IProgress { void IProgress.Report(T data) => callback(data); } ================================================ FILE: samples/Avalonia/CrossPlatform/Demo.CrossPlatform/Demo.CrossPlatform.csproj ================================================  net10.0 enable latest all runtime; build; native; contentfiles; analyzers; buildtransitive all runtime; build; native; contentfiles; analyzers; buildtransitive ConfirmCloseView.axaml Code ConfirmCloseWindow.axaml Code ================================================ FILE: samples/Avalonia/CrossPlatform/Demo.CrossPlatform/FodyWeavers.xml ================================================  ================================================ FILE: samples/Avalonia/CrossPlatform/Demo.CrossPlatform/GlobalUsings.cs ================================================ global using System; global using Avalonia; global using RxCommandUnit = ReactiveUI.ReactiveCommand; ================================================ FILE: samples/Avalonia/CrossPlatform/Demo.CrossPlatform/Roots.xml ================================================  ================================================ FILE: samples/Avalonia/CrossPlatform/Demo.CrossPlatform/Services/IStorageService.cs ================================================ using System.Threading.Tasks; using HanumanInstitute.MvvmDialogs.FileSystem; namespace Demo.CrossPlatform.Services; public interface IStorageService { Task GetDownloadsFolderAsync(); } ================================================ FILE: samples/Avalonia/CrossPlatform/Demo.CrossPlatform/Services/StorageService.cs ================================================ using System.Threading.Tasks; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Platform.Storage; using Avalonia.VisualTree; using HanumanInstitute.MvvmDialogs.Avalonia; using HanumanInstitute.MvvmDialogs.FileSystem; namespace Demo.CrossPlatform.Services; public class StorageService : IStorageService { protected virtual IStorageProvider Storage => _storage ??= GetTopLevel(Application.Current)?.StorageProvider ?? throw new NullReferenceException("No StorageProvider found."); private IStorageProvider? _storage; public async Task GetDownloadsFolderAsync() { var result = await Storage.TryGetWellKnownFolderAsync(WellKnownFolder.Downloads); return result?.ToDialog(); } /// /// Returns the TopLevel from the main window or view. /// /// The application to get the TopLevel for. /// A TopLevel object. private TopLevel? GetTopLevel(Application? app) { if (app?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { return desktop.MainWindow; } if (app?.ApplicationLifetime is ISingleViewApplicationLifetime viewApp) { return TopLevel.GetTopLevel(viewApp.MainView); } return null; } } ================================================ FILE: samples/Avalonia/CrossPlatform/Demo.CrossPlatform/ViewLocator.cs ================================================ using Demo.CrossPlatform.ViewModels; using Demo.CrossPlatform.Views; using HanumanInstitute.MvvmDialogs.Avalonia; namespace Demo.CrossPlatform; /// /// Maps view models to views in Avalonia. /// public class ViewLocator : StrongViewLocator { public ViewLocator() { ForceSinglePageNavigation = false; Register(); Register(); Register(); } } ================================================ FILE: samples/Avalonia/CrossPlatform/Demo.CrossPlatform/ViewModels/ConfirmCloseViewModel.cs ================================================ using System.ComponentModel; using System.Threading.Tasks; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.FrameworkDialogs; using ReactiveUI; using ReactiveUI.SourceGenerators; namespace Demo.CrossPlatform.ViewModels; public partial class ConfirmCloseViewModel : ViewModelBase, IModalDialogViewModel, IViewClosing, IViewLoaded, ICloseable { private readonly IDialogService _dialogService; public event EventHandler? RequestClose; public bool? DialogResult => true; public ConfirmCloseViewModel(IDialogService dialogService) { _dialogService = dialogService; Close = ReactiveCommand.Create(CloseImpl); } [Reactive] public partial string Text { get; set; } = string.Empty; public RxCommandUnit Close { get; } public void OnLoaded() { Text = "This dialog requires close confirmation."; } public void OnClosing(CancelEventArgs e) { e.Cancel = true; } private void CloseImpl() { RequestClose?.Invoke(this, EventArgs.Empty); } public async Task OnClosingAsync(CancelEventArgs e) { var result = await _dialogService.ShowMessageBoxAsync(this, "Do you want to close it?", "Confirmation", MessageBoxButton.YesNo); e.Cancel = result == false; } } ================================================ FILE: samples/Avalonia/CrossPlatform/Demo.CrossPlatform/ViewModels/CurrentTimeViewModel.cs ================================================ using System.Reactive.Linq; using HanumanInstitute.MvvmDialogs; using ReactiveUI; namespace Demo.CrossPlatform.ViewModels; public class CurrentTimeViewModel : ViewModelBase, IModalDialogViewModel, ICloseable, IViewClosed { public CurrentTimeViewModel() { Observable.Timer(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1)).Subscribe( (_) => { this.RaisePropertyChanged(nameof(CurrentTime)); }); Close = ReactiveCommand.Create(CloseImpl); } public DateTime CurrentTime => DateTime.Now; public bool? DialogResult { get; } = true; public event EventHandler? RequestClose; public event EventHandler? Closed; public RxCommandUnit Close { get; } private void CloseImpl() { RequestClose?.Invoke(this, EventArgs.Empty); } public void OnClosed() => Closed?.Invoke(this, EventArgs.Empty); } ================================================ FILE: samples/Avalonia/CrossPlatform/Demo.CrossPlatform/ViewModels/MainViewModel.cs ================================================ using System.IO; using System.Linq; using System.Reactive.Linq; using System.Threading.Tasks; using Demo.CrossPlatform.Services; using Demo.CrossPlatform.Business; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.FileSystem; using HanumanInstitute.MvvmDialogs.FrameworkDialogs; using ReactiveUI; using ReactiveUI.SourceGenerators; namespace Demo.CrossPlatform.ViewModels; public partial class MainViewModel : ViewModelBase { private readonly IDialogService _dialogService; private readonly IStorageService _storage; public MainViewModel(IDialogService dialogService, IStorageService storage) { this._dialogService = dialogService; this._storage = storage; var canShow = this.WhenAnyValue(x => x.DialogViewModel).Select(x => x == null); Show = ReactiveCommand.Create(ShowImpl, canShow); var canActivate = this.WhenAnyValue(x => x.DialogViewModel).Select(x => x != null); Activate = ReactiveCommand.Create(ActivateImpl, canActivate); Close = ReactiveCommand.Create(CloseImpl, canActivate); ShowDialog = ReactiveCommand.CreateFromTask(ShowDialogImplAsync); DialogConfirmClose = ReactiveCommand.CreateFromTask(DialogConfirmCloseImplAsync); OpenFile = ReactiveCommand.CreateFromTask(OpenFileImplAsync); OpenFiles = ReactiveCommand.CreateFromTask(OpenFilesImplAsync); OpenFolder = ReactiveCommand.CreateFromTask(OpenFolderImplAsync); OpenFolders = ReactiveCommand.CreateFromTask(OpenFoldersImplAsync); SaveFile = ReactiveCommand.CreateFromTask(SaveFileImplAsync); MessageBox = ReactiveCommand.CreateFromTask(MessageBoxImplAsync); MessageBoxMultiple = ReactiveCommand.CreateFromTask(MessageBoxMultipleImplAsync); } [Reactive] public partial string? Output { get; set; } private CurrentTimeViewModel? _dialogViewModel; protected CurrentTimeViewModel? DialogViewModel { get => _dialogViewModel; set { if (DialogViewModel != null) { DialogViewModel.Closed -= Dialog_ViewClosed; } this.RaiseAndSetIfChanged(ref _dialogViewModel, value); if (DialogViewModel != null) { DialogViewModel.Closed += Dialog_ViewClosed; } } } private void Dialog_ViewClosed(object? sender, EventArgs e) => DialogViewModel = null; public RxCommandUnit Show { get; } public RxCommandUnit ShowDialog { get; } public RxCommandUnit Close { get; } public RxCommandUnit Activate { get; } public RxCommandUnit DialogConfirmClose { get; } public RxCommandUnit OpenFile { get; } public RxCommandUnit OpenFiles { get; } public RxCommandUnit OpenFolder { get; } public RxCommandUnit OpenFolders { get; } public RxCommandUnit SaveFile { get; } public RxCommandUnit MessageBox { get; } public RxCommandUnit MessageBoxMultiple { get; } private void ShowImpl() { DialogViewModel = _dialogService.CreateViewModel(); _dialogService.Show(this, DialogViewModel); } private void ActivateImpl() => _dialogService.Activate(DialogViewModel!); private void CloseImpl() { _dialogService.Close(DialogViewModel!); DialogViewModel = null; } private async Task ShowDialogImplAsync() { var vm = _dialogService.CreateViewModel(); await _dialogService.ShowDialogAsync(this, vm); } private async Task DialogConfirmCloseImplAsync() { var vm = _dialogService.CreateViewModel(); await _dialogService.ShowDialogAsync(this, vm); } private async Task OpenFileImplAsync() { var settings = new OpenFileDialogSettings { SuggestedStartLocation = await _storage.GetDownloadsFolderAsync() }; var file = await _dialogService.ShowOpenFileDialogAsync(this, settings); Output = file?.Path + Environment.NewLine; if (file?.Path != null) { await ScanFileProgressAsync(file); } } private async Task ScanFileProgressAsync(IDialogStorageFile file) { using var stream = file.OpenReadAsync(); Output += "File opened." + Environment.NewLine; var outputHeader = string.Empty; long length = 0; IProgress progress = new SynchronousProgress(value => { Output = outputHeader + ((float)value / length).ToString("P1") + Environment.NewLine; }); await stream.ContinueWith( async t => { using var ms = new MemoryStream(); var streamResult = stream.Result; length = streamResult.Length; Output += "Result size: " + streamResult.Length + " starting copy to memory" + Environment.NewLine; outputHeader = Output; await streamResult.CopyToAsync(ms, progress, default, 1024); Output += "Done" + Environment.NewLine; ms.Position = 0; }); } private async Task OpenFilesImplAsync() { var settings = new OpenFileDialogSettings { SuggestedStartLocation = await _storage.GetDownloadsFolderAsync() }; var files = await _dialogService.ShowOpenFilesDialogAsync(this, settings); Output = string.Join(Environment.NewLine, files.Select(x => x?.Path?.ToString() ?? "")); } private async Task OpenFolderImplAsync() { var settings = new OpenFolderDialogSettings { SuggestedStartLocation = await _storage.GetDownloadsFolderAsync() }; var folder = await _dialogService.ShowOpenFolderDialogAsync(this, settings); Output = folder?.Path?.ToString(); } private async Task OpenFoldersImplAsync() { var settings = new OpenFolderDialogSettings { SuggestedStartLocation = await _storage.GetDownloadsFolderAsync() }; var folders = await _dialogService.ShowOpenFoldersDialogAsync(this, settings); Output = string.Join(Environment.NewLine, folders.Select(x => x?.Path?.ToString() ?? "")); } private async Task SaveFileImplAsync() { var settings = new SaveFileDialogSettings { SuggestedStartLocation = await _storage.GetDownloadsFolderAsync() }; var file = await _dialogService.ShowSaveFileDialogAsync(this, settings); Output = file?.Path?.ToString(); } private async Task MessageBoxImplAsync() { var result = await _dialogService.ShowMessageBoxAsync(this, "Do you want it?", "Question", MessageBoxButton.YesNo, MessageBoxImage.Exclamation); Output = result.ToString(); } private async Task MessageBoxMultipleImplAsync() { var t1 = _dialogService.ShowMessageBoxAsync(this, "First message box", "Go", MessageBoxButton.YesNo, MessageBoxImage.Exclamation).ConfigureAwait(false); await Task.Delay(1000).ConfigureAwait(false); var t2 = _dialogService.ShowMessageBoxAsync(this, "Second message box", "Again", MessageBoxButton.YesNo, MessageBoxImage.Exclamation).ConfigureAwait(false); await Task.Delay(1000).ConfigureAwait(false); var t3 = _dialogService.ShowMessageBoxAsync(this, "Third message box", "Once More!", MessageBoxButton.YesNo, MessageBoxImage.Exclamation).ConfigureAwait(false); var r1 = await t1; var r2 = await t2; var r3 = await t3; Output = r1 + Environment.NewLine + r2 + Environment.NewLine + r3; } } ================================================ FILE: samples/Avalonia/CrossPlatform/Demo.CrossPlatform/ViewModels/ViewModelBase.cs ================================================ using ReactiveUI; namespace Demo.CrossPlatform.ViewModels; public class ViewModelBase : ReactiveObject { } ================================================ FILE: samples/Avalonia/CrossPlatform/Demo.CrossPlatform/Views/ConfirmCloseView.axaml ================================================ ================================================ FILE: samples/Avalonia/Demo.ActivateNonModalDialog.MvvmToolkit/MainWindow.axaml.cs ================================================ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Avalonia.ActivateNonModalDialog; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void InitializeComponent() => AvaloniaXamlLoader.Load(this); } ================================================ FILE: samples/Avalonia/Demo.ActivateNonModalDialog.MvvmToolkit/MainWindowViewModel.cs ================================================ using System.ComponentModel; using CommunityToolkit.Mvvm.Input; using HanumanInstitute.MvvmDialogs; namespace Demo.Avalonia.ActivateNonModalDialog; public class MainWindowViewModel : ViewModelBase { private readonly IDialogService _dialogService; private INotifyPropertyChanged? _dialogViewModel; public INotifyPropertyChanged? DialogViewModel { get => _dialogViewModel; set { if (SetProperty(ref _dialogViewModel, value)) { ShowCommand.NotifyCanExecuteChanged(); ActivateCommand.NotifyCanExecuteChanged(); } } } public RelayCommand ShowCommand { get; } public RelayCommand ActivateCommand { get; } public MainWindowViewModel(IDialogService dialogService) { this._dialogService = dialogService; ShowCommand = new RelayCommand(Show, () => DialogViewModel == null); ActivateCommand = new RelayCommand(Activate, () => DialogViewModel != null); } public void Show() { DialogViewModel = _dialogService.CreateViewModel(); _dialogService.Show(this, DialogViewModel); } public void Activate() => _dialogService.Activate(DialogViewModel!); } ================================================ FILE: samples/Avalonia/Demo.ActivateNonModalDialog.MvvmToolkit/Program.cs ================================================ using System; using Avalonia; namespace Demo.Avalonia.ActivateNonModalDialog; public class Program { // Initialization code. Don't use any Avalonia, third-party APIs or any // SynchronizationContext-reliant code before AppMain is called: things aren't initialized // yet and stuff might break. [STAThread] public static void Main(string[] args) => BuildAvaloniaApp() .StartWithClassicDesktopLifetime(args); // Avalonia configuration, don't remove; also used by visual designer. public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() .LogToTrace(); } ================================================ FILE: samples/Avalonia/Demo.ActivateNonModalDialog.MvvmToolkit/ViewLocator.cs ================================================ using HanumanInstitute.MvvmDialogs.Avalonia; namespace Demo.Avalonia.ActivateNonModalDialog; /// /// Maps view models to views in Avalonia. /// public class ViewLocator : ViewLocatorBase { /// protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", ""); } ================================================ FILE: samples/Avalonia/Demo.ActivateNonModalDialog.MvvmToolkit/ViewModelBase.cs ================================================ using CommunityToolkit.Mvvm.ComponentModel; namespace Demo.Avalonia.ActivateNonModalDialog; public class ViewModelBase : ObservableObject { } ================================================ FILE: samples/Avalonia/Demo.CloseNonModalDialog/App.axaml ================================================ ================================================ FILE: samples/Avalonia/Demo.CloseNonModalDialog/App.axaml.cs ================================================ using System; using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.Avalonia; using Microsoft.Extensions.Logging; using Splat; namespace Demo.Avalonia.CloseNonModalDialog; public class App : Application { public override void Initialize() { AvaloniaXamlLoader.Load(this); var build = Locator.CurrentMutable; var loggerFactory = LoggerFactory.Create(builder => builder.AddDebug()); build.RegisterLazySingleton(() => (IDialogService)new DialogService( new DialogManager( viewLocator: new ViewLocator(), logger: loggerFactory.CreateLogger()), viewModelFactory: x => Locator.Current.GetService(x))); SplatRegistrations.Register(); SplatRegistrations.Register(); SplatRegistrations.SetupIOC(); } public override void OnFrameworkInitializationCompleted() { GC.KeepAlive(typeof(DialogService)); if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { desktop.MainWindow = new MainWindow { DataContext = MainWindow }; } base.OnFrameworkInitializationCompleted(); } public static MainWindowViewModel MainWindow => Locator.Current.GetService()!; public static CurrentTimeDialogViewModel CurrentTimeDialog => Locator.Current.GetService()!; public static IDialogService DialogService => Locator.Current.GetService()!; } ================================================ FILE: samples/Avalonia/Demo.CloseNonModalDialog/CurrentTimeDialog.axaml ================================================  ================================================ FILE: samples/Avalonia/Demo.CloseNonModalDialog/CurrentTimeDialog.axaml.cs ================================================ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Avalonia.CloseNonModalDialog; public partial class CurrentTimeDialog : Window { public CurrentTimeDialog() { InitializeComponent(); } private void InitializeComponent() => AvaloniaXamlLoader.Load(this); } ================================================ FILE: samples/Avalonia/Demo.CloseNonModalDialog/CurrentTimeDialogViewModel.cs ================================================ using System; using System.Reactive.Linq; using ReactiveUI; namespace Demo.Avalonia.CloseNonModalDialog; public class CurrentTimeDialogViewModel : ViewModelBase { public DateTime CurrentTime => DateTime.Now; public CurrentTimeDialogViewModel() => Observable.Timer(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1)).Subscribe((_) => { this.RaisePropertyChanged(nameof(CurrentTime)); }); } ================================================ FILE: samples/Avalonia/Demo.CloseNonModalDialog/Demo.CloseNonModalDialog.csproj ================================================  WinExe net10.0 enable default Demo.Avalonia.CloseNonModalDialog Demo.Avalonia.CloseNonModalDialog all runtime; build; native; contentfiles; analyzers; buildtransitive ================================================ FILE: samples/Avalonia/Demo.CloseNonModalDialog/MainWindow.axaml ================================================  ================================================ FILE: samples/Avalonia/Demo.CloseNonModalDialog/MainWindow.axaml.cs ================================================ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Avalonia.CloseNonModalDialog; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void InitializeComponent() => AvaloniaXamlLoader.Load(this); } ================================================ FILE: samples/Avalonia/Demo.CloseNonModalDialog/MainWindowViewModel.cs ================================================ using System.ComponentModel; using System.Reactive.Linq; using System.Windows.Input; using HanumanInstitute.MvvmDialogs; using ReactiveUI; namespace Demo.Avalonia.CloseNonModalDialog; public class MainWindowViewModel : ViewModelBase { private readonly IDialogService _dialogService; private INotifyPropertyChanged? _dialogViewModel; public INotifyPropertyChanged? DialogViewModel { get => _dialogViewModel; set => this.RaiseAndSetIfChanged(ref _dialogViewModel, value, nameof(DialogViewModel)); } public ICommand ShowCommand { get; } public ICommand CloseCommand { get; } public MainWindowViewModel(IDialogService dialogService) { this._dialogService = dialogService; var canShow = this.WhenAnyValue(x => x.DialogViewModel).Select(d => d == null); ShowCommand = ReactiveCommand.Create(ShowImpl, canShow); var canClose = this.WhenAnyValue(x => x.DialogViewModel).Select(d => d != null); CloseCommand = ReactiveCommand.Create(CloseImpl, canClose); } // Run from background threads private void ShowImpl() { DialogViewModel = _dialogService.CreateViewModel(); _dialogService.Show(this, DialogViewModel); } private void CloseImpl() { _dialogService.Close(DialogViewModel!); DialogViewModel = null; } } ================================================ FILE: samples/Avalonia/Demo.CloseNonModalDialog/Program.cs ================================================ using System; using Avalonia; using ReactiveUI.Avalonia; namespace Demo.Avalonia.CloseNonModalDialog; class Program { // Initialization code. Don't use any Avalonia, third-party APIs or any // SynchronizationContext-reliant code before AppMain is called: things aren't initialized // yet and stuff might break. [STAThread] public static void Main(string[] args) => BuildAvaloniaApp() .StartWithClassicDesktopLifetime(args); // Avalonia configuration, don't remove; also used by visual designer. public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() .LogToTrace() .UseReactiveUI(rxui => { }); } ================================================ FILE: samples/Avalonia/Demo.CloseNonModalDialog/ViewLocator.cs ================================================ using HanumanInstitute.MvvmDialogs.Avalonia; namespace Demo.Avalonia.CloseNonModalDialog; /// /// Maps view models to views in Avalonia. /// public class ViewLocator : ViewLocatorBase { /// protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", ""); } ================================================ FILE: samples/Avalonia/Demo.CloseNonModalDialog/ViewModelBase.cs ================================================ using ReactiveUI; namespace Demo.Avalonia.CloseNonModalDialog; public class ViewModelBase : ReactiveObject { } ================================================ FILE: samples/Avalonia/Demo.CustomOpenFolderDialog/App.axaml ================================================ ================================================ FILE: samples/Avalonia/Demo.CustomOpenFolderDialog/App.axaml.cs ================================================ using System; using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.Avalonia; using Microsoft.Extensions.Logging; using Splat; namespace Demo.Avalonia.CustomOpenFolderDialog; public class App : Application { public override void Initialize() { AvaloniaXamlLoader.Load(this); var build = Locator.CurrentMutable; var loggerFactory = LoggerFactory.Create(builder => builder.AddFilter(logLevel => true).AddDebug()); build.RegisterLazySingleton(() => (IDialogService)new DialogService( dialogManager: new DialogManager( viewLocator: new ViewLocator(), dialogFactory: new DialogFactory().AddCustomOpenFolder(), logger: loggerFactory.CreateLogger()), viewModelFactory: x => Locator.Current.GetService(x))); SplatRegistrations.Register(); SplatRegistrations.SetupIOC(); } public override void OnFrameworkInitializationCompleted() { GC.KeepAlive(typeof(DialogService)); if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { desktop.MainWindow = new MainWindow { DataContext = MainWindow }; } base.OnFrameworkInitializationCompleted(); } public static MainWindowViewModel MainWindow => Locator.Current.GetService()!; public static IDialogService DialogService => Locator.Current.GetService()!; } ================================================ FILE: samples/Avalonia/Demo.CustomOpenFolderDialog/CustomDialogFactory.cs ================================================ using System; using System.Threading.Tasks; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.FrameworkDialogs; using HanumanInstitute.MvvmDialogs.Avalonia; using Ookii.Dialogs.WinForms; using Avalonia.Controls; using System.Collections.Generic; using HanumanInstitute.MvvmDialogs.FileSystem; namespace Demo.Avalonia.CustomOpenFolderDialog; /// /// Initializes a new instance of a FrameworkDialog. /// /// If the dialog is not handled by this class, calls this other handler next. public class CustomDialogFactory(IDialogFactory? chain = null) : DialogFactoryBase(chain) { /// public override async Task ShowDialogAsync(IView? owner, TSettings settings) => settings switch { OpenFolderDialogSettings s => await ShowOpenFolderDialogAsync(owner, s), _ => base.ShowDialogAsync(owner, settings) }; private async Task> ShowOpenFolderDialogAsync(IView? owner, OpenFolderDialogSettings settings) { ArgumentNullException.ThrowIfNull(owner); var window = TopLevel.GetTopLevel(owner.GetRef()); var handle = (window?.TryGetPlatformHandle()?.Handle) ?? throw new NullReferenceException("Cannot obtain HWND handle for owner."); var dialog = new VistaFolderBrowserDialog { Description = settings.Title, SelectedPath = settings.SuggestedStartLocation?.LocalPath }; var result = await UiExtensions.RunUiAsync(() => dialog.ShowDialog(handle)); return result == true ? [new DesktopDialogStorageFolder(dialog.SelectedPath!)] : []; } } ================================================ FILE: samples/Avalonia/Demo.CustomOpenFolderDialog/Demo.CustomOpenFolderDialog.csproj ================================================  WinExe net10.0-windows enable default true Demo.Avalonia.CustomOpenFolderDialog Demo.Avalonia.CustomOpenFolderDialog all runtime; build; native; contentfiles; analyzers; buildtransitive ================================================ FILE: samples/Avalonia/Demo.CustomOpenFolderDialog/DialogFactoryExtensions.cs ================================================ using HanumanInstitute.MvvmDialogs; namespace Demo.Avalonia.CustomOpenFolderDialog { public static class DialogFactoryExtensions { public static IDialogFactory AddCustomOpenFolder(this IDialogFactory factory) => new CustomDialogFactory(factory); } } ================================================ FILE: samples/Avalonia/Demo.CustomOpenFolderDialog/MainWindow.axaml ================================================ ================================================ FILE: samples/Avalonia/Demo.DialogHost/MainView.axaml.cs ================================================ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Avalonia.DialogHost; public partial class MainView : Window { public MainView() { InitializeComponent(); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } } ================================================ FILE: samples/Avalonia/Demo.DialogHost/MainViewModel.cs ================================================ using System.Reactive; using System.Threading.Tasks; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.Avalonia.DialogHost; using ReactiveUI; using ReactiveUI.SourceGenerators; namespace Demo.Avalonia.DialogHost; public partial class MainViewModel : ViewModelBase { private readonly IDialogService _dialogService; public MainViewModel(IDialogService dialogService) { this._dialogService = dialogService; ShowViewModel = ReactiveCommand.CreateFromTask(ShowViewModelImplAsync); AskText = ReactiveCommand.CreateFromTask(AskTextImplAsync); ShowMessage = ReactiveCommand.CreateFromTask(ShowMessageImplAsync); ShowControl = ReactiveCommand.CreateFromTask(ShowControlImplAsync); ConfirmClose = ReactiveCommand.CreateFromTask(ConfirmCloseImplAsync); } public ReactiveCommand ShowViewModel { get; } public ReactiveCommand AskText { get; } public ReactiveCommand ShowMessage { get; } public ReactiveCommand ShowControl { get; } public ReactiveCommand ConfirmClose { get; } [Reactive] public partial string? TextOutput { get; set; } private async Task ShowViewModelImplAsync() { var dialogViewModel = _dialogService.CreateViewModel(); await _dialogService.ShowDialogHostAsync( this, new DialogHostSettings(dialogViewModel) { CloseOnClickAway = true, ClosingHandler = (_, e) => { if (dialogViewModel.StayOpen) { e.Cancel(); } } }); } private async Task AskTextImplAsync() { TextOutput = await _dialogService.AskTextAsync(this); } private async Task ShowMessageImplAsync() { var result = await _dialogService.ShowDialogHostAsync( this, new DialogHostSettings("Hello world!") { CloseOnClickAway = true }).ConfigureAwait(true); TextOutput = result?.ToString() ?? "(null)"; } private async Task ShowControlImplAsync() { var content = new MessageView(); var result = await _dialogService.ShowDialogHostAsync(this, new DialogHostSettings(content)).ConfigureAwait(true); TextOutput = result?.ToString() ?? "(null)"; } private async Task ConfirmCloseImplAsync() { var dialogViewModel = _dialogService.CreateViewModel(); dialogViewModel.ConfirmClose = true; // dialogViewModel.Owner = this; await _dialogService.ShowDialogHostAsync( this, new DialogHostSettings(dialogViewModel) { CloseOnClickAway = true }); } } ================================================ FILE: samples/Avalonia/Demo.DialogHost/MessageView.axaml ================================================ ================================================ FILE: samples/Avalonia/Demo.FluentContentDialog/MainView.axaml.cs ================================================ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Avalonia.FluentContentDialog; public partial class MainView : Window { public MainView() { InitializeComponent(); } private void InitializeComponent() => AvaloniaXamlLoader.Load(this); } ================================================ FILE: samples/Avalonia/Demo.FluentContentDialog/MainViewModel.cs ================================================ using System.Reactive; using System.Threading.Tasks; using FluentAvalonia.UI.Controls; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.Avalonia.Fluent; using ReactiveUI; using ReactiveUI.SourceGenerators; namespace Demo.Avalonia.FluentContentDialog; public partial class MainViewModel : ViewModelBase { private readonly IDialogService _dialogService; public ReactiveCommand ShowMessageBox { get; } public ReactiveCommand AskText { get; } public ReactiveCommand ShowViewModel { get; } public ReactiveCommand ShowControl { get; } public MainViewModel(IDialogService dialogService) { this._dialogService = dialogService; ShowMessageBox = ReactiveCommand.CreateFromTask(ShowMessageBoxImplAsync); AskText = ReactiveCommand.CreateFromTask(AskTextImplAsync); ShowViewModel = ReactiveCommand.CreateFromTask(ShowViewModelImplAsync); ShowControl = ReactiveCommand.CreateFromTask(ShowControlImplAsync); } [Reactive] public partial string? TextOutput { get; set; } private async Task ShowMessageBoxImplAsync() { ContentDialogSettings settings = new() { Content = "This is the text.", Title = "This Is The Caption", PrimaryButtonText = "OK", SecondaryButtonText = "Cancel", DefaultButton = FAContentDialogButton.Secondary }; var result = await _dialogService.ShowContentDialogAsync(this, settings); UpdateResult(result == FAContentDialogResult.Primary); } private void UpdateResult(bool? result) => TextOutput = result == true ? "We got confirmation to continue!" : string.Empty; private async Task AskTextImplAsync() { var vm = _dialogService.CreateViewModel(); vm.Title = "Title within the View"; ContentDialogSettings settings = new() { Content = vm, Title = "Please enter some text", PrimaryButtonText = "OK", SecondaryButtonText = "Cancel", DefaultButton = FAContentDialogButton.Primary }; var result = await _dialogService.ShowContentDialogAsync(this, settings); if (result == FAContentDialogResult.Primary) { TextOutput = vm.Text; } } private async Task ShowViewModelImplAsync() { var dialogViewModel = _dialogService.CreateViewModel(); dialogViewModel.ConfirmClose = true; await _dialogService.ShowContentDialogAsync(this, new ContentDialogSettings(dialogViewModel) { PrimaryButtonText = "OK" }).ConfigureAwait(true); } private async Task ShowControlImplAsync() { var content = new MessageView(); var result = await _dialogService.ShowContentDialogAsync(this, new ContentDialogSettings(content) { PrimaryButtonText = "OK" }).ConfigureAwait(true); TextOutput = result.ToString(); } } ================================================ FILE: samples/Avalonia/Demo.FluentContentDialog/MessageView.axaml ================================================ ================================================ FILE: samples/Avalonia/Demo.FluentContentDialog/MessageView.axaml.cs ================================================ using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Avalonia.FluentContentDialog; public partial class MessageView : UserControl { public MessageView() { InitializeComponent(); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } } ================================================ FILE: samples/Avalonia/Demo.FluentContentDialog/Program.cs ================================================ using System; using Avalonia; using ReactiveUI.Avalonia; namespace Demo.Avalonia.FluentContentDialog; class Program { // Initialization code. Don't use any Avalonia, third-party APIs or any // SynchronizationContext-reliant code before AppMain is called: things aren't initialized // yet and stuff might break. [STAThread] public static void Main(string[] args) => BuildAvaloniaApp() .StartWithClassicDesktopLifetime(args); // Avalonia configuration, don't remove; also used by visual designer. public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() .LogToTrace() .UseReactiveUI(rxui => { }); } ================================================ FILE: samples/Avalonia/Demo.FluentContentDialog/ViewLocator.cs ================================================ using HanumanInstitute.MvvmDialogs.Avalonia; namespace Demo.Avalonia.FluentContentDialog; /// /// Maps view models to views in Avalonia. /// // public class ViewLocator : ViewLocatorBase // { // /// // protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", "View"); // } public class ViewLocator : StrongViewLocator { public ViewLocator() { Register(); Register(); Register(); } } ================================================ FILE: samples/Avalonia/Demo.FluentContentDialog/ViewModelBase.cs ================================================ using ReactiveUI; namespace Demo.Avalonia.FluentContentDialog; public class ViewModelBase : ReactiveObject { } ================================================ FILE: samples/Avalonia/Demo.FluentMessageBoxContentDialog/App.axaml ================================================ ================================================ FILE: samples/Avalonia/Demo.FluentMessageBoxContentDialog/App.axaml.cs ================================================ using System; using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.Avalonia; using Microsoft.Extensions.Logging; using Splat; namespace Demo.Avalonia.FluentMessageBoxContentDialog; public class App : Application { public override void Initialize() { AvaloniaXamlLoader.Load(this); var build = Locator.CurrentMutable; var loggerFactory = LoggerFactory.Create(builder => builder.AddFilter(logLevel => true).AddDebug()); build.RegisterLazySingleton(() => (IDialogService)new DialogService( new DialogManager( viewLocator: new ViewLocator(), logger: loggerFactory.CreateLogger(), dialogFactory: new DialogFactory().AddFluent(FluentMessageBoxType.ContentDialog)), viewModelFactory: x => Locator.Current.GetService(x))); SplatRegistrations.Register(); SplatRegistrations.SetupIOC(); } public override void OnFrameworkInitializationCompleted() { GC.KeepAlive(typeof(DialogService)); if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { desktop.MainWindow = new MainWindow { DataContext = MainWindow }; } base.OnFrameworkInitializationCompleted(); } public static MainWindowViewModel MainWindow => Locator.Current.GetService()!; public static IDialogService DialogService => Locator.Current.GetService()!; } ================================================ FILE: samples/Avalonia/Demo.FluentMessageBoxContentDialog/Demo.FluentMessageBoxContentDialog.csproj ================================================  WinExe net10.0 enable default Demo.Avalonia.FluentMessageBoxContentDialog Demo.Avalonia.FluentMessageBoxContentDialog all runtime; build; native; contentfiles; analyzers; buildtransitive ================================================ FILE: samples/Avalonia/Demo.FluentMessageBoxContentDialog/MainWindow.axaml ================================================  ================================================ FILE: samples/Avalonia/Demo.FluentMessageBoxContentDialog/MainWindow.axaml.cs ================================================ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Avalonia.FluentMessageBoxContentDialog; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void InitializeComponent() => AvaloniaXamlLoader.Load(this); } ================================================ FILE: samples/Avalonia/Demo.FluentMessageBoxContentDialog/MainWindowViewModel.cs ================================================ using System.Threading.Tasks; using System.Windows.Input; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.FrameworkDialogs; using ReactiveUI; namespace Demo.Avalonia.FluentMessageBoxContentDialog; public class MainWindowViewModel : ViewModelBase { private readonly IDialogService _dialogService; public ICommand ShowMessageBoxWithMessageCommand { get; } public ICommand ShowMessageBoxWithCaptionCommand { get; } public ICommand ShowMessageBoxWithButtonCommand { get; } public ICommand ShowMessageBoxWithIconCommand { get; } public ICommand ShowMessageBoxWithDefaultResultCommand { get; } public MainWindowViewModel(IDialogService dialogService) { this._dialogService = dialogService; ShowMessageBoxWithMessageCommand = ReactiveCommand.CreateFromTask(ShowMessageBoxWithMessage); ShowMessageBoxWithCaptionCommand = ReactiveCommand.CreateFromTask(ShowMessageBoxWithCaption); ShowMessageBoxWithButtonCommand = ReactiveCommand.CreateFromTask(ShowMessageBoxWithButton); ShowMessageBoxWithIconCommand = ReactiveCommand.CreateFromTask(ShowMessageBoxWithIcon); ShowMessageBoxWithDefaultResultCommand = ReactiveCommand.CreateFromTask(ShowMessageBoxWithDefaultResult); } private string _confirmation = string.Empty; public string Confirmation { get => _confirmation; private set => this.RaiseAndSetIfChanged(ref _confirmation, value, nameof(Confirmation)); } private async Task ShowMessageBoxWithMessage() { var result = await _dialogService.ShowMessageBoxAsync( this, "This is the text."); UpdateResult(result); } private async Task ShowMessageBoxWithCaption() { var result = await _dialogService.ShowMessageBoxAsync( this, "This is the text.", "This Is The Caption"); UpdateResult(result); } private async Task ShowMessageBoxWithButton() { var result = await _dialogService.ShowMessageBoxAsync( this, "This is the text.", "This Is The Caption", MessageBoxButton.OkCancel); UpdateResult(result); } private async Task ShowMessageBoxWithIcon() { var result = await _dialogService.ShowMessageBoxAsync( this, "This is the text.", "This Is The Caption", MessageBoxButton.OkCancel, MessageBoxImage.Information); UpdateResult(result); } private async Task ShowMessageBoxWithDefaultResult() { var result = await _dialogService.ShowMessageBoxAsync( this, "This is the text.", "This Is The Caption", MessageBoxButton.OkCancel, MessageBoxImage.Information, null); UpdateResult(result); } private void UpdateResult(bool? result) => Confirmation = result == true ? "We got confirmation to continue!" : string.Empty; } ================================================ FILE: samples/Avalonia/Demo.FluentMessageBoxContentDialog/Program.cs ================================================ using System; using Avalonia; using ReactiveUI.Avalonia; namespace Demo.Avalonia.FluentMessageBoxContentDialog; class Program { // Initialization code. Don't use any Avalonia, third-party APIs or any // SynchronizationContext-reliant code before AppMain is called: things aren't initialized // yet and stuff might break. [STAThread] public static void Main(string[] args) => BuildAvaloniaApp() .StartWithClassicDesktopLifetime(args); // Avalonia configuration, don't remove; also used by visual designer. public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() .LogToTrace() .UseReactiveUI(rxui => { }); } ================================================ FILE: samples/Avalonia/Demo.FluentMessageBoxContentDialog/ViewLocator.cs ================================================ using HanumanInstitute.MvvmDialogs.Avalonia; namespace Demo.Avalonia.FluentMessageBoxContentDialog; /// /// Maps view models to views in Avalonia. /// public class ViewLocator : ViewLocatorBase { /// protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", ""); } ================================================ FILE: samples/Avalonia/Demo.FluentMessageBoxContentDialog/ViewModelBase.cs ================================================ using ReactiveUI; namespace Demo.Avalonia.FluentMessageBoxContentDialog; public class ViewModelBase : ReactiveObject { } ================================================ FILE: samples/Avalonia/Demo.FluentMessageBoxTaskDialog/App.axaml ================================================ ================================================ FILE: samples/Avalonia/Demo.FluentMessageBoxTaskDialog/App.axaml.cs ================================================ using System; using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.Avalonia; using Microsoft.Extensions.Logging; using Splat; namespace Demo.Avalonia.FluentMessageBoxTaskDialog; public class App : Application { public override void Initialize() { AvaloniaXamlLoader.Load(this); var build = Locator.CurrentMutable; var loggerFactory = LoggerFactory.Create(builder => builder.AddFilter(logLevel => true).AddDebug()); build.RegisterLazySingleton(() => (IDialogService)new DialogService( new DialogManager( viewLocator: new ViewLocator(), logger: loggerFactory.CreateLogger(), dialogFactory: new DialogFactory().AddFluent(FluentMessageBoxType.TaskDialog)), viewModelFactory: x => Locator.Current.GetService(x))); SplatRegistrations.Register(); SplatRegistrations.SetupIOC(); } public override void OnFrameworkInitializationCompleted() { GC.KeepAlive(typeof(DialogService)); if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { desktop.MainWindow = new MainWindow { DataContext = MainWindow }; } base.OnFrameworkInitializationCompleted(); } public static MainWindowViewModel MainWindow => Locator.Current.GetService()!; public static IDialogService DialogService => Locator.Current.GetService()!; } ================================================ FILE: samples/Avalonia/Demo.FluentMessageBoxTaskDialog/Demo.FluentMessageBoxTaskDialog.csproj ================================================  WinExe net10.0 enable default Demo.Avalonia.FluentMessageBoxTaskDialog Demo.Avalonia.FluentMessageBoxTaskDialog all runtime; build; native; contentfiles; analyzers; buildtransitive ================================================ FILE: samples/Avalonia/Demo.FluentMessageBoxTaskDialog/MainWindow.axaml ================================================  ================================================ FILE: samples/Avalonia/Demo.FluentMessageBoxTaskDialog/MainWindow.axaml.cs ================================================ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Avalonia.FluentMessageBoxTaskDialog; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void InitializeComponent() => AvaloniaXamlLoader.Load(this); } ================================================ FILE: samples/Avalonia/Demo.FluentMessageBoxTaskDialog/MainWindowViewModel.cs ================================================ using System.Threading.Tasks; using System.Windows.Input; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.FrameworkDialogs; using ReactiveUI; namespace Demo.Avalonia.FluentMessageBoxTaskDialog; public class MainWindowViewModel : ViewModelBase { private readonly IDialogService _dialogService; public ICommand ShowMessageBoxWithMessageCommand { get; } public ICommand ShowMessageBoxWithCaptionCommand { get; } public ICommand ShowMessageBoxWithButtonCommand { get; } public ICommand ShowMessageBoxWithIconCommand { get; } public ICommand ShowMessageBoxWithDefaultResultCommand { get; } public MainWindowViewModel(IDialogService dialogService) { this._dialogService = dialogService; ShowMessageBoxWithMessageCommand = ReactiveCommand.CreateFromTask(ShowMessageBoxWithMessage); ShowMessageBoxWithCaptionCommand = ReactiveCommand.CreateFromTask(ShowMessageBoxWithCaption); ShowMessageBoxWithButtonCommand = ReactiveCommand.CreateFromTask(ShowMessageBoxWithButton); ShowMessageBoxWithIconCommand = ReactiveCommand.CreateFromTask(ShowMessageBoxWithIcon); ShowMessageBoxWithDefaultResultCommand = ReactiveCommand.CreateFromTask(ShowMessageBoxWithDefaultResult); } private string _confirmation = string.Empty; public string Confirmation { get => _confirmation; private set => this.RaiseAndSetIfChanged(ref _confirmation, value, nameof(Confirmation)); } private async Task ShowMessageBoxWithMessage() { var result = await _dialogService.ShowMessageBoxAsync( this, "This is the text."); UpdateResult(result); } private async Task ShowMessageBoxWithCaption() { var result = await _dialogService.ShowMessageBoxAsync( this, "This is the text.", "This Is The Caption"); UpdateResult(result); } private async Task ShowMessageBoxWithButton() { var result = await _dialogService.ShowMessageBoxAsync( this, "This is the text.", "This Is The Caption", MessageBoxButton.OkCancel); UpdateResult(result); } private async Task ShowMessageBoxWithIcon() { var result = await _dialogService.ShowMessageBoxAsync( this, "This is the text.", "This Is The Caption", MessageBoxButton.OkCancel, MessageBoxImage.Information); UpdateResult(result); } private async Task ShowMessageBoxWithDefaultResult() { var result = await _dialogService.ShowMessageBoxAsync( this, "This is the text.", "This Is The Caption", MessageBoxButton.OkCancel, MessageBoxImage.Information, true); UpdateResult(result); } private void UpdateResult(bool? result) => Confirmation = result == true ? "We got confirmation to continue!" : string.Empty; } ================================================ FILE: samples/Avalonia/Demo.FluentMessageBoxTaskDialog/Program.cs ================================================ using System; using Avalonia; using ReactiveUI.Avalonia; namespace Demo.Avalonia.FluentMessageBoxTaskDialog; class Program { // Initialization code. Don't use any Avalonia, third-party APIs or any // SynchronizationContext-reliant code before AppMain is called: things aren't initialized // yet and stuff might break. [STAThread] public static void Main(string[] args) => BuildAvaloniaApp() .StartWithClassicDesktopLifetime(args); // Avalonia configuration, don't remove; also used by visual designer. public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() .LogToTrace() .UseReactiveUI(rxui => { }); } ================================================ FILE: samples/Avalonia/Demo.FluentMessageBoxTaskDialog/ViewLocator.cs ================================================ using HanumanInstitute.MvvmDialogs.Avalonia; namespace Demo.Avalonia.FluentMessageBoxTaskDialog; /// /// Maps view models to views in Avalonia. /// public class ViewLocator : ViewLocatorBase { /// protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", ""); } ================================================ FILE: samples/Avalonia/Demo.FluentMessageBoxTaskDialog/ViewModelBase.cs ================================================ using ReactiveUI; namespace Demo.Avalonia.FluentMessageBoxTaskDialog; public class ViewModelBase : ReactiveObject { } ================================================ FILE: samples/Avalonia/Demo.FluentTaskDialog/App.axaml ================================================ ================================================ FILE: samples/Avalonia/Demo.FluentTaskDialog/App.axaml.cs ================================================ using System; using Avalonia; using Avalonia.Markup.Xaml; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.Avalonia; using Microsoft.Extensions.Logging; using Splat; namespace Demo.Avalonia.FluentTaskDialog; public class App : Application { public override void Initialize() { AvaloniaXamlLoader.Load(this); var build = Locator.CurrentMutable; var loggerFactory = LoggerFactory.Create(builder => builder.AddFilter(logLevel => true).AddDebug()); build.RegisterLazySingleton(() => (IDialogService)new DialogService( new DialogManager( viewLocator: new ViewLocator(), logger: loggerFactory.CreateLogger(), dialogFactory: new DialogFactory().AddFluent()), viewModelFactory: x => Locator.Current.GetService(x))); SplatRegistrations.Register(); SplatRegistrations.Register(); SplatRegistrations.Register(); SplatRegistrations.SetupIOC(); } public override void OnFrameworkInitializationCompleted() { GC.KeepAlive(typeof(DialogService)); DialogService.Show(null, Main); base.OnFrameworkInitializationCompleted(); } public static MainViewModel Main => Locator.Current.GetService()!; public static CurrentTimeViewModel CurrentTime => Locator.Current.GetService()!; public static AskTextBoxViewModel AskTextBox => Locator.Current.GetService()!; public static IDialogService DialogService => Locator.Current.GetService()!; } ================================================ FILE: samples/Avalonia/Demo.FluentTaskDialog/AskTextBoxView.axaml ================================================ ================================================ FILE: samples/Avalonia/Demo.FluentTaskDialog/AskTextBoxView.axaml.cs ================================================ using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Avalonia.FluentTaskDialog; public partial class AskTextBoxView : UserControl { public AskTextBoxView() { InitializeComponent(); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } } ================================================ FILE: samples/Avalonia/Demo.FluentTaskDialog/AskTextBoxViewModel.cs ================================================ using ReactiveUI.SourceGenerators; namespace Demo.Avalonia.FluentTaskDialog; public partial class AskTextBoxViewModel : ViewModelBase { [Reactive] public partial string Title { get; set; } = "Title"; [Reactive] public partial string Text { get; set; } = string.Empty; } ================================================ FILE: samples/Avalonia/Demo.FluentTaskDialog/CurrentTimeView.axaml ================================================  ================================================ FILE: samples/Avalonia/Demo.FluentTaskDialog/CurrentTimeView.axaml.cs ================================================ using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Avalonia.FluentTaskDialog; public partial class CurrentTimeView : UserControl { public CurrentTimeView() { InitializeComponent(); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } } ================================================ FILE: samples/Avalonia/Demo.FluentTaskDialog/CurrentTimeViewModel.cs ================================================ using System; using System.ComponentModel; using System.Reactive.Linq; using System.Threading.Tasks; using HanumanInstitute.MvvmDialogs; using ReactiveUI; namespace Demo.Avalonia.FluentTaskDialog; public class CurrentTimeViewModel : ViewModelBase, IViewClosing { public DateTime CurrentTime => DateTime.Now; public bool ConfirmClose { get; set; } public bool StayOpen { get; set; } public CurrentTimeViewModel() => Observable.Timer(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1)).Subscribe((_) => { this.RaisePropertyChanged(nameof(CurrentTime)); }); public void OnClosing(CancelEventArgs e) { if (ConfirmClose) { e.Cancel = StayOpen; } } public Task OnClosingAsync(CancelEventArgs e) => Task.CompletedTask; } ================================================ FILE: samples/Avalonia/Demo.FluentTaskDialog/Demo.FluentTaskDialog.csproj ================================================  WinExe net10.0 enable default Demo.Avalonia.FluentTaskDialog Demo.Avalonia.FluentTaskDialog all runtime; build; native; contentfiles; analyzers; buildtransitive all runtime; build; native; contentfiles; analyzers; buildtransitive CurrentTimeView.axaml Code MessageView.axaml Code AskTextBoxView.axaml Code ================================================ FILE: samples/Avalonia/Demo.FluentTaskDialog/FodyWeavers.xml ================================================  ================================================ FILE: samples/Avalonia/Demo.FluentTaskDialog/FodyWeavers.xsd ================================================  'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. A comma-separated list of error codes that can be safely ignored in assembly verification. 'false' to turn off automatic generation of the XML Schema file. ================================================ FILE: samples/Avalonia/Demo.FluentTaskDialog/MainView.axaml ================================================  ================================================ FILE: samples/Avalonia/Demo.FluentTaskDialog/MainView.axaml.cs ================================================ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Avalonia.FluentTaskDialog; public partial class MainView : Window { public MainView() { InitializeComponent(); } private void InitializeComponent() => AvaloniaXamlLoader.Load(this); } ================================================ FILE: samples/Avalonia/Demo.FluentTaskDialog/MainViewModel.cs ================================================ using System.Collections.Generic; using System.Reactive; using System.Threading.Tasks; using FluentAvalonia.UI.Controls; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.Avalonia.Fluent; using ReactiveUI; using ReactiveUI.SourceGenerators; namespace Demo.Avalonia.FluentTaskDialog; public partial class MainViewModel : ViewModelBase { private readonly IDialogService _dialogService; public ReactiveCommand ShowMessageBox { get; } public ReactiveCommand AskText { get; } public ReactiveCommand ShowViewModel { get; } public ReactiveCommand ShowControl { get; } public MainViewModel(IDialogService dialogService) { this._dialogService = dialogService; ShowMessageBox = ReactiveCommand.CreateFromTask(ShowMessageBoxImplAsync); AskText = ReactiveCommand.CreateFromTask(AskTextImplAsync); ShowViewModel = ReactiveCommand.CreateFromTask(ShowViewModelImplAsync); ShowControl = ReactiveCommand.CreateFromTask(ShowControlImplAsync); } [Reactive] public partial string? TextOutput { get; set; } private async Task ShowMessageBoxImplAsync() { TaskDialogSettings settings = new() { Content = "This is the text.", Title = "This Is The Caption", Buttons = new List() { FATaskDialogButton.OKButton, FATaskDialogButton.CancelButton } }; var result = await _dialogService.ShowTaskDialogAsync(this, settings); UpdateResult(result == FATaskDialogStandardResult.OK); } private void UpdateResult(bool? result) => TextOutput = result == true ? "We got confirmation to continue!" : string.Empty; private async Task AskTextImplAsync() { var vm = _dialogService.CreateViewModel(); vm.Title = "Title within the View"; TaskDialogSettings settings = new() { Content = vm, Title = "Please enter some text", Buttons = new List() { FATaskDialogButton.OKButton, FATaskDialogButton.CancelButton } }; var result = await _dialogService.ShowTaskDialogAsync(this, settings); if (result == FATaskDialogStandardResult.OK) { TextOutput = vm.Text; } } private async Task ShowViewModelImplAsync() { var dialogViewModel = _dialogService.CreateViewModel(); dialogViewModel.ConfirmClose = true; await _dialogService.ShowTaskDialogAsync(this, new TaskDialogSettings(dialogViewModel) { Buttons = new List() { FATaskDialogButton.OKButton } }).ConfigureAwait(true); } private async Task ShowControlImplAsync() { var content = new MessageView(); var result = await _dialogService.ShowTaskDialogAsync(this, new TaskDialogSettings(content) { Buttons = new List() { FATaskDialogButton.OKButton } }).ConfigureAwait(true); TextOutput = result.ToString(); } } ================================================ FILE: samples/Avalonia/Demo.FluentTaskDialog/MessageView.axaml ================================================ ================================================ FILE: samples/Avalonia/Demo.FluentTaskDialog/MessageView.axaml.cs ================================================ using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Avalonia.FluentTaskDialog; public partial class MessageView : UserControl { public MessageView() { InitializeComponent(); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } } ================================================ FILE: samples/Avalonia/Demo.FluentTaskDialog/Program.cs ================================================ using System; using Avalonia; using ReactiveUI.Avalonia; namespace Demo.Avalonia.FluentTaskDialog; class Program { // Initialization code. Don't use any Avalonia, third-party APIs or any // SynchronizationContext-reliant code before AppMain is called: things aren't initialized // yet and stuff might break. [STAThread] public static void Main(string[] args) => BuildAvaloniaApp() .StartWithClassicDesktopLifetime(args); // Avalonia configuration, don't remove; also used by visual designer. public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() .LogToTrace() .UseReactiveUI(rxui => { }); } ================================================ FILE: samples/Avalonia/Demo.FluentTaskDialog/ViewLocator.cs ================================================ using HanumanInstitute.MvvmDialogs.Avalonia; namespace Demo.Avalonia.FluentTaskDialog; /// /// Maps view models to views in Avalonia. /// public class ViewLocator : ViewLocatorBase { /// protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", "View"); } ================================================ FILE: samples/Avalonia/Demo.FluentTaskDialog/ViewModelBase.cs ================================================ using ReactiveUI; namespace Demo.Avalonia.FluentTaskDialog; public class ViewModelBase : ReactiveObject { } ================================================ FILE: samples/Avalonia/Demo.Logging/AddTextDialog.axaml ================================================  ================================================ FILE: samples/Avalonia/Demo.Logging/MainWindow.axaml.cs ================================================ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Logging; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); #if DEBUG this.AttachDevTools(); #endif } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } } ================================================ FILE: samples/Avalonia/Demo.Logging/MainWindowViewModel.cs ================================================ using System; using System.Collections.ObjectModel; using System.Threading.Tasks; using System.Windows.Input; using HanumanInstitute.MvvmDialogs; using ReactiveUI; namespace Demo.Logging; public class MainWindowViewModel : ViewModelBase { private readonly IDialogService dialogService; public ICommand ImplicitShowDialogCommand { get; } public ICommand ExplicitShowDialogCommand { get; } public ObservableCollection Texts { get; } = new ObservableCollection(); public MainWindowViewModel(IDialogService dialogService) { this.dialogService = dialogService; ImplicitShowDialogCommand = ReactiveCommand.Create(ImplicitShowDialog); ExplicitShowDialogCommand = ReactiveCommand.Create(ExplicitShowDialog); } private Task ImplicitShowDialog() => ShowDialogAsync(viewModel => dialogService.ShowDialogAsync(this, viewModel)); private Task ExplicitShowDialog() => ShowDialogAsync(viewModel => dialogService.ShowDialogAsync(this, viewModel)); private async Task ShowDialogAsync(Func> showDialogAsync) { var dialogViewModel = new AddTextDialogViewModel(); var success = await showDialogAsync(dialogViewModel).ConfigureAwait(true); if (success == true) { Texts.Add(dialogViewModel.Text); } } } ================================================ FILE: samples/Avalonia/Demo.Logging/Program.cs ================================================ using System; using Avalonia; using Avalonia.ReactiveUI; namespace Demo.Logging; class Program { // Initialization code. Don't use any Avalonia, third-party APIs or any // SynchronizationContext-reliant code before AppMain is called: things aren't initialized // yet and stuff might break. [STAThread] public static void Main(string[] args) => BuildAvaloniaApp() .StartWithClassicDesktopLifetime(args); // Avalonia configuration, don't remove; also used by visual designer. public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() .LogToTrace() .UseReactiveUI(); } ================================================ FILE: samples/Avalonia/Demo.Logging/ViewLocator.cs ================================================ using HanumanInstitute.MvvmDialogs.Avalonia; namespace Demo.Logging; /// /// Maps view models to views in Avalonia. /// public class ViewLocator : ViewLocatorBase { /// protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", ""); } ================================================ FILE: samples/Avalonia/Demo.Logging/ViewModelBase.cs ================================================ using ReactiveUI; namespace Demo.Logging; public class ViewModelBase : ReactiveObject { } ================================================ FILE: samples/Avalonia/Demo.MessageBox/App.axaml ================================================ ================================================ FILE: samples/Avalonia/Demo.MessageBox/App.axaml.cs ================================================ using System; using Avalonia; using Avalonia.Markup.Xaml; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.Avalonia; using Microsoft.Extensions.Logging; using Splat; namespace Demo.Avalonia.MessageBox; public class App : Application { public override void Initialize() { AvaloniaXamlLoader.Load(this); var build = Locator.CurrentMutable; var loggerFactory = LoggerFactory.Create(builder => builder.AddFilter(logLevel => true).AddDebug()); build.RegisterLazySingleton(() => (IDialogService)new DialogService( new DialogManager( viewLocator: new ViewLocator(), logger: loggerFactory.CreateLogger(), dialogFactory: new DialogFactory().AddMessageBox()), viewModelFactory: x => Locator.Current.GetService(x))); SplatRegistrations.Register(); SplatRegistrations.SetupIOC(); } public override void OnFrameworkInitializationCompleted() { GC.KeepAlive(typeof(DialogService)); DialogService.Show(null, MainWindow); base.OnFrameworkInitializationCompleted(); } public static MainWindowViewModel MainWindow => Locator.Current.GetService()!; public static IDialogService DialogService => Locator.Current.GetService()!; } ================================================ FILE: samples/Avalonia/Demo.MessageBox/Demo.MessageBox.csproj ================================================  WinExe net10.0 enable default Demo.Avalonia.MessageBox Demo.Avalonia.MessageBox 1.0.0.24361 1.0.0.24361 all runtime; build; native; contentfiles; analyzers; buildtransitive ================================================ FILE: samples/Avalonia/Demo.MessageBox/MainWindow.axaml ================================================  ================================================ FILE: samples/Avalonia/Demo.MessageBox/MainWindow.axaml.cs ================================================ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Avalonia.MessageBox; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void InitializeComponent() => AvaloniaXamlLoader.Load(this); } ================================================ FILE: samples/Avalonia/Demo.MessageBox/MainWindowViewModel.cs ================================================ using System.Threading.Tasks; using System.Windows.Input; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.FrameworkDialogs; using ReactiveUI; namespace Demo.Avalonia.MessageBox; public class MainWindowViewModel : ViewModelBase { private readonly IDialogService _dialogService; public ICommand ShowMessageBoxWithMessageCommand { get; } public ICommand ShowMessageBoxWithCaptionCommand { get; } public ICommand ShowMessageBoxWithButtonCommand { get; } public ICommand ShowMessageBoxWithIconCommand { get; } public ICommand ShowMessageBoxWithDefaultResultCommand { get; } public MainWindowViewModel(IDialogService dialogService) { this._dialogService = dialogService; ShowMessageBoxWithMessageCommand = ReactiveCommand.CreateFromTask(ShowMessageBoxWithMessage); ShowMessageBoxWithCaptionCommand = ReactiveCommand.CreateFromTask(ShowMessageBoxWithCaption); ShowMessageBoxWithButtonCommand = ReactiveCommand.CreateFromTask(ShowMessageBoxWithButton); ShowMessageBoxWithIconCommand = ReactiveCommand.CreateFromTask(ShowMessageBoxWithIcon); ShowMessageBoxWithDefaultResultCommand = ReactiveCommand.CreateFromTask(ShowMessageBoxWithDefaultResult); } private string _confirmation = string.Empty; public string Confirmation { get => _confirmation; private set => this.RaiseAndSetIfChanged(ref _confirmation, value, nameof(Confirmation)); } private async Task ShowMessageBoxWithMessage() { var result = await _dialogService.ShowMessageBoxAsync( this, "This is the text."); UpdateResult(result); } private async Task ShowMessageBoxWithCaption() { var result = await _dialogService.ShowMessageBoxAsync( this, "This is the text.", "This Is The Caption"); UpdateResult(result); } private async Task ShowMessageBoxWithButton() { var result = await _dialogService.ShowMessageBoxAsync( this, "This is the text.", "This Is The Caption", MessageBoxButton.OkCancel); UpdateResult(result); } private async Task ShowMessageBoxWithIcon() { var result = await _dialogService.ShowMessageBoxAsync( this, "This is the text.", "This Is The Caption", MessageBoxButton.OkCancel, MessageBoxImage.Information); UpdateResult(result); } private async Task ShowMessageBoxWithDefaultResult() { var result = await _dialogService.ShowMessageBoxAsync( this, "This is the text.", "This Is The Caption", MessageBoxButton.OkCancel, MessageBoxImage.Information, null); UpdateResult(result); } private void UpdateResult(bool? result) => Confirmation = result == true ? "We got confirmation to continue!" : string.Empty; } ================================================ FILE: samples/Avalonia/Demo.MessageBox/Program.cs ================================================ using System; using Avalonia; using ReactiveUI.Avalonia; namespace Demo.Avalonia.MessageBox; class Program { // Initialization code. Don't use any Avalonia, third-party APIs or any // SynchronizationContext-reliant code before AppMain is called: things aren't initialized // yet and stuff might break. [STAThread] public static void Main(string[] args) => BuildAvaloniaApp() .StartWithClassicDesktopLifetime(args); // Avalonia configuration, don't remove; also used by visual designer. public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() .LogToTrace() .UseReactiveUI(rxui => { }); } ================================================ FILE: samples/Avalonia/Demo.MessageBox/ViewLocator.cs ================================================ using HanumanInstitute.MvvmDialogs.Avalonia; namespace Demo.Avalonia.MessageBox; /// /// Maps view models to views in Avalonia. /// public class ViewLocator : ViewLocatorBase { /// protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", ""); } ================================================ FILE: samples/Avalonia/Demo.MessageBox/ViewModelBase.cs ================================================ using ReactiveUI; namespace Demo.Avalonia.MessageBox; public class ViewModelBase : ReactiveObject { } ================================================ FILE: samples/Avalonia/Demo.ModalCustomDialog/AddTextCustomDialog.cs ================================================ using System; using System.Collections.Generic; using System.ComponentModel; using System.Threading.Tasks; using Avalonia.Controls; using HanumanInstitute.MvvmDialogs; namespace Demo.Avalonia.ModalCustomDialog; public class AddTextCustomDialog : IView { public void Initialize(INotifyPropertyChanged viewModel, ViewDefinition viewDef) { ViewModel = viewModel; } public void InitializeExisting(INotifyPropertyChanged viewModel, object view) { ViewModel = viewModel; } public Type ViewType { get; set; } = default!; public object RefObj => this; public AddTextDialog Ref { get; } = new(); public event EventHandler Loaded { add => Ref.Opened += value; remove => Ref.Opened -= value; } public event EventHandler Closed { add => Ref.Closed += value; remove => Ref.Closed -= value; } public event EventHandler? Closing { add { if (value != null) { var handler = new EventHandler(value.Invoke); _closingHandlers.Add(value, handler); Ref.Closing += handler; } } remove { if (value != null) { Ref.Closing += _closingHandlers[value]; _closingHandlers.Remove(value); } } } private readonly Dictionary, EventHandler> _closingHandlers = new(); public INotifyPropertyChanged ViewModel { get => (INotifyPropertyChanged)Ref.DataContext!; set => Ref.DataContext = value; } public INotifyPropertyChanged? Owner { get; set; } public Task ShowDialogAsync(IView owner) => Ref.ShowDialog((Window)owner.RefObj!); public void Show(IView? owner) => Ref.Show((Window)owner!.RefObj); public void Activate() => Ref.Activate(); public void Close() => Ref.Close(); public bool IsEnabled { get => Ref.IsEnabled; set => Ref.IsEnabled = value; } public bool IsVisible => Ref.IsVisible; public bool ClosingConfirmed { get; set; } } ================================================ FILE: samples/Avalonia/Demo.ModalCustomDialog/AddTextCustomDialogViewModel.cs ================================================ using System; using System.Windows.Input; using HanumanInstitute.MvvmDialogs; using ReactiveUI; namespace Demo.Avalonia.ModalCustomDialog; public class AddTextCustomDialogViewModel : ViewModelBase, IModalDialogViewModel, ICloseable { private string _text = string.Empty; private bool? _dialogResult; public ICommand OkCommand { get; } public event EventHandler? RequestClose; public AddTextCustomDialogViewModel() { OkCommand = ReactiveCommand.Create(Ok); } public string Text { get => _text; set => this.RaiseAndSetIfChanged(ref _text, value, nameof(Text)); } public bool? DialogResult { get => _dialogResult; private set => this.RaiseAndSetIfChanged(ref _dialogResult, value, nameof(DialogResult)); } private void Ok() { if (!string.IsNullOrEmpty(Text)) { DialogResult = true; RequestClose?.Invoke(this, EventArgs.Empty); } } public void Cancel() { DialogResult = false; RequestClose?.Invoke(this, EventArgs.Empty); } } ================================================ FILE: samples/Avalonia/Demo.ModalCustomDialog/AddTextDialog.axaml ================================================  ================================================ FILE: samples/Avalonia/Demo.ModalCustomDialog/MainWindow.axaml.cs ================================================ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Avalonia.ModalCustomDialog; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void InitializeComponent() => AvaloniaXamlLoader.Load(this); } ================================================ FILE: samples/Avalonia/Demo.ModalCustomDialog/MainWindowViewModel.cs ================================================ using System; using System.Collections.ObjectModel; using System.Threading.Tasks; using System.Windows.Input; using HanumanInstitute.MvvmDialogs; using ReactiveUI; namespace Demo.Avalonia.ModalCustomDialog; public class MainWindowViewModel : ViewModelBase { private readonly IDialogService _dialogService; public ICommand ImplicitShowDialogCommand { get; } public ICommand ExplicitShowDialogCommand { get; } public ObservableCollection Texts { get; } = new ObservableCollection(); public MainWindowViewModel(IDialogService dialogService) { this._dialogService = dialogService; ImplicitShowDialogCommand = ReactiveCommand.Create(ImplicitShowDialog); ExplicitShowDialogCommand = ReactiveCommand.Create(ExplicitShowDialog); } private Task ImplicitShowDialog() => ShowDialogAsync(viewModel => _dialogService.ShowDialogAsync(this, viewModel)); private Task ExplicitShowDialog() => ShowDialogAsync(viewModel => _dialogService.ShowDialogAsync(this, viewModel)); private async Task ShowDialogAsync(Func> showDialogAsync) { var dialogViewModel = _dialogService.CreateViewModel(); var success = await showDialogAsync(dialogViewModel).ConfigureAwait(true); if (success == true) { Texts.Add(dialogViewModel.Text); } } } ================================================ FILE: samples/Avalonia/Demo.ModalCustomDialog/Program.cs ================================================ using System; using Avalonia; using ReactiveUI.Avalonia; namespace Demo.Avalonia.ModalCustomDialog; class Program { // Initialization code. Don't use any Avalonia, third-party APIs or any // SynchronizationContext-reliant code before AppMain is called: things aren't initialized // yet and stuff might break. [STAThread] public static void Main(string[] args) => BuildAvaloniaApp() .StartWithClassicDesktopLifetime(args); // Avalonia configuration, don't remove; also used by visual designer. public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() .LogToTrace() .UseReactiveUI(rxui => { }); } ================================================ FILE: samples/Avalonia/Demo.ModalCustomDialog/ViewLocator.cs ================================================ using HanumanInstitute.MvvmDialogs.Avalonia; namespace Demo.Avalonia.ModalCustomDialog; /// /// Maps view models to views in Avalonia. /// public class ViewLocator : ViewLocatorBase { /// protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", ""); } ================================================ FILE: samples/Avalonia/Demo.ModalCustomDialog/ViewModelBase.cs ================================================ using ReactiveUI; namespace Demo.Avalonia.ModalCustomDialog; public class ViewModelBase : ReactiveObject { } ================================================ FILE: samples/Avalonia/Demo.ModalDialog/AddTextDialog.axaml ================================================  ================================================ FILE: samples/Avalonia/Demo.ModalDialog/MainWindow.axaml.cs ================================================ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Avalonia.ModalDialog; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } } ================================================ FILE: samples/Avalonia/Demo.ModalDialog/MainWindowViewModel.cs ================================================ using System; using System.Collections.ObjectModel; using System.Threading.Tasks; using System.Windows.Input; using HanumanInstitute.MvvmDialogs; using ReactiveUI; namespace Demo.Avalonia.ModalDialog; public class MainWindowViewModel : ViewModelBase { private readonly IDialogService _dialogService; public ICommand ImplicitShowDialogCommand { get; } public ICommand ExplicitShowDialogCommand { get; } public ObservableCollection Texts { get; } = new ObservableCollection(); public MainWindowViewModel(IDialogService dialogService) { this._dialogService = dialogService; ImplicitShowDialogCommand = ReactiveCommand.Create(ImplicitShowDialog); ExplicitShowDialogCommand = ReactiveCommand.Create(ExplicitShowDialog); } private Task ImplicitShowDialog() => ShowDialogAsync(viewModel => _dialogService.ShowDialogAsync(this, viewModel)); private Task ExplicitShowDialog() => ShowDialogAsync(viewModel => _dialogService.ShowDialogAsync(this, viewModel)); private async Task ShowDialogAsync(Func> showDialogAsync) { var dialogViewModel = _dialogService.CreateViewModel(); var success = await showDialogAsync(dialogViewModel).ConfigureAwait(true); if (success == true) { Texts.Add(dialogViewModel.Text); } } } ================================================ FILE: samples/Avalonia/Demo.ModalDialog/Program.cs ================================================ using System; using Avalonia; using ReactiveUI.Avalonia; namespace Demo.Avalonia.ModalDialog; class Program { // Initialization code. Don't use any Avalonia, third-party APIs or any // SynchronizationContext-reliant code before AppMain is called: things aren't initialized // yet and stuff might break. [STAThread] public static void Main(string[] args) => BuildAvaloniaApp() .StartWithClassicDesktopLifetime(args); // Avalonia configuration, don't remove; also used by visual designer. public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() .LogToTrace() .UseReactiveUI(rxui => { }); } ================================================ FILE: samples/Avalonia/Demo.ModalDialog/ViewLocator.cs ================================================ using HanumanInstitute.MvvmDialogs.Avalonia; namespace Demo.Avalonia.ModalDialog; /// /// Maps view models to views in Avalonia. /// public class ViewLocator : ViewLocatorBase { /// protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", ""); } ================================================ FILE: samples/Avalonia/Demo.ModalDialog/ViewModelBase.cs ================================================ using ReactiveUI; namespace Demo.Avalonia.ModalDialog; public class ViewModelBase : ReactiveObject { } ================================================ FILE: samples/Avalonia/Demo.ModalDialog.Tests/Demo.ModalDialog.Tests.csproj ================================================  net10.0 Exe enable false Demo.Avalonia.ModalDialog.Tests Demo.Avalonia.ModalDialog.Tests runtime; build; native; contentfiles; analyzers; buildtransitive all runtime; build; native; contentfiles; analyzers; buildtransitive all ================================================ FILE: samples/Avalonia/Demo.ModalDialog.Tests/MainWindowViewModelTests.cs ================================================ using System; using System.ComponentModel; using System.Linq; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.Avalonia; using Xunit; using Moq; namespace Demo.Avalonia.ModalDialog.Tests; public class MainWindowViewModelTests { public MainWindowViewModel Model => _model ??= new MainWindowViewModel(DialogService); private MainWindowViewModel? _model; public DialogService DialogService => _dialogService ??= new DialogService(MockDialogManager.Object, viewModelFactory: ViewModelFactory); private DialogService? _dialogService; public Mock MockDialogManager => _mockDialogManager ??= new Mock(); private Mock? _mockDialogManager; private object? ViewModelFactory(Type type) => (type) switch { _ when type == typeof(AddTextDialogViewModel) => new AddTextDialogViewModel(), _ => null }; [Fact] public void ShowDialogCommand_InputValue_AddToList() { var newText = "abc"; MockDialogManager.Setup(x => x.ShowDialogAsync(It.IsAny(), It.IsAny())) .Callback( (ownerViewModel, viewModel) => { var vm = (AddTextDialogViewModel)viewModel; vm.Text = newText; vm.DialogResult = true; }); Model.ImplicitShowDialogCommand.Execute(null); Assert.Single(Model.Texts); Assert.Equal(newText, Model.Texts.First()); } } ================================================ FILE: samples/Avalonia/Demo.NonModalCustomDialog/App.axaml ================================================ ================================================ FILE: samples/Avalonia/Demo.NonModalCustomDialog/App.axaml.cs ================================================ using System; using Avalonia; using Avalonia.Markup.Xaml; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.Avalonia; using Microsoft.Extensions.Logging; using Splat; namespace Demo.Avalonia.NonModalCustomDialog; public class App : Application { public override void Initialize() { AvaloniaXamlLoader.Load(this); var build = Locator.CurrentMutable; var loggerFactory = LoggerFactory.Create(builder => builder.AddFilter(logLevel => true).AddDebug()); build.RegisterLazySingleton(() => (IDialogService)new DialogService( new DialogManager( viewLocator: new ViewLocator(), logger: loggerFactory.CreateLogger()), viewModelFactory: x => Locator.Current.GetService(x))); SplatRegistrations.Register(); SplatRegistrations.Register(); SplatRegistrations.SetupIOC(); } public override void OnFrameworkInitializationCompleted() { GC.KeepAlive(typeof(DialogService)); DialogService.Show(null, MainWindow); base.OnFrameworkInitializationCompleted(); } public static MainWindowViewModel MainWindow => Locator.Current.GetService()!; public static CurrentTimeCustomDialogViewModel CurrentTimeDialog => Locator.Current.GetService()!; public static IDialogService DialogService => Locator.Current.GetService()!; } ================================================ FILE: samples/Avalonia/Demo.NonModalCustomDialog/CurrentTimeCustomDialog.cs ================================================ using System; using System.Collections.Generic; using System.ComponentModel; using System.Threading.Tasks; using Avalonia.Controls; using HanumanInstitute.MvvmDialogs; namespace Demo.Avalonia.NonModalCustomDialog; public class CurrentTimeCustomDialog : IView { private readonly CurrentTimeDialog _dialog = new(); public void Initialize(INotifyPropertyChanged viewModel, ViewDefinition viewDef) { ViewModel = viewModel; } public void InitializeExisting(INotifyPropertyChanged viewModel, object view) { ViewModel = viewModel; } public Type ViewType { get; set; } = default!; public object RefObj => this; public event EventHandler Loaded { add => _dialog.Opened += value; remove => _dialog.Opened -= value; } public event EventHandler Closed { add => _dialog.Closed += value; remove => _dialog.Closed -= value; } public event EventHandler? Closing { add { if (value != null) { var handler = new EventHandler(value.Invoke); _closingHandlers.Add(value, handler); _dialog.Closing += handler; } } remove { if (value != null) { _dialog.Closing += _closingHandlers[value]; _closingHandlers.Remove(value); } } } private readonly Dictionary, EventHandler> _closingHandlers = new(); public INotifyPropertyChanged ViewModel { get => (INotifyPropertyChanged)_dialog.DataContext!; set => _dialog.DataContext = value; } public Task ShowDialogAsync(IView owner) { return _dialog.ShowDialog((Window)owner.RefObj); } public void Show(IView? owner) => _dialog.Show((Window)owner!.RefObj); public void Activate() => _dialog.Activate(); public void Close() => _dialog.Close(); public bool IsEnabled { get => _dialog.IsEnabled; set => _dialog.IsEnabled = value; } public bool IsVisible => _dialog.IsEnabled; public bool ClosingConfirmed { get; set; } } ================================================ FILE: samples/Avalonia/Demo.NonModalCustomDialog/CurrentTimeCustomDialogViewModel.cs ================================================ using System; using System.Reactive.Linq; using ReactiveUI; namespace Demo.Avalonia.NonModalCustomDialog; public class CurrentTimeCustomDialogViewModel : ViewModelBase { public DateTime CurrentTime => DateTime.Now; public CurrentTimeCustomDialogViewModel() => Observable.Timer(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1)).Subscribe((_) => { this.RaisePropertyChanged(nameof(CurrentTime)); }); } ================================================ FILE: samples/Avalonia/Demo.NonModalCustomDialog/CurrentTimeDialog.axaml ================================================  ================================================ FILE: samples/Avalonia/Demo.NonModalCustomDialog/CurrentTimeDialog.axaml.cs ================================================ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Avalonia.NonModalCustomDialog; public partial class CurrentTimeDialog : Window { public CurrentTimeDialog() { InitializeComponent(); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } } ================================================ FILE: samples/Avalonia/Demo.NonModalCustomDialog/Demo.NonModalCustomDialog.csproj ================================================  WinExe net10.0 enable default Demo.Avalonia.NonModalCustomDialog Demo.Avalonia.NonModalCustomDialog all runtime; build; native; contentfiles; analyzers; buildtransitive ================================================ FILE: samples/Avalonia/Demo.NonModalCustomDialog/MainWindow.axaml ================================================ ================================================ FILE: samples/Avalonia/Demo.NonModalCustomDialog/MainWindow.axaml.cs ================================================ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Avalonia.NonModalCustomDialog; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } } ================================================ FILE: samples/Avalonia/Demo.NonModalCustomDialog/MainWindowViewModel.cs ================================================ using System; using System.Windows.Input; using HanumanInstitute.MvvmDialogs; using ReactiveUI; namespace Demo.Avalonia.NonModalCustomDialog; public class MainWindowViewModel : ViewModelBase { private readonly IDialogService _dialogService; public MainWindowViewModel(IDialogService dialogService) { this._dialogService = dialogService; ImplicitShowCommand = ReactiveCommand.Create(ImplicitShow); ExplicitShowCommand = ReactiveCommand.Create(ExplicitShow); } public ICommand ImplicitShowCommand { get; } public ICommand ExplicitShowCommand { get; } private void ImplicitShow() { Show(viewModel => _dialogService.Show(this, viewModel)); } private void ExplicitShow() { Show(viewModel => _dialogService.Show(this, viewModel)); } private void Show(Action show) { var dialogViewModel = _dialogService.CreateViewModel(); show(dialogViewModel); } } ================================================ FILE: samples/Avalonia/Demo.NonModalCustomDialog/Program.cs ================================================ using System; using Avalonia; using ReactiveUI.Avalonia; namespace Demo.Avalonia.NonModalCustomDialog; class Program { // Initialization code. Don't use any Avalonia, third-party APIs or any // SynchronizationContext-reliant code before AppMain is called: things aren't initialized // yet and stuff might break. [STAThread] public static void Main(string[] args) => BuildAvaloniaApp() .StartWithClassicDesktopLifetime(args); // Avalonia configuration, don't remove; also used by visual designer. public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() .LogToTrace() .UseReactiveUI(rxui => { }); } ================================================ FILE: samples/Avalonia/Demo.NonModalCustomDialog/ViewLocator.cs ================================================ using HanumanInstitute.MvvmDialogs.Avalonia; namespace Demo.Avalonia.NonModalCustomDialog; /// /// Maps view models to views in Avalonia. /// public class ViewLocator : ViewLocatorBase { /// protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", ""); } ================================================ FILE: samples/Avalonia/Demo.NonModalCustomDialog/ViewModelBase.cs ================================================ using ReactiveUI; namespace Demo.Avalonia.NonModalCustomDialog; public class ViewModelBase : ReactiveObject { } ================================================ FILE: samples/Avalonia/Demo.NonModalDialog/App.axaml ================================================ ================================================ FILE: samples/Avalonia/Demo.NonModalDialog/App.axaml.cs ================================================ using System; using Avalonia; using Avalonia.Markup.Xaml; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.Avalonia; using Microsoft.Extensions.Logging; using Splat; namespace Demo.Avalonia.NonModalDialog; public class App : Application { public override void Initialize() { AvaloniaXamlLoader.Load(this); var build = Locator.CurrentMutable; var loggerFactory = LoggerFactory.Create(builder => builder.AddFilter(logLevel => true).AddDebug()); build.RegisterLazySingleton(() => (IDialogService)new DialogService( new DialogManager( viewLocator: new ViewLocator(), logger: loggerFactory.CreateLogger()), viewModelFactory: x => Locator.Current.GetService(x))); SplatRegistrations.Register(); SplatRegistrations.Register(); SplatRegistrations.SetupIOC(); } public override void OnFrameworkInitializationCompleted() { GC.KeepAlive(typeof(DialogService)); DialogService.Show(null, MainWindow); base.OnFrameworkInitializationCompleted(); } public static MainWindowViewModel MainWindow => Locator.Current.GetService()!; public static CurrentTimeDialogViewModel CurrentTimeDialog => Locator.Current.GetService()!; public static IDialogService DialogService => Locator.Current.GetService()!; } ================================================ FILE: samples/Avalonia/Demo.NonModalDialog/CurrentTimeDialog.axaml ================================================  ================================================ FILE: samples/Avalonia/Demo.NonModalDialog/CurrentTimeDialog.axaml.cs ================================================ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Avalonia.NonModalDialog; public partial class CurrentTimeDialog : Window { public CurrentTimeDialog() { InitializeComponent(); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } } ================================================ FILE: samples/Avalonia/Demo.NonModalDialog/CurrentTimeDialogViewModel.cs ================================================ using System; using System.Reactive.Linq; using ReactiveUI; namespace Demo.Avalonia.NonModalDialog; public class CurrentTimeDialogViewModel : ViewModelBase { public DateTime CurrentTime => DateTime.Now; public CurrentTimeDialogViewModel() => Observable.Timer(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1)).Subscribe((_) => { this.RaisePropertyChanged(nameof(CurrentTime)); }); } ================================================ FILE: samples/Avalonia/Demo.NonModalDialog/Demo.NonModalDialog.csproj ================================================  WinExe net10.0 enable default Demo.Avalonia.NonModalDialog Demo.Avalonia.NonModalDialog all runtime; build; native; contentfiles; analyzers; buildtransitive %(Filename) ================================================ FILE: samples/Avalonia/Demo.NonModalDialog/MainWindow.axaml ================================================ ================================================ FILE: samples/Avalonia/Demo.NonModalDialog/MainWindow.axaml.cs ================================================ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Avalonia.NonModalDialog; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } } ================================================ FILE: samples/Avalonia/Demo.NonModalDialog/MainWindowViewModel.cs ================================================ using System; using System.Windows.Input; using HanumanInstitute.MvvmDialogs; using ReactiveUI; namespace Demo.Avalonia.NonModalDialog; public class MainWindowViewModel : ViewModelBase { private readonly IDialogService _dialogService; public MainWindowViewModel(IDialogService dialogService) { this._dialogService = dialogService; ImplicitShowCommand = ReactiveCommand.Create(ImplicitShow); ExplicitShowCommand = ReactiveCommand.Create(ExplicitShow); } public ICommand ImplicitShowCommand { get; } public ICommand ExplicitShowCommand { get; } private void ImplicitShow() { Show(viewModel => _dialogService.Show(this, viewModel)); } private void ExplicitShow() { Show(viewModel => _dialogService.Show(this, viewModel)); } private void Show(Action show) { var dialogViewModel = _dialogService.CreateViewModel(); show(dialogViewModel); } } ================================================ FILE: samples/Avalonia/Demo.NonModalDialog/Program.cs ================================================ using System; using Avalonia; using ReactiveUI.Avalonia; namespace Demo.Avalonia.NonModalDialog; class Program { // Initialization code. Don't use any Avalonia, third-party APIs or any // SynchronizationContext-reliant code before AppMain is called: things aren't initialized // yet and stuff might break. [STAThread] public static void Main(string[] args) => BuildAvaloniaApp() .StartWithClassicDesktopLifetime(args); // Avalonia configuration, don't remove; also used by visual designer. public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() .LogToTrace() .UseReactiveUI(rxui => { }); } ================================================ FILE: samples/Avalonia/Demo.NonModalDialog/ViewLocator.cs ================================================ using HanumanInstitute.MvvmDialogs.Avalonia; namespace Demo.Avalonia.NonModalDialog; /// /// Maps view models to views in Avalonia. /// public class ViewLocator : ViewLocatorBase { /// protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", ""); } ================================================ FILE: samples/Avalonia/Demo.NonModalDialog/ViewModelBase.cs ================================================ using ReactiveUI; namespace Demo.Avalonia.NonModalDialog; public class ViewModelBase : ReactiveObject { } ================================================ FILE: samples/Avalonia/Demo.OpenFileDialog/App.axaml ================================================ ================================================ FILE: samples/Avalonia/Demo.OpenFileDialog/App.axaml.cs ================================================ using System; using Avalonia; using Avalonia.Markup.Xaml; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.Avalonia; using Microsoft.Extensions.Logging; using Splat; namespace Demo.Avalonia.OpenFileDialog; public class App : Application { public override void Initialize() { AvaloniaXamlLoader.Load(this); var build = Locator.CurrentMutable; var loggerFactory = LoggerFactory.Create(builder => builder.AddFilter(logLevel => true).AddDebug()); build.RegisterLazySingleton(() => (IDialogService)new DialogService( new DialogManager( viewLocator: new ViewLocator(), logger: loggerFactory.CreateLogger(), dialogFactory: new DialogFactory().AddMessageBox()), viewModelFactory: x => Locator.Current.GetService(x))); SplatRegistrations.Register(); SplatRegistrations.SetupIOC(); } public override void OnFrameworkInitializationCompleted() { GC.KeepAlive(typeof(DialogService)); DialogService.Show(null, MainWindow); base.OnFrameworkInitializationCompleted(); } public static MainWindowViewModel MainWindow => Locator.Current.GetService()!; public static IDialogService DialogService => Locator.Current.GetService()!; } ================================================ FILE: samples/Avalonia/Demo.OpenFileDialog/Demo.OpenFileDialog.csproj ================================================  WinExe net10.0 enable default Demo.Avalonia.OpenFileDialog Demo.Avalonia.OpenFileDialog all runtime; build; native; contentfiles; analyzers; buildtransitive ================================================ FILE: samples/Avalonia/Demo.OpenFileDialog/MainWindow.axaml ================================================ ================================================ FILE: samples/Avalonia/Demo.StrongLocator/MainWindow.axaml.cs ================================================ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Avalonia.StrongLocator; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } } ================================================ FILE: samples/Avalonia/Demo.StrongLocator/MainWindowViewModel.cs ================================================ using System; using System.Collections.ObjectModel; using System.Threading.Tasks; using System.Windows.Input; using HanumanInstitute.MvvmDialogs; using ReactiveUI; namespace Demo.Avalonia.StrongLocator; public class MainWindowViewModel : ViewModelBase { private readonly IDialogService _dialogService; public ICommand ImplicitShowDialogCommand { get; } public ICommand ExplicitShowDialogCommand { get; } public ObservableCollection Texts { get; } = new ObservableCollection(); public MainWindowViewModel(IDialogService dialogService) { this._dialogService = dialogService; ImplicitShowDialogCommand = ReactiveCommand.Create(ImplicitShowDialog); ExplicitShowDialogCommand = ReactiveCommand.Create(ExplicitShowDialog); } private Task ImplicitShowDialog() => ShowDialogAsync(viewModel => _dialogService.ShowDialogAsync(this, viewModel)); private Task ExplicitShowDialog() => ShowDialogAsync(viewModel => _dialogService.ShowDialogAsync(this, viewModel)); private async Task ShowDialogAsync(Func> showDialogAsync) { var dialogViewModel = _dialogService.CreateViewModel(); var success = await showDialogAsync(dialogViewModel).ConfigureAwait(true); if (success == true) { Texts.Add(dialogViewModel.Text); } } } ================================================ FILE: samples/Avalonia/Demo.StrongLocator/Program.cs ================================================ using System; using Avalonia; using ReactiveUI.Avalonia; namespace Demo.Avalonia.StrongLocator; class Program { // Initialization code. Don't use any Avalonia, third-party APIs or any // SynchronizationContext-reliant code before AppMain is called: things aren't initialized // yet and stuff might break. [STAThread] public static void Main(string[] args) => BuildAvaloniaApp() .StartWithClassicDesktopLifetime(args); // Avalonia configuration, don't remove; also used by visual designer. public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() .LogToTrace() .UseReactiveUI(rxui => { }); } ================================================ FILE: samples/Avalonia/Demo.StrongLocator/ViewLocator.cs ================================================ using HanumanInstitute.MvvmDialogs.Avalonia; namespace Demo.Avalonia.StrongLocator; /// /// Maps view models to views in Avalonia. /// public class ViewLocator : StrongViewLocator { public ViewLocator() { Register(); Register(); } } ================================================ FILE: samples/Avalonia/Demo.StrongLocator/ViewModelBase.cs ================================================ using ReactiveUI; namespace Demo.Avalonia.StrongLocator; public class ViewModelBase : ReactiveObject { } ================================================ FILE: samples/Avalonia/Demo.ViewEvents/App.axaml ================================================ ================================================ FILE: samples/Avalonia/Demo.ViewEvents/App.axaml.cs ================================================ using System; using Avalonia; using Avalonia.Markup.Xaml; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.Avalonia; using Microsoft.Extensions.Logging; using Splat; namespace Demo.Avalonia.ViewEvents; public class App : Application { public override void Initialize() { AvaloniaXamlLoader.Load(this); var build = Locator.CurrentMutable; var loggerFactory = LoggerFactory.Create(builder => builder.AddFilter(logLevel => true).AddDebug()); build.RegisterLazySingleton(() => (IDialogService)new DialogService( new DialogManager( viewLocator: new ViewLocator(), logger: loggerFactory.CreateLogger(), dialogFactory: new DialogFactory().AddFluent()), viewModelFactory: x => Locator.Current.GetService(x))); SplatRegistrations.Register(); SplatRegistrations.SetupIOC(); } public override void OnFrameworkInitializationCompleted() { GC.KeepAlive(typeof(DialogService)); DialogService.Show(null, MainWindow); base.OnFrameworkInitializationCompleted(); } public static MainWindowViewModel MainWindow => Locator.Current.GetService()!; public static IDialogService DialogService => Locator.Current.GetService()!; } ================================================ FILE: samples/Avalonia/Demo.ViewEvents/Demo.ViewEvents.csproj ================================================  WinExe net10.0 enable default Demo.Avalonia.ViewEvents Demo.Avalonia.ViewEvents all runtime; build; native; contentfiles; analyzers; buildtransitive ================================================ FILE: samples/Avalonia/Demo.ViewEvents/MainWindow.axaml ================================================  ================================================ FILE: samples/Avalonia/Demo.ViewEvents/MainWindow.axaml.cs ================================================ using Avalonia; using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace Demo.Avalonia.ViewEvents; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void InitializeComponent() => AvaloniaXamlLoader.Load(this); } ================================================ FILE: samples/Avalonia/Demo.ViewEvents/MainWindowViewModel.cs ================================================ using System.ComponentModel; using System.Threading.Tasks; using HanumanInstitute.MvvmDialogs; using ReactiveUI; namespace Demo.Avalonia.ViewEvents; public class MainWindowViewModel(IDialogService dialogService) : ViewModelBase, IViewLoaded, IViewClosing, IViewClosed { private readonly IDialogService _dialogService = dialogService; public void OnLoaded() { Text = "Loaded!"; } public void OnClosing(CancelEventArgs e) { e.Cancel = true; } public async Task OnClosingAsync(CancelEventArgs e) { var quit = await _dialogService.ShowMessageBoxAsync(this, "Do you really want to quit? ", "Confirmation", HanumanInstitute.MvvmDialogs.FrameworkDialogs.MessageBoxButton.YesNo); e.Cancel = quit != true; } public async void OnClosed() { await _dialogService.ShowMessageBoxAsync(null, "It's over.", "Closed"); } public string Text { get => _text; set => this.RaiseAndSetIfChanged(ref _text, value); } private string _text = string.Empty; } ================================================ FILE: samples/Avalonia/Demo.ViewEvents/Program.cs ================================================ using System; using Avalonia; using ReactiveUI.Avalonia; namespace Demo.Avalonia.ViewEvents; public class Program { // Initialization code. Don't use any Avalonia, third-party APIs or any // SynchronizationContext-reliant code before AppMain is called: things aren't initialized // yet and stuff might break. [STAThread] public static void Main(string[] args) => BuildAvaloniaApp() .StartWithClassicDesktopLifetime(args); // Avalonia configuration, don't remove; also used by visual designer. public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() .LogToTrace() .UseReactiveUI(rxui => { }); } ================================================ FILE: samples/Avalonia/Demo.ViewEvents/ViewLocator.cs ================================================ using HanumanInstitute.MvvmDialogs.Avalonia; namespace Demo.Avalonia.ViewEvents; /// /// Maps view models to views in Avalonia. /// public class ViewLocator : ViewLocatorBase { /// protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", ""); } ================================================ FILE: samples/Avalonia/Demo.ViewEvents/ViewModelBase.cs ================================================ using ReactiveUI; namespace Demo.Avalonia.ViewEvents; public class ViewModelBase : ReactiveObject { } ================================================ FILE: samples/Directory.Build.props ================================================ latest enable Hanuman Institute ================================================ FILE: samples/Wpf/Demo.ActivateNonModalDialog/App.xaml ================================================  ================================================ FILE: samples/Wpf/Demo.ActivateNonModalDialog/App.xaml.cs ================================================ using System.Windows; using CommunityToolkit.Mvvm.DependencyInjection; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.Wpf; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; namespace Demo.Wpf.ActivateNonModalDialog; public partial class App { protected override void OnStartup(StartupEventArgs e) { var loggerFactory = LoggerFactory.Create(builder => builder.AddFilter(logLevel => true).AddDebug()); Ioc.Default.ConfigureServices( new ServiceCollection() .AddSingleton(new DialogService( new DialogManager( viewLocator: new ViewLocator(), logger: loggerFactory.CreateLogger()), viewModelFactory: x => Ioc.Default.GetService(x))) .AddTransient() .AddTransient() .BuildServiceProvider()); } } ================================================ FILE: samples/Wpf/Demo.ActivateNonModalDialog/ApplicationResources.xaml ================================================  ================================================ FILE: samples/Wpf/Demo.ActivateNonModalDialog/CurrentTimeDialog.xaml ================================================  ================================================ FILE: samples/Wpf/Demo.ActivateNonModalDialog/CurrentTimeDialog.xaml.cs ================================================ namespace Demo.Wpf.ActivateNonModalDialog; public partial class CurrentTimeDialog { public CurrentTimeDialog() { InitializeComponent(); } } ================================================ FILE: samples/Wpf/Demo.ActivateNonModalDialog/CurrentTimeDialogViewModel.cs ================================================ using System; using System.Windows.Input; using System.Windows.Threading; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; namespace Demo.Wpf.ActivateNonModalDialog; public class CurrentTimeDialogViewModel : ObservableObject { // ReSharper disable once NotAccessedField.Local private DispatcherTimer? _timer; public CurrentTimeDialogViewModel() { StartClockCommand = new RelayCommand(StartClock); } public ICommand StartClockCommand { get; } public DateTime CurrentTime => DateTime.Now; private void StartClock() { _timer = new DispatcherTimer( TimeSpan.FromSeconds(1), DispatcherPriority.Normal, OnTick, Dispatcher.CurrentDispatcher); } private void OnTick(object? sender, EventArgs e) { OnPropertyChanged(nameof(CurrentTime)); } } ================================================ FILE: samples/Wpf/Demo.ActivateNonModalDialog/Demo.ActivateNonModalDialog.csproj ================================================  WinExe net10.0-windows latest true Demo.Wpf.ActivateNonModalDialog Demo.Wpf.ActivateNonModalDialog enable ================================================ FILE: samples/Wpf/Demo.ActivateNonModalDialog/MainWindow.xaml ================================================  ================================================ FILE: samples/Wpf/Demo.ActivateNonModalDialog/MainWindow.xaml.cs ================================================ namespace Demo.Wpf.ActivateNonModalDialog; public partial class MainWindow { public MainWindow() { InitializeComponent(); } } ================================================ FILE: samples/Wpf/Demo.ActivateNonModalDialog/MainWindowViewModel.cs ================================================ using System.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using HanumanInstitute.MvvmDialogs; namespace Demo.Wpf.ActivateNonModalDialog; public class MainWindowViewModel : ObservableObject { private readonly IDialogService _dialogService; private INotifyPropertyChanged? _dialogViewModel; public MainWindowViewModel(IDialogService dialogService) { this._dialogService = dialogService; ShowCommand = new RelayCommand(Show, CanShow); ActivateCommand = new RelayCommand(Activate, CanActivate); } public RelayCommand ShowCommand { get; } public RelayCommand ActivateCommand { get; } private void Show() { _dialogViewModel = _dialogService.CreateViewModel(); _dialogService.Show(this, _dialogViewModel); ShowCommand.NotifyCanExecuteChanged(); ActivateCommand.NotifyCanExecuteChanged(); } private bool CanShow() { return _dialogViewModel == null; } private void Activate() { _dialogService.Activate(_dialogViewModel!); } private bool CanActivate() { return _dialogViewModel != null; } } ================================================ FILE: samples/Wpf/Demo.ActivateNonModalDialog/ViewLocator.cs ================================================ using HanumanInstitute.MvvmDialogs.Wpf; namespace Demo.Wpf.ActivateNonModalDialog; /// /// Maps view models to views in Avalonia. /// public class ViewLocator : ViewLocatorBase { /// protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", ""); } ================================================ FILE: samples/Wpf/Demo.ActivateNonModalDialog/ViewModelLocator.cs ================================================ using CommunityToolkit.Mvvm.DependencyInjection; namespace Demo.Wpf.ActivateNonModalDialog; /// /// This class contains static references to all the view models in the /// application and provides an entry point for the bindings. /// public class ViewModelLocator { public MainWindowViewModel MainWindow => Ioc.Default.GetRequiredService(); } ================================================ FILE: samples/Wpf/Demo.CloseNonModalDialog/App.xaml ================================================  ================================================ FILE: samples/Wpf/Demo.CloseNonModalDialog/App.xaml.cs ================================================ using System.Windows; using CommunityToolkit.Mvvm.DependencyInjection; using Microsoft.Extensions.DependencyInjection; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.Wpf; using Microsoft.Extensions.Logging; namespace Demo.Wpf.CloseNonModalDialog; public partial class App { protected override void OnStartup(StartupEventArgs e) { var loggerFactory = LoggerFactory.Create(builder => builder.AddFilter(logLevel => true).AddDebug()); Ioc.Default.ConfigureServices( new ServiceCollection() .AddSingleton(new DialogService( new DialogManager( viewLocator: new ViewLocator(), logger: loggerFactory.CreateLogger()), viewModelFactory: x => Ioc.Default.GetService(x))) .AddTransient() .AddTransient() .BuildServiceProvider()); } } ================================================ FILE: samples/Wpf/Demo.CloseNonModalDialog/ApplicationResources.xaml ================================================  ================================================ FILE: samples/Wpf/Demo.CloseNonModalDialog/CurrentTimeDialog.xaml ================================================  ================================================ FILE: samples/Wpf/Demo.CloseNonModalDialog/CurrentTimeDialog.xaml.cs ================================================ namespace Demo.Wpf.CloseNonModalDialog; public partial class CurrentTimeDialog { public CurrentTimeDialog() { InitializeComponent(); } } ================================================ FILE: samples/Wpf/Demo.CloseNonModalDialog/CurrentTimeDialogViewModel.cs ================================================ using System; using System.Windows.Input; using System.Windows.Threading; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; namespace Demo.Wpf.CloseNonModalDialog; public class CurrentTimeDialogViewModel : ObservableObject { // ReSharper disable once NotAccessedField.Local private DispatcherTimer? _timer; public CurrentTimeDialogViewModel() { StartClockCommand = new RelayCommand(StartClock); } public ICommand StartClockCommand { get; } public DateTime CurrentTime => DateTime.Now; private void StartClock() { _timer = new DispatcherTimer( TimeSpan.FromSeconds(1), DispatcherPriority.Normal, OnTick, Dispatcher.CurrentDispatcher); } private void OnTick(object? sender, EventArgs e) { OnPropertyChanged(nameof(CurrentTime)); } } ================================================ FILE: samples/Wpf/Demo.CloseNonModalDialog/Demo.CloseNonModalDialog.csproj ================================================  WinExe net10.0-windows latest true Demo.Wpf.CloseNonModalDialog Demo.Wpf.CloseNonModalDialog enable ================================================ FILE: samples/Wpf/Demo.CloseNonModalDialog/MainWindow.xaml ================================================  ================================================ FILE: samples/Wpf/Demo.CloseNonModalDialog/MainWindow.xaml.cs ================================================ namespace Demo.Wpf.CloseNonModalDialog; public partial class MainWindow { public MainWindow() { InitializeComponent(); } } ================================================ FILE: samples/Wpf/Demo.CloseNonModalDialog/MainWindowViewModel.cs ================================================ using System.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using HanumanInstitute.MvvmDialogs; namespace Demo.Wpf.CloseNonModalDialog; public class MainWindowViewModel : ObservableObject { private readonly IDialogService _dialogService; private INotifyPropertyChanged? _dialogViewModel; public MainWindowViewModel(IDialogService dialogService) { this._dialogService = dialogService; ShowCommand = new RelayCommand(Show, CanShow); CloseCommand = new RelayCommand(Close, CanClose); } public RelayCommand ShowCommand { get; } public RelayCommand CloseCommand { get; } private void Show() { _dialogViewModel = _dialogService.CreateViewModel(); _dialogService.Show(this, _dialogViewModel); ShowCommand.NotifyCanExecuteChanged(); CloseCommand.NotifyCanExecuteChanged(); } private bool CanShow() { return _dialogViewModel == null; } private void Close() { _dialogService.Close(_dialogViewModel!); _dialogViewModel = null; ShowCommand.NotifyCanExecuteChanged(); CloseCommand.NotifyCanExecuteChanged(); } private bool CanClose() { return _dialogViewModel != null; } } ================================================ FILE: samples/Wpf/Demo.CloseNonModalDialog/ViewLocator.cs ================================================ using HanumanInstitute.MvvmDialogs.Wpf; namespace Demo.Wpf.CloseNonModalDialog; /// /// Maps view models to views in Avalonia. /// public class ViewLocator : ViewLocatorBase { /// protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", ""); } ================================================ FILE: samples/Wpf/Demo.CloseNonModalDialog/ViewModelLocator.cs ================================================ using CommunityToolkit.Mvvm.DependencyInjection; namespace Demo.Wpf.CloseNonModalDialog; /// /// This class contains static references to all the view models in the /// application and provides an entry point for the bindings. /// public class ViewModelLocator { public MainWindowViewModel MainWindow => Ioc.Default.GetRequiredService(); } ================================================ FILE: samples/Wpf/Demo.CustomOpenFolderDialog/App.xaml ================================================ ================================================ FILE: samples/Wpf/Demo.CustomOpenFolderDialog/App.xaml.cs ================================================ using System.Windows; using CommunityToolkit.Mvvm.DependencyInjection; using Microsoft.Extensions.DependencyInjection; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.Wpf; using Microsoft.Extensions.Logging; namespace Demo.Wpf.CustomOpenFolderDialog; public partial class App { protected override void OnStartup(StartupEventArgs e) { var loggerFactory = LoggerFactory.Create(builder => builder.AddFilter(logLevel => true).AddDebug()); Ioc.Default.ConfigureServices( new ServiceCollection() .AddSingleton(_ => new DialogService( new DialogManager( viewLocator: new ViewLocator(), dialogFactory: new DialogFactory().AddCustomOpenFolder(), logger: loggerFactory.CreateLogger()), viewModelFactory: x => Ioc.Default.GetService(x))) .AddTransient() .BuildServiceProvider()); } } ================================================ FILE: samples/Wpf/Demo.CustomOpenFolderDialog/ApplicationResources.xaml ================================================  ================================================ FILE: samples/Wpf/Demo.MessageBox/Demo.MessageBox.csproj ================================================  WinExe net10.0-windows latest true Demo.Wpf.MessageBox Demo.Wpf.MessageBox enable ================================================ FILE: samples/Wpf/Demo.MessageBox/MainWindow.xaml ================================================  ================================================ FILE: samples/Wpf/Demo.MessageBox/MainWindow.xaml.cs ================================================ namespace Demo.Wpf.MessageBox; public partial class MainWindow { public MainWindow() { InitializeComponent(); } } ================================================ FILE: samples/Wpf/Demo.MessageBox/MainWindowViewModel.cs ================================================ using System; using System.Threading.Tasks; using System.Windows.Input; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.FrameworkDialogs; namespace Demo.Wpf.MessageBox; public class MainWindowViewModel : ObservableObject { private readonly IDialogService _dialogService; private string? _confirmation; public MainWindowViewModel(IDialogService dialogService) { this._dialogService = dialogService; ShowWithMessage = new AsyncRelayCommand(() => Show(ShowWithMessageImpl, ShowWithMessageImplAsync)); ShowWithCaption = new AsyncRelayCommand(() => Show(ShowWithCaptionImpl, ShowWithCaptionImplAsync)); ShowWithButton = new AsyncRelayCommand(() => Show(ShowWithButtonImpl, ShowWithButtonImplAsync)); ShowWithIcon = new AsyncRelayCommand(() => Show(ShowWithIconImpl, ShowWithIconImplAsync)); ShowWithDefaultResult = new AsyncRelayCommand(() => Show(ShowWithDefaultResultImpl, ShowWithDefaultResultImplAsync)); } public ICommand ShowWithMessage { get; } public ICommand ShowWithCaption { get; } public ICommand ShowWithButton { get; } public ICommand ShowWithIcon { get; } public ICommand ShowWithDefaultResult { get; } private Task Show(Action action, Func asyncAction) { if (UseAsync) { return asyncAction(); } action(); return Task.CompletedTask; } public bool UseAsync { get => _useAsync; set => SetProperty(ref _useAsync, value); } private bool _useAsync = true; public bool SetOwner { get => _setOwner; set => SetProperty(ref _setOwner, value); } private bool _setOwner = true; public string? Confirmation { get => _confirmation; private set => SetProperty(ref _confirmation, value); } private void ShowWithMessageImpl() { var result = _dialogService.ShowMessageBox( SetOwner ? this : null, "This is the text."); UpdateResult(result); } private async Task ShowWithMessageImplAsync() { var result = await _dialogService.ShowMessageBoxAsync( SetOwner ? this : null, "This is the text."); UpdateResult(result); } private void ShowWithCaptionImpl() { var result = _dialogService.ShowMessageBox( SetOwner ? this : null, "This is the text.", "This Is The Caption"); UpdateResult(result); } private async Task ShowWithCaptionImplAsync() { var result = await _dialogService.ShowMessageBoxAsync( SetOwner ? this : null, "This is the text.", "This Is The Caption"); UpdateResult(result); } private void ShowWithButtonImpl() { var result = _dialogService.ShowMessageBox( SetOwner ? this : null, "This is the text.", "This Is The Caption", MessageBoxButton.OkCancel); UpdateResult(result); } private async Task ShowWithButtonImplAsync() { var result = await _dialogService.ShowMessageBoxAsync( SetOwner ? this : null, "This is the text.", "This Is The Caption", MessageBoxButton.OkCancel); UpdateResult(result); } private void ShowWithIconImpl() { var result = _dialogService.ShowMessageBox( SetOwner ? this : null, "This is the text.", "This Is The Caption", MessageBoxButton.OkCancel, MessageBoxImage.Information); UpdateResult(result); } private async Task ShowWithIconImplAsync() { var result = await _dialogService.ShowMessageBoxAsync( SetOwner ? this : null, "This is the text.", "This Is The Caption", MessageBoxButton.OkCancel, MessageBoxImage.Information); UpdateResult(result); } private void ShowWithDefaultResultImpl() { var result = _dialogService.ShowMessageBox( SetOwner ? this : null, "This is the text.", "This Is The Caption", MessageBoxButton.OkCancel, MessageBoxImage.Information, false); UpdateResult(result); } private async Task ShowWithDefaultResultImplAsync() { var result = await _dialogService.ShowMessageBoxAsync( SetOwner ? this : null, "This is the text.", "This Is The Caption", MessageBoxButton.OkCancel, MessageBoxImage.Information, false); UpdateResult(result); } private void UpdateResult(bool? result) { Confirmation = result == true ? "We got confirmation to continue!" : string.Empty; } } ================================================ FILE: samples/Wpf/Demo.MessageBox/ViewLocator.cs ================================================ using HanumanInstitute.MvvmDialogs.Wpf; namespace Demo.Wpf.MessageBox; /// /// Maps view models to views in Avalonia. /// public class ViewLocator : ViewLocatorBase { /// protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", ""); } ================================================ FILE: samples/Wpf/Demo.MessageBox/ViewModelLocator.cs ================================================ using CommunityToolkit.Mvvm.DependencyInjection; namespace Demo.Wpf.MessageBox; /// /// This class contains static references to all the view models in the /// application and provides an entry point for the bindings. /// public class ViewModelLocator { public MainWindowViewModel MainWindow => Ioc.Default.GetRequiredService(); } ================================================ FILE: samples/Wpf/Demo.ModalCustomDialog/AddTextCustomDialog.cs ================================================ using System; using System.ComponentModel; using System.Threading.Tasks; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.Wpf; namespace Demo.Wpf.ModalCustomDialog; public class AddTextCustomDialog : IView, IViewSync { private readonly AddTextDialog _dialog = new(); public object RefObj => this; public void Initialize(INotifyPropertyChanged viewModel, ViewDefinition viewDef) { ViewModel = viewModel; } public void InitializeExisting(INotifyPropertyChanged viewModel, object view) { ViewModel = viewModel; } public event EventHandler Closed { add => _dialog.Closed += value; remove => _dialog.Closed -= value; } public event EventHandler Loaded { add { } remove { } } public event EventHandler Closing { add { } remove { } } public INotifyPropertyChanged ViewModel { get => (INotifyPropertyChanged)_dialog.DataContext; set => _dialog.DataContext = value; } public IView? Owner { get => _dialog.Owner.AsWrapper(); set => _dialog.Owner = value.AsWrapper()?.Ref; } public Task ShowDialogAsync(IView owner) => UiExtensions.RunUiAsync(() => ShowDialog(owner)); public void ShowDialog(IView owner) { _dialog.Owner = owner.GetRef(); _dialog.ShowDialog(); } public void Show(IView? owner) { _dialog.Owner = owner.GetRef(); _dialog.Show(); } public void Activate() => _dialog.Activate(); public void Close() => _dialog.Close(); public bool IsEnabled { get => _dialog.IsEnabled; set => _dialog.IsEnabled = value; } public bool IsVisible => _dialog.IsVisible; public bool ClosingConfirmed { get; set; } } ================================================ FILE: samples/Wpf/Demo.ModalCustomDialog/AddTextCustomDialogViewModel.cs ================================================ using System; using System.Windows.Input; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using HanumanInstitute.MvvmDialogs; namespace Demo.Wpf.ModalCustomDialog; public class AddTextCustomDialogViewModel : ObservableObject, IModalDialogViewModel, ICloseable { public event EventHandler? RequestClose; private string? _text; private bool? _dialogResult; public AddTextCustomDialogViewModel() { OkCommand = new RelayCommand(Ok); } public string? Text { get => _text; set => SetProperty(ref _text, value); } public ICommand OkCommand { get; } public bool? DialogResult { get => _dialogResult; private set => SetProperty(ref _dialogResult, value); } private void Ok() { if (!string.IsNullOrEmpty(Text)) { RequestClose?.Invoke(this, EventArgs.Empty); DialogResult = true; } } } ================================================ FILE: samples/Wpf/Demo.ModalCustomDialog/AddTextDialog.xaml ================================================  ================================================ FILE: samples/Wpf/Demo.NonModalCustomDialog/MainWindow.xaml.cs ================================================ namespace Demo.Wpf.NonModalCustomDialog; public partial class MainWindow { public MainWindow() { InitializeComponent(); } } ================================================ FILE: samples/Wpf/Demo.NonModalCustomDialog/MainWindowViewModel.cs ================================================ using System; using System.Windows.Input; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using HanumanInstitute.MvvmDialogs; namespace Demo.Wpf.NonModalCustomDialog; public class MainWindowViewModel : ObservableObject { private readonly IDialogService _dialogService; public MainWindowViewModel(IDialogService dialogService) { this._dialogService = dialogService; ImplicitShowCommand = new RelayCommand(ImplicitShow); ExplicitShowCommand = new RelayCommand(ExplicitShow); } public ICommand ImplicitShowCommand { get; } public ICommand ExplicitShowCommand { get; } private void ImplicitShow() { Show(viewModel => _dialogService.Show(this, viewModel)); } private void ExplicitShow() { Show(viewModel => _dialogService.Show(this, viewModel)); } private void Show(Action show) { var dialogViewModel = _dialogService.CreateViewModel(); show(dialogViewModel); } } ================================================ FILE: samples/Wpf/Demo.NonModalCustomDialog/ViewLocator.cs ================================================ using HanumanInstitute.MvvmDialogs.Wpf; namespace Demo.Wpf.NonModalCustomDialog; /// /// Maps view models to views in Avalonia. /// public class ViewLocator : ViewLocatorBase { /// protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", ""); } ================================================ FILE: samples/Wpf/Demo.NonModalCustomDialog/ViewModelLocator.cs ================================================ using CommunityToolkit.Mvvm.DependencyInjection; namespace Demo.Wpf.NonModalCustomDialog; /// /// This class contains static references to all the view models in the /// application and provides an entry point for the bindings. /// public class ViewModelLocator { public MainWindowViewModel MainWindow => Ioc.Default.GetRequiredService(); } ================================================ FILE: samples/Wpf/Demo.NonModalDialog/App.xaml ================================================  ================================================ FILE: samples/Wpf/Demo.NonModalDialog/App.xaml.cs ================================================ using System.Windows; using CommunityToolkit.Mvvm.DependencyInjection; using Microsoft.Extensions.DependencyInjection; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.Wpf; using Microsoft.Extensions.Logging; namespace Demo.Wpf.NonModalDialog; public partial class App { protected override void OnStartup(StartupEventArgs e) { var loggerFactory = LoggerFactory.Create(builder => builder.AddFilter(logLevel => true).AddDebug()); Ioc.Default.ConfigureServices( new ServiceCollection() .AddSingleton(new DialogService( new DialogManager( viewLocator: new ViewLocator(), logger: loggerFactory.CreateLogger()), viewModelFactory: x => Ioc.Default.GetService(x))) .AddTransient() .AddTransient() .BuildServiceProvider()); } } ================================================ FILE: samples/Wpf/Demo.NonModalDialog/ApplicationResources.xaml ================================================  ================================================ FILE: samples/Wpf/Demo.NonModalDialog/CurrentTimeDialog.xaml ================================================  ================================================ FILE: samples/Wpf/Demo.NonModalDialog/CurrentTimeDialog.xaml.cs ================================================ namespace Demo.Wpf.NonModalDialog; public partial class CurrentTimeDialog { public CurrentTimeDialog() { InitializeComponent(); } } ================================================ FILE: samples/Wpf/Demo.NonModalDialog/CurrentTimeDialogViewModel.cs ================================================ using System; using System.Windows.Input; using System.Windows.Threading; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; namespace Demo.Wpf.NonModalDialog; public class CurrentTimeDialogViewModel : ObservableObject { // ReSharper disable once NotAccessedField.Local private DispatcherTimer? _timer; public CurrentTimeDialogViewModel() { StartClockCommand = new RelayCommand(StartClock); } public ICommand StartClockCommand { get; } public DateTime CurrentTime => DateTime.Now; private void StartClock() { _timer = new DispatcherTimer( TimeSpan.FromSeconds(1), DispatcherPriority.Normal, OnTick, Dispatcher.CurrentDispatcher); } private void OnTick(object? sender, EventArgs e) { OnPropertyChanged(nameof(CurrentTime)); } } ================================================ FILE: samples/Wpf/Demo.NonModalDialog/Demo.NonModalDialog.csproj ================================================  WinExe net10.0-windows latest true Demo.Wpf.NonModalDialog Demo.Wpf.NonModalDialog enable ================================================ FILE: samples/Wpf/Demo.NonModalDialog/MainWindow.xaml ================================================  ================================================ FILE: samples/Wpf/Demo.NonModalDialog/MainWindow.xaml.cs ================================================ namespace Demo.Wpf.NonModalDialog; public partial class MainWindow { public MainWindow() { InitializeComponent(); } } ================================================ FILE: samples/Wpf/Demo.NonModalDialog/MainWindowViewModel.cs ================================================ using System; using System.Windows.Input; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using HanumanInstitute.MvvmDialogs; namespace Demo.Wpf.NonModalDialog; public class MainWindowViewModel : ObservableObject { private readonly IDialogService _dialogService; public MainWindowViewModel(IDialogService dialogService) { this._dialogService = dialogService; ImplicitShowCommand = new RelayCommand(ImplicitShow); ExplicitShowCommand = new RelayCommand(ExplicitShow); } public ICommand ImplicitShowCommand { get; } public ICommand ExplicitShowCommand { get; } private void ImplicitShow() { Show(viewModel => _dialogService.Show(this, viewModel)); } private void ExplicitShow() { Show(viewModel => _dialogService.Show(this, viewModel)); } private void Show(Action show) { var dialogViewModel = _dialogService.CreateViewModel(); show(dialogViewModel); } } ================================================ FILE: samples/Wpf/Demo.NonModalDialog/ViewLocator.cs ================================================ using HanumanInstitute.MvvmDialogs.Wpf; namespace Demo.Wpf.NonModalDialog; /// /// Maps view models to views in Avalonia. /// public class ViewLocator : ViewLocatorBase { /// protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", ""); } ================================================ FILE: samples/Wpf/Demo.NonModalDialog/ViewModelLocator.cs ================================================ using CommunityToolkit.Mvvm.DependencyInjection; namespace Demo.Wpf.NonModalDialog; /// /// This class contains static references to all the view models in the /// application and provides an entry point for the bindings. /// public class ViewModelLocator { public MainWindowViewModel MainWindow => Ioc.Default.GetRequiredService(); } ================================================ FILE: samples/Wpf/Demo.OpenFileDialog/App.xaml ================================================  ================================================ FILE: samples/Wpf/Demo.OpenFileDialog/App.xaml.cs ================================================ using System.Windows; using CommunityToolkit.Mvvm.DependencyInjection; using Microsoft.Extensions.DependencyInjection; using HanumanInstitute.MvvmDialogs; using HanumanInstitute.MvvmDialogs.Wpf; using Microsoft.Extensions.Logging; namespace Demo.Wpf.OpenFileDialog; public partial class App { protected override void OnStartup(StartupEventArgs e) { var loggerFactory = LoggerFactory.Create(builder => builder.AddFilter(logLevel => true).AddDebug()); Ioc.Default.ConfigureServices( new ServiceCollection() .AddSingleton(new DialogService( new DialogManager( viewLocator: new ViewLocator(), logger: loggerFactory.CreateLogger()), viewModelFactory: x => Ioc.Default.GetService(x))) .AddTransient() .BuildServiceProvider()); } } ================================================ FILE: samples/Wpf/Demo.OpenFileDialog/ApplicationResources.xaml ================================================  ================================================ FILE: samples/Wpf/Demo.ViewEvents/Demo.ViewEvents.csproj ================================================  WinExe net10.0-windows latest true Demo.Wpf.ViewEvents Demo.Wpf.ViewEvents enable ================================================ FILE: samples/Wpf/Demo.ViewEvents/MainWindow.xaml ================================================  ================================================ FILE: samples/Wpf/Demo.ViewEvents/MainWindow.xaml.cs ================================================ namespace Demo.Wpf.ViewEvents; public partial class MainWindow { public MainWindow() { InitializeComponent(); } } ================================================ FILE: samples/Wpf/Demo.ViewEvents/MainWindowViewModel.cs ================================================ using System.ComponentModel; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using HanumanInstitute.MvvmDialogs; namespace Demo.Wpf.ViewEvents; public class MainWindowViewModel : ObservableObject, IViewLoaded, IViewClosing, IViewClosed { private readonly IDialogService _dialogService; public MainWindowViewModel(IDialogService dialogService) { this._dialogService = dialogService; } public string Text { get => _text; set => this.SetProperty(ref _text, value); } private string _text = string.Empty; public void OnClosed() { _dialogService.ShowMessageBox(null, "It's over.", "Closed"); } public void OnClosing(CancelEventArgs e) { e.Cancel = true; } public async Task OnClosingAsync(CancelEventArgs e) { var quit = await _dialogService.ShowMessageBoxAsync(this, "Do you really want to quit? ", "Confirmation", HanumanInstitute.MvvmDialogs.FrameworkDialogs.MessageBoxButton.YesNo); e.Cancel = quit != true; } public void OnLoaded() { Text = "Loaded!"; } } ================================================ FILE: samples/Wpf/Demo.ViewEvents/ViewLocator.cs ================================================ using HanumanInstitute.MvvmDialogs.Wpf; namespace Demo.Wpf.ViewEvents; /// /// Maps view models to views in Avalonia. /// public class ViewLocator : ViewLocatorBase { /// protected override string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", ""); } ================================================ FILE: samples/Wpf/Demo.ViewEvents/ViewModelLocator.cs ================================================ using CommunityToolkit.Mvvm.DependencyInjection; namespace Demo.Wpf.ViewEvents; /// /// This class contains static references to all the view models in the /// application and provides an entry point for the bindings. /// public class ViewModelLocator { public MainWindowViewModel MainWindow => Ioc.Default.GetRequiredService(); } ================================================ FILE: samples/Wpf/TestBaseClasses/Features/FeatureSteps.cs ================================================ using System; using System.Diagnostics; using System.Drawing.Imaging; using System.IO; using NUnit.Framework; using NUnit.Framework.Interfaces; using TechTalk.SpecFlow; using TestStack.White; using TestStack.White.ScreenObjects; namespace TestBaseClasses.Features { /// /// Base class for all tests that are driven by SpecFlow. /// public abstract class FeatureSteps where T : AppScreen { protected Application? Application { get; private set; } protected ScreenRepository? ScreenRepository { get; private set; } protected T? MainScreen { get; private set; } [BeforeScenario] public void InitialBeforeScenario() { Application = LaunchApplication(); ScreenRepository = new ScreenRepository(Application.ApplicationSession); MainScreen = GetMainScreen(ScreenRepository); } [AfterScenario] public void InitialAfterScenario() { if (TestContext.CurrentContext.Result.Outcome.Status == TestStatus.Failed) { TakeScreenshot(); } Application?.Close(); } protected abstract Application LaunchApplication(); protected abstract T GetMainScreen(ScreenRepository screenRepository); private static void TakeScreenshot() { string directoryName = Path.Combine( TestContext.CurrentContext.TestDirectory, "FailedTestScreenshots"); string filePath = Path.Combine( directoryName, $"Failed_{TestContext.CurrentContext.Test.FullName}.png"); try { if (!Directory.Exists(directoryName)) { Directory.CreateDirectory(directoryName); } Desktop.TakeScreenshot(filePath, ImageFormat.Png); } catch (Exception e) { Trace.TraceError($"Unable to take screenshot and save it to '{filePath}'.{Environment.NewLine}{e}"); } } } } ================================================ FILE: samples/Wpf/TestBaseClasses/TestBaseClasses.csproj ================================================  Library net472 enable ================================================ FILE: src/Directory.Build.props ================================================ latest enable 2.3.0 Etienne Charland Hanuman Institute HanumanInstitute.MvvmDialogs Copyright © 2009-2026 MVVM Dialogs contributors en-US https://github.com/mysteryx93/HanumanInstitute.MvvmDialogs MIT Library simplifying the concept of opening dialogs from a view model when using MVVM in WPF wpf avalonia mvvm dialog window messagebox openfiledialog savefiledialog folderbrowserdialog messagedialog contentdialog fileopenpicker filesavepicker folderpicker android ios mobile xamarin ================================================ FILE: src/MvvmDialogs/DialogManagerBase.cs ================================================ using System.Threading; using Microsoft.Extensions.Logging; // ReSharper disable MemberCanBePrivate.Global // ReSharper disable SuspiciousTypeConversion.Global namespace HanumanInstitute.MvvmDialogs; /// /// Interface responsible for UI interactions. /// /// The base data type of the dialog window for target framework. public abstract class DialogManagerBase : IDialogManager { /// /// Locator responsible for finding a dialog type matching a view model. /// protected IViewLocator ViewLocator { get; } /// /// A factory to resolve framework dialog types. /// protected IDialogFactory DialogFactory { get; } /// public ILogger? Logger { get; } /// public bool AllowConcurrentDialogs { get; set; } /// /// Returns whether the code is running in design mode. /// protected abstract bool IsDesignMode { get; } /// /// Initializes a new instance of the DisplayManager class. /// /// Locator responsible for finding a dialog type matching a view model. /// A factory to resolve framework dialog types. /// A ILogger to capture MvvmDialogs logs. protected DialogManagerBase(IViewLocator viewLocator, IDialogFactory dialogFactory, ILogger>? logger) { ViewLocator = viewLocator; DialogFactory = dialogFactory; DialogFactory.DialogManager = this; Logger = logger; } /// /// Gets or sets whether to raise ViewModel view events when dialog events occur. /// Must be set to False for view navigation because it would re-trigger the same event in loop. /// protected bool ForwardViewEvents { get; set; } = true; /// public virtual void Show(INotifyPropertyChanged? ownerViewModel, INotifyPropertyChanged viewModel) { if (IsDesignMode) { return; } Dispatch( () => { var viewDef = ViewLocator.Locate(viewModel); Logger?.LogInformation("View: {View}; ViewModel: {ViewModel}; Owner: {OwnerViewModel}", viewDef.ViewType, viewModel.GetType(), ownerViewModel?.GetType()); var dialog = CreateDialog(viewModel, viewDef); dialog.Show(FindViewByViewModelOrThrow(ownerViewModel)); }); } /// public virtual async Task ShowDialogAsync(INotifyPropertyChanged ownerViewModel, IModalDialogViewModel viewModel) { if (IsDesignMode) { return; } await await DispatchAsync( async () => { var viewDef = ViewLocator.Locate(viewModel); Logger?.LogInformation("View: {View}; ViewModel: {ViewModel}; Owner: {OwnerViewModel}", viewDef.ViewType, viewModel.GetType(), ownerViewModel.GetType()); var dialog = CreateDialog(viewModel, viewDef); await dialog.ShowDialogAsync(FindViewByViewModelOrThrow(ownerViewModel)!); Logger?.LogInformation("View: {View}; Result: {Result}", viewDef.ViewType, viewModel.DialogResult); }); } /// /// Returns the IView with a DataContext equal to specified ViewModel. /// /// The ViewModel to search for. /// A IView, or null. /// Cannot find View for viewModel type. protected IView? FindViewByViewModelOrThrow(INotifyPropertyChanged? viewModel) { if (viewModel == null) { return null; } var owner = FindViewByViewModel(viewModel); if (owner == null) { throw new InvalidOperationException($"Cannot find View for viewModel of type {viewModel.GetType()}"); } return owner; } /// /// Creates a new IWindow from the configured IDialogFactory. /// /// The view model of the new dialog. /// The view definition including its type and how to create one. /// The new IWindow. /// Could not load view for view model. protected IView CreateDialog(INotifyPropertyChanged viewModel, ViewDefinition viewDef) { // ReSharper disable once SuspiciousTypeConversion.Global IView? dialog; if (viewDef.TypeDerivesFrom()) { dialog = (IView)viewDef.Create(); dialog.Initialize(viewModel, viewDef); } else if (viewDef.TypeDerivesFrom()) { dialog = CreateWrapper(viewModel, viewDef); } else { throw new TypeLoadException($"Only dialogs of type {typeof(T)} or {typeof(IView)} are supported."); } HandleDialogEvents(viewModel, dialog); return dialog; } /// /// Creates a wrapper around a View. /// /// The view model of the View. /// The view definition including its type and how to create one. protected abstract IView CreateWrapper(INotifyPropertyChanged viewModel, ViewDefinition viewDef); /// /// Creates a wrapper around a View. /// /// The view to create a wrapper for. protected abstract IView AsWrapper(T view); /// /// Dispatches an action to the UI thread. /// /// The action to execute on the UI thread. protected abstract void Dispatch(Action action); /// /// Dispatches an asynchronous action to the UI thread. /// /// The action to execute on the UI thread. /// The return type of the dispatched function. protected abstract Task DispatchAsync(Func action); /// /// Handles window events. By default, ICloseable and IActivable are handled. /// /// The view model of the new dialog. /// The dialog being shown. public virtual void HandleDialogEvents(INotifyPropertyChanged viewModel, IView dialog) { if (viewModel is ICloseable closable) { closable.RequestClose += (_, _) => Dispatch(dialog.Close); } if (viewModel is IActivable activable) { activable.RequestActivate += (_, _) => Dispatch(dialog.Activate); } if (viewModel is IViewClosing) { dialog.Closing += (_, e) => View_Closing(dialog, e); } if (ForwardViewEvents) { if (viewModel is IViewLoaded loaded) { dialog.Loaded += (_, _) => loaded.OnLoaded(); } if (viewModel is IViewClosed closed) { dialog.Closed += (_, _) => closed.OnClosed(); } } } private bool _isViewClosing; /// /// Called when the view is closing. /// public async void View_Closing(IView dialog, CancelEventArgs e) { if (dialog.ViewModel is not IViewClosing closing || dialog.ClosingConfirmed) { dialog.ClosingConfirmed = true; return; } // Prevent re-closing while prompting. if (_isViewClosing) { e.Cancel = true; return; } _isViewClosing = true; try { // ReSharper disable once MethodHasAsyncOverload closing.OnClosing(e); if (e.Cancel) { // caller returns and window stays open await Task.Yield(); await closing.OnClosingAsync(e).ConfigureAwait(true); if (!e.Cancel) { dialog.ClosingConfirmed = true; dialog.Close(); } } else { dialog.ClosingConfirmed = true; } } finally { _isViewClosing = false; } } private readonly SemaphoreSlim _semaphoreShow = new(1); /// public virtual async Task ShowFrameworkDialogAsync( INotifyPropertyChanged? ownerViewModel, TSettings settings, Func? resultToString = null) where TSettings : DialogSettingsBase { if (IsDesignMode) { return null; } if (!AllowConcurrentDialogs) { await _semaphoreShow.WaitAsync(); } try { Logger?.LogInformation("Dialog: {Dialog}; Title: {Title}", settings.GetType().Name, settings.Title); var result = await await DispatchAsync( async () => { IView? owner; var isDummyOwner = false; if (ownerViewModel != null) { owner = FindViewByViewModel(ownerViewModel) ?? throw new ArgumentException($"No view found with specified ownerViewModel of type {ownerViewModel.GetType()}."); } else { // If no owner is specified, get MainWindow if available, otherwise create a dummy parent window. owner = GetMainWindow(); if (owner == null || !owner.IsVisible) { owner = GetDummyWindow(); isDummyOwner = true; } } var result = await DialogFactory.ShowDialogAsync(owner, settings).ConfigureAwait(true); if (isDummyOwner) { owner!.Close(); } return result; }).ConfigureAwait(true); Logger?.LogInformation("Dialog: {Dialog}; Result: {Result}", settings.GetType().Name, resultToString != null ? resultToString(result) : result?.ToString()); return result; } finally { if (!AllowConcurrentDialogs) { _semaphoreShow.Release(); } } } /// public abstract IView? FindViewByViewModel(INotifyPropertyChanged viewModel); /// public abstract IView? GetMainWindow(); /// public abstract IView? GetDummyWindow(); } ================================================ FILE: src/MvvmDialogs/DialogNotFoundException.cs ================================================ #if NETSTANDARD2_0_OR_GREATER using System.Runtime.Serialization; #endif namespace HanumanInstitute.MvvmDialogs; /// /// Exception thrown by when a certain dialog isn't found. /// #if NETSTANDARD2_0_OR_GREATER [Serializable] #endif public class DialogNotFoundException : Exception { /// /// Initializes a new instance of the class. /// /// The error message that explains the reason for the exception. /// The exception that is the cause of the current exception, or a null reference if no /// inner exception is specified. public DialogNotFoundException(string? message = null, Exception? innerException = null) : base(message, innerException) { } #if NETSTANDARD2_0_OR_GREATER /// /// Initializes a new instance of the class. /// /// The that holds the serialized object data about the /// exception being thrown. /// The that contains contextual information about the /// source or destination. protected DialogNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) { } #endif } ================================================ FILE: src/MvvmDialogs/DialogServiceBase.cs ================================================ using Microsoft.Extensions.Logging; namespace HanumanInstitute.MvvmDialogs; /// /// Class abstracting the interaction between view models and views when it comes to /// opening dialogs using the MVVM pattern in WPF. /// public abstract class DialogServiceBase : IDialogService { /// /// Initializes a new instance of the class. /// /// Class responsible to manage UI interactions. /// Function used to create view model instances. This function is used only by and is not used internally. protected DialogServiceBase(IDialogManager dialogManager, Func? viewModelFactory) { DialogManager = dialogManager; ViewModelFactory = viewModelFactory; } /// /// Factory responsible for creating dialogs. /// public IDialogManager DialogManager { get; } /// /// Function used to create view model instances. This function is used only by and is not used internally. /// protected Func? ViewModelFactory { get; } /// public void Show(INotifyPropertyChanged? ownerViewModel, INotifyPropertyChanged viewModel) => ShowInternal(ownerViewModel, viewModel); /// public void Show(INotifyPropertyChanged? ownerViewModel, INotifyPropertyChanged viewModel) => ShowInternal(ownerViewModel, viewModel); /// public Task ShowDialogAsync(INotifyPropertyChanged ownerViewModel, IModalDialogViewModel viewModel) => ShowDialogInternalAsync(ownerViewModel, viewModel); /// public Task ShowDialogAsync(INotifyPropertyChanged ownerViewModel, IModalDialogViewModel viewModel) => ShowDialogInternalAsync(ownerViewModel, viewModel); /// /// Attempts to bring the window to the foreground and activates it. /// This method is not thread-safe and must be run on the UI thread. /// /// The view model of the window. /// true if the Window was successfully activated; otherwise, false. public bool Activate(INotifyPropertyChanged viewModel) { if (viewModel == null) throw new ArgumentNullException(nameof(viewModel)); var window = DialogManager.FindViewByViewModel(viewModel); DialogManager.Logger?.LogInformation("Activate View: {View}; ViewModel: {ViewModel}", window?.RefObj?.GetType(), viewModel.GetType()); window?.Activate(); return window != null; } /// /// Closes a non-modal dialog that previously was opened using . /// This method is not thread-safe and must be run on the UI thread. /// /// The view model of the dialog to close. /// true if the Window was successfully closed; otherwise, false. public bool Close(INotifyPropertyChanged viewModel) { if (viewModel == null) throw new ArgumentNullException(nameof(viewModel)); var window = DialogManager.FindViewByViewModel(viewModel); DialogManager.Logger?.LogInformation("Close View: {View}; ViewModel: {ViewModel}", window?.RefObj.GetType(), viewModel.GetType()); if (window != null) { try { window.Close(); return true; } catch (Exception e) { DialogManager.Logger?.LogWarning(e, "Failed to close dialog"); } } return false; } /// /// Displays a non-modal dialog of specified type. /// /// A view model that represents the owner window of the dialog. /// The view model of the new dialog. /// No view is registered with specified owner view model as data context. protected void ShowInternal(INotifyPropertyChanged? ownerViewModel, INotifyPropertyChanged viewModel) { if (viewModel == null) throw new ArgumentNullException(nameof(viewModel)); DialogManager.Show(ownerViewModel, viewModel); } /// /// Displays a modal dialog of specified type. /// /// A view model that represents the owner window of the dialog. /// The view model of the new dialog. /// A nullable value of type that signifies how a window was closed by the user. /// No view is registered with specified owner view model as data context. protected async Task ShowDialogInternalAsync(INotifyPropertyChanged ownerViewModel, IModalDialogViewModel viewModel) { if (ownerViewModel == null) throw new ArgumentNullException(nameof(ownerViewModel)); if (viewModel == null) throw new ArgumentNullException(nameof(viewModel)); await DialogManager.ShowDialogAsync(ownerViewModel, viewModel); return viewModel.DialogResult; } /// public object CreateViewModel(Type type) => ViewModelFactory?.Invoke(type) ?? throw new NullReferenceException( $"ViewModelFactory was not set in the DialogService constructor or the function returned null for type '{type}'."); /// public T CreateViewModel() => (T?)ViewModelFactory?.Invoke(typeof(T)) ?? throw new NullReferenceException( $"ViewModelFactory was not set in the DialogService constructor or the function returned null for type '{typeof(T)}'."); } ================================================ FILE: src/MvvmDialogs/DialogServiceExtensions.cs ================================================ using System.Collections.Generic; using System.Linq; using HanumanInstitute.MvvmDialogs.FileSystem; using HanumanInstitute.MvvmDialogs.FrameworkDialogs; // ReSharper disable once CheckNamespace namespace HanumanInstitute.MvvmDialogs; /// /// Provides IDialogService extensions for standard dialog methods. /// public static class DialogServiceExtensions { /// /// Displays a message box that has a message, title bar caption, button, and icon; and /// that accepts a default message box result and returns a result. /// /// The IDialogService on which to attach the extension method. /// A view model that represents the owner window of the dialog. /// A that specifies the text to display. /// A that specifies the title bar caption to display. Default value is an empty string. /// A value that specifies which button or buttons to display. /// Default value is . /// A value that specifies the icon to display. /// Default value is . /// Specifies the value of the button selected by default. Default value is true. /// A value that specifies which message box button is clicked by the user. True=OK/Yes, False=No, Null=Cancel /// No view is registered with specified owner view model as data context. public static Task ShowMessageBoxAsync( this IDialogService service, INotifyPropertyChanged? ownerViewModel, string text, string title = "", MessageBoxButton button = MessageBoxButton.Ok, MessageBoxImage icon = MessageBoxImage.None, bool? defaultResult = true) { var settings = new MessageBoxSettings { Content = text, Title = title, Button = button, Icon = icon, DefaultValue = defaultResult }; return ShowMessageBoxAsync(service, ownerViewModel, settings); } /// /// Displays a message box that has a message, title bar caption, button, and icon; and /// that accepts a default message box result and returns a result. /// /// The IDialogService on which to attach the extension method. /// A view model that represents the owner window of the dialog. /// The settings for the message box dialog. /// A value that specifies which message box button is clicked by the user. True=OK/Yes, False=No, Null=Cancel /// No view is registered with specified owner view model as data context. public static async Task ShowMessageBoxAsync(this IDialogService service, INotifyPropertyChanged? ownerViewModel, MessageBoxSettings? settings = null) { return (bool?)await service.DialogManager.ShowFrameworkDialogAsync( ownerViewModel, settings ?? new MessageBoxSettings()).ConfigureAwait(true); } /// /// Displays the OpenFileDialog to select a single file. /// /// The IDialogService on which to attach the extension method. /// A view model that represents the owner window of the dialog. /// The settings for the open file dialog. /// The file selected by the user, or null if the user cancelled. /// No view is registered with specified owner view model as data context. public static async Task ShowOpenFileDialogAsync(this IDialogService service, INotifyPropertyChanged? ownerViewModel, OpenFileDialogSettings? settings = null) { settings ??= new OpenFileDialogSettings(); settings.AllowMultiple ??= false; var result = await ShowOpenFilesDialogAsync(service, ownerViewModel, settings).ConfigureAwait(true); return result.Count > 0 ? result[0] : null; } /// /// Displays the OpenFileDialog to select multiple files. /// /// The IDialogService on which to attach the extension method. /// A view model that represents the owner window of the dialog. /// The settings for the open file dialog. /// The list of files selected by the user, or null if the user cancelled. /// No view is registered with specified owner view model as data context. public static async Task> ShowOpenFilesDialogAsync(this IDialogService service, INotifyPropertyChanged? ownerViewModel, OpenFileDialogSettings? settings = null) { settings ??= new OpenFileDialogSettings(); settings.AllowMultiple ??= true; return (IReadOnlyList)(await service.DialogManager.ShowFrameworkDialogAsync( ownerViewModel, settings, x => string.Join(", ", x)).ConfigureAwait(true))!; } /// /// Displays the SaveFileDialog. /// /// The IDialogService on which to attach the extension method. /// A view model that represents the owner window of the dialog. /// The settings for the save file dialog. /// The path to the file selected by the user, or null if the user cancelled. /// No view is registered with specified owner view model as data context. public static async Task ShowSaveFileDialogAsync(this IDialogService service, INotifyPropertyChanged? ownerViewModel, SaveFileDialogSettings? settings = null) { return (IDialogStorageFile?)await service.DialogManager.ShowFrameworkDialogAsync( ownerViewModel, settings ?? new SaveFileDialogSettings()).ConfigureAwait(true); } /// /// Displays the FolderBrowserDialog to select multiple folders. /// /// The IDialogService on which to attach the extension method. /// A view model that represents the owner window of the dialog. /// The settings for the folder browser dialog. /// The path of the folder selected by the user, or null if the user cancelled. /// No view is registered with specified owner view model as data context. public static async Task> ShowOpenFoldersDialogAsync(this IDialogService service, INotifyPropertyChanged? ownerViewModel, OpenFolderDialogSettings? settings = null) { return (IReadOnlyList)(await service.DialogManager.ShowFrameworkDialogAsync( ownerViewModel, settings ?? new OpenFolderDialogSettings()).ConfigureAwait(true))!; } /// /// Displays the FolderBrowserDialog to select a single folder. /// /// The IDialogService on which to attach the extension method. /// A view model that represents the owner window of the dialog. /// The settings for the folder browser dialog. /// The path of the folder selected by the user, or null if the user cancelled. /// No view is registered with specified owner view model as data context. public static async Task ShowOpenFolderDialogAsync(this IDialogService service, INotifyPropertyChanged? ownerViewModel, OpenFolderDialogSettings? settings = null) { settings ??= new OpenFolderDialogSettings(); settings.AllowMultiple ??= false; var result = await ShowOpenFoldersDialogAsync(service, ownerViewModel, settings).ConfigureAwait(true); return result?.FirstOrDefault(); } } ================================================ FILE: src/MvvmDialogs/DialogSettingsBase.cs ================================================ namespace HanumanInstitute.MvvmDialogs; /// /// Base class for dialog settings. /// public abstract class DialogSettingsBase { /// /// Gets or sets the dialog title. /// public string Title { get; set; } = string.Empty; } ================================================ FILE: src/MvvmDialogs/FileSystem/DesktopDialogStorageFactory.cs ================================================ namespace HanumanInstitute.MvvmDialogs.FileSystem; /// public class DesktopDialogStorageFactory : IDesktopDialogStorageFactory { /// public IDialogStorageFile GetFile(string filePath) => new DesktopDialogStorageFile(filePath); /// public IDialogStorageFolder GetDirectory(string path) => new DesktopDialogStorageFolder(path); } ================================================ FILE: src/MvvmDialogs/FileSystem/DesktopDialogStorageFile.cs ================================================ using System.IO; namespace HanumanInstitute.MvvmDialogs.FileSystem; /// public class DesktopDialogStorageFile : DesktopDialogStorageItem, IDialogStorageFile { private readonly FileInfo _info; /// /// Returns file system information about the file. /// public FileInfo Info => _info; /// /// Initializes a new instance of DesktopDialogStorageFile to expose a path. /// /// Information of the file to wrap. public DesktopDialogStorageFile(FileInfo info) { _info = info; } /// /// Initializes a new instance of DesktopDialogStorageFile to expose a path. /// /// The path of the file to get information for. public DesktopDialogStorageFile(string path) { _info = new FileInfo(path); if (_info == null) { throw new FileNotFoundException($"File '{path}' not found."); } } /// protected override FileSystemInfo InfoBase => _info; /// protected override DirectoryInfo? Parent => _info.Directory; /// public Task OpenReadAsync() => Task.Run(() => File.OpenRead(_info.FullName)); /// public Task OpenWriteAsync() => Task.Run(() => File.OpenWrite(_info.FullName)); /// public override Task MoveAsync(IDialogStorageFolder destination) { if (destination is DesktopDialogStorageFolder storageFolder) { var newPath = System.IO.Path.Combine(storageFolder.Info.FullName, _info.Name); _info.MoveTo(newPath); return Task.FromResult(new DesktopDialogStorageFile(destination.LocalPath)); } return Task.FromResult(null); } } ================================================ FILE: src/MvvmDialogs/FileSystem/DesktopDialogStorageFolder.cs ================================================ using System.Collections.Generic; using System.IO; using System.Linq; namespace HanumanInstitute.MvvmDialogs.FileSystem; /// public class DesktopDialogStorageFolder : DesktopDialogStorageItem, IDialogStorageFolder { private readonly DirectoryInfo _info; /// /// Returns file system information about the file. /// public DirectoryInfo Info => _info; /// /// Initializes a new instance of DialogStorageFolder to expose a path. /// /// Information of the folder to wrap. public DesktopDialogStorageFolder(DirectoryInfo info) { _info = info; } /// /// Initializes a new instance of DialogStorageFolder to expose a path. /// /// The path of the folder to get information for. public DesktopDialogStorageFolder(string path) { _info = new DirectoryInfo(path); } /// protected override FileSystemInfo InfoBase => _info; /// protected override DirectoryInfo? Parent => _info.Parent; /// public IAsyncEnumerable GetItemsAsync() => GetItemsAsync(string.Empty, SearchOption.TopDirectoryOnly); private IAsyncEnumerable GetItemsAsync(string searchPattern) => GetItemsAsync(searchPattern, SearchOption.TopDirectoryOnly); private async IAsyncEnumerable GetItemsAsync(string searchPattern, SearchOption searchOption) { var items = _info.EnumerateFileSystemInfos(searchPattern, searchOption) .Select(x => x is FileInfo f ? (IDialogStorageItem)new DesktopDialogStorageFile(f) : new DesktopDialogStorageFolder((DirectoryInfo)x)); foreach (var item in items) { yield return item; } } // /// // public IEnumerable EnumeratePathInfos(string searchPattern, SearchOption searchOption) => _info.EnumerateFileSystemInfos(searchPattern, searchOption); /// public Task CreateFileAsync(string name) { var path = System.IO.Path.Combine(LocalPath, name); File.Create(path); return Task.FromResult(new DesktopDialogStorageFile(path)); } /// public Task CreateFolderAsync(string name) { var path = System.IO.Path.Combine(LocalPath, name); Directory.CreateDirectory(path); return Task.FromResult(new DesktopDialogStorageFolder(path)); } /// public override Task MoveAsync(IDialogStorageFolder destination) { if (destination is DesktopDialogStorageFolder storageFolder) { var newPath = System.IO.Path.Combine(storageFolder.Info.FullName, Info.Name); Info.MoveTo(newPath); return Task.FromResult(new DesktopDialogStorageFolder(newPath)); } return Task.FromResult(null); } } ================================================ FILE: src/MvvmDialogs/FileSystem/DesktopDialogStorageItem.cs ================================================ using System.IO; namespace HanumanInstitute.MvvmDialogs.FileSystem; /// public abstract class DesktopDialogStorageItem : IDialogStorageItem { /// /// Information about the file or directory. /// protected abstract FileSystemInfo InfoBase { get; } /// public string Name => InfoBase.Name; /// public Uri Path => _path ??= new Uri(InfoBase.FullName); private Uri? _path; /// public string LocalPath => Path.LocalPath; /// public Task GetBasicPropertiesAsync() { if (InfoBase.Exists) { var length = InfoBase is FileInfo f ? (ulong?)f.Length : null; return Task.FromResult(new DesktopDialogStorageItemProperties(length, InfoBase.CreationTimeUtc, InfoBase.LastWriteTimeUtc)); } return Task.FromResult(new DesktopDialogStorageItemProperties()); } /// public bool CanBookmark => true; /// public Task SaveBookmarkAsync() => Task.FromResult((string?)InfoBase.FullName); /// public Task GetParentAsync() { var parent = Parent; return Task.FromResult(parent != null ? new DesktopDialogStorageFolder(parent) : null); } /// /// /// protected abstract DirectoryInfo? Parent { get; } /// public Task DeleteAsync() => Task.Run(() => InfoBase.Delete()); /// public abstract Task MoveAsync(IDialogStorageFolder destination); /// public void Dispose() { } } ================================================ FILE: src/MvvmDialogs/FileSystem/DesktopDialogStorageItemProperties.cs ================================================ namespace HanumanInstitute.MvvmDialogs.FileSystem; /// /// Provides access to the content-related properties of an item (like a file or folder). /// public class DesktopDialogStorageItemProperties { /// /// Initializes a new instance of the DialogStorageItemProperties class. /// /// The size of the file in bytes. /// The date and time that the current folder was created. /// The date and time of the last time the file was modified. public DesktopDialogStorageItemProperties( ulong? size = null, DateTimeOffset? dateCreated = null, DateTimeOffset? dateModified = null) { Size = size; DateCreated = dateCreated; DateModified = dateModified; } /// /// Gets the size of the file in bytes. /// /// /// Can be null if property is not available. /// public ulong? Size { get; } /// /// Gets the date and time that the current folder was created. /// /// /// Can be null if property is not available. /// public DateTimeOffset? DateCreated { get; } /// /// Gets the date and time of the last time the file was modified. /// /// /// Can be null if property is not available. /// public DateTimeOffset? DateModified { get; } } ================================================ FILE: src/MvvmDialogs/FileSystem/IDesktopDialogStorageFactory.cs ================================================ namespace HanumanInstitute.MvvmDialogs.FileSystem; /// /// Allows creating dialog storage classes to get file/folder information. Direct file access will only work in desktop OS. /// public interface IDesktopDialogStorageFactory { /// /// Creates a new instance of to get information about a file path. /// /// The path of the file to get information for. /// A new instance. IDialogStorageFile GetFile(string filePath); /// /// Creates a new instance of to get information about a directory path. /// /// The path of the directory to get information for. /// A new instance. IDialogStorageFolder GetDirectory(string path); } ================================================ FILE: src/MvvmDialogs/FileSystem/IDialogStorageFile.cs ================================================ using System.IO; namespace HanumanInstitute.MvvmDialogs.FileSystem; /// /// Represents a file. Provides information about the file and its contents, and ways to manipulate them. /// public interface IDialogStorageFile : IDialogStorageItem { /// /// Opens a stream for read access. /// Task OpenReadAsync(); /// /// Opens stream for writing to the file. /// Task OpenWriteAsync(); } ================================================ FILE: src/MvvmDialogs/FileSystem/IDialogStorageFolder.cs ================================================ using System.Collections.Generic; namespace HanumanInstitute.MvvmDialogs.FileSystem; /// /// Manipulates folders and their contents, and provides information about them. /// public interface IDialogStorageFolder : IDialogStorageItem { /// /// Gets the files and subfolders in the current folder. /// /// The path encapsulated in the object is invalid (for example, it is on an unmapped drive). /// The caller does not have the required permission. /// When this method completes successfully, it returns a list of the files and folders in the current folder. Each item in the list is represented by an implementation object. IAsyncEnumerable GetItemsAsync(); // /// // /// Gets the files and subfolders in the current folder. // /// // /// The search string to match against the names of directories. This parameter can contain a combination of valid literal path and wildcard (* and ?) characters, but it doesn't support regular expressions. // /// The path encapsulated in the object is invalid (for example, it is on an unmapped drive). // /// The caller does not have the required permission. // /// When this method completes successfully, it returns a list of the files and folders in the current folder. Each item in the list is represented by an implementation object. // Task> GetItemsAsync(string searchPattern); // /// // /// Gets the files and subfolders in the current folder. // /// // /// The search string to match against the names of directories. This parameter can contain a combination of valid literal path and wildcard (* and ?) characters, but it doesn't support regular expressions. // /// One of the enumeration values that specifies whether the search operation should include only the current directory or all subdirectories. The default value is . // /// The path encapsulated in the object is invalid (for example, it is on an unmapped drive). // /// The caller does not have the required permission. // /// When this method completes successfully, it returns a list of the files and folders in the current folder. Each item in the list is represented by an implementation object. // Task> GetItemsAsync(string searchPattern, SearchOption searchOption); /// /// Creates a file with specified name as a child of the current storage folder /// /// The display name /// A new pointing to the moved file. If not null, the current storage item becomes invalid Task CreateFileAsync(string name); /// /// Creates a folder with specified name as a child of the current storage folder /// /// The display name /// A new pointing to the moved file. If not null, the current storage item becomes invalid Task CreateFolderAsync(string name); } ================================================ FILE: src/MvvmDialogs/FileSystem/IDialogStorageItem.cs ================================================ namespace HanumanInstitute.MvvmDialogs.FileSystem; /// /// Manipulates storage items (files and folders) and their contents, and provides information about them /// /// /// This interface inherits . It's recommended to dispose when it's not used anymore. /// public interface IDialogStorageItem : IDisposable { /// /// Gets the name of the item including the file name extension if there is one. /// string Name { get; } /// /// Gets the full file-system path of the item, if the item has a path. /// /// /// Android backend might return file path with "content:" scheme. /// Browser and iOS backends might return relative uris. /// Uri Path { get; } /// /// Gets a local operating-system representation of a file name. /// string LocalPath { get; } /// /// Gets the basic properties of the current item. /// Task GetBasicPropertiesAsync(); /// /// Returns true is item can be bookmarked and reused later. /// bool CanBookmark { get; } /// /// Saves items to a bookmark. /// /// /// Returns identifier of a bookmark. Can be null if OS denied request. /// Task SaveBookmarkAsync(); /// /// Gets the parent folder of the current storage item. /// Task GetParentAsync(); /// /// Deletes the current storage item and it's contents /// Task DeleteAsync(); /// /// Moves the current storage item and it's contents to a /// /// The to move the item into Task MoveAsync(IDialogStorageFolder destination); } ================================================ FILE: src/MvvmDialogs/FrameworkDialogs/FileDialogSettings.cs ================================================ using System.Collections.Generic; namespace HanumanInstitute.MvvmDialogs.FrameworkDialogs; /// /// Settings for FileDialog. /// public abstract class FileDialogSettings : PickerDialogSettings { /// /// Gets or sets a value indicating whether a file dialog returns either the location of /// the file referenced by a shortcut or the location of the shortcut file (.lnk). /// public bool DereferenceLinks { get; set; } = true; /// /// Gets or sets a collection of filters which determine the types of files displayed in an /// OpenFileDialog or SaveFileDialog. /// /// /// The '.' in extensions is optional. Extensions will automatically be added /// to the descriptions unless it contains '('. /// If you do not wish to display extensions, end the name with '()' and it will be trimmed away. /// public IList Filters { get; set; } = new List(); /// /// Gets or sets the initial file that is displayed by a file dialog. /// public string SuggestedFileName { get; set; } = string.Empty; /// /// Callback to invoke when the user clicks the help button. Setting this will display a help button. /// public EventHandler? HelpRequest { get; set; } } ================================================ FILE: src/MvvmDialogs/FrameworkDialogs/FileFilter.cs ================================================ using System.Collections.Generic; using System.Linq; using System.Text; namespace HanumanInstitute.MvvmDialogs.FrameworkDialogs; /// /// Represents a filter in an OpenFileDialog or SaveFileDialog. /// public class FileFilter { /// /// Initializes a new instance of the FileFilter class. /// public FileFilter() { } /// /// Initializes a new instance of the FileFilter class. /// /// The display name of the filter. /// The file extension to filter on, excluding the trailing dot. public FileFilter(string name, string extension) { Name = name; Extensions = new[] { extension }; } /// /// Initializes a new instance of the FileFilter class. /// /// The display name of the filter. /// The file extensions to filter on, excluding the trailing dots. public FileFilter(string name, IReadOnlyList extensions) { Name = name; Extensions = extensions; } /// /// Gets or sets the display name of the filter. /// public string Name { get; set; } = string.Empty; /// /// Gets or sets a list of file extensions matched by the filter, excluding the trailing dots (e.g. "txt" or "*" for all files). /// /// /// Used on Windows and Linux systems. /// public IReadOnlyList? Extensions { get; set; } /// /// List of extensions in MIME format. /// /// /// Used on Android, Browser and Linux systems. /// public IReadOnlyList? MimeTypes { get; set; } /// /// List of extensions in Apple uniform format. /// /// /// Used only on Apple devices. /// See https://developer.apple.com/documentation/uniformtypeidentifiers/system_declared_uniform_type_identifiers. /// public IReadOnlyList? AppleUniformTypeIdentifiers { get; set; } /// /// Returns a string with all extensions starting with '*.' and separated by specified separator. /// ex: "*.BMP;*.JPG;*.GIF" /// /// The separator between extensions. /// A string representation of the extensions. public string? ExtensionsToString(char separator = ';') { if (Extensions == null) { return null; } var builder = new StringBuilder(); foreach (var ext in Extensions.Select(x => x.TrimStart('.'))) { // Add separator. if (builder.Length > 0) { builder.Append(separator); } // Add *.ext builder.Append('*'); if (!string.IsNullOrEmpty(ext) && !ext.StartsWith("'")) { builder.Append('.'); } builder.Append(ext); } return builder.ToString(); } /// /// Returns a string containing the name plus extensions. /// ex: "Image Files (*.BMP;*.JPG;*.GIF)" /// /// /// The '.' in extensions is optional. Extensions will automatically be added /// to the descriptions unless it contains '('. /// If you do not wish to display extensions, end the name with '()' and it will be trimmed away. /// /// The extensions to add, calculated with . /// The name ready for display. public string NameToString(string? extensions) { var name = Name ?? string.Empty; // Only add extensions to description if it doesn't contain parenthesis. var hasExtInDesc = name.Contains("("); // If name ends with '()', trim it and display no extensions. if (name.EndsWith("()")) { name = name.Substring(0, name.Length - 2).TrimEnd(); } // Add all extensions to description. if (!hasExtInDesc && !string.IsNullOrEmpty(extensions)) { name += " (" + extensions + ")"; } return name; } } ================================================ FILE: src/MvvmDialogs/FrameworkDialogs/MessageBoxButton.cs ================================================ namespace HanumanInstitute.MvvmDialogs.FrameworkDialogs; /// /// Specifies the buttons that are displayed on a message box. /// public enum MessageBoxButton { /// /// The message box displays an OK button. /// Ok, /// /// The message box displays OK and Cancel buttons. /// OkCancel, /// /// The message box displays Yes and No buttons. /// YesNo, /// /// The message box displays Yes, No, and Cancel buttons. /// YesNoCancel } ================================================ FILE: src/MvvmDialogs/FrameworkDialogs/MessageBoxImage.cs ================================================ namespace HanumanInstitute.MvvmDialogs.FrameworkDialogs; /// /// Specifies the icon that is displayed by a message box. /// public enum MessageBoxImage { /// /// The message box contains no symbols. /// None, /// /// The message box contains a symbol consisting of white X in a circle with a red background. /// Error, /// /// The message box contains a symbol consisting of an exclamation point in a triangle with a yellow background. /// Exclamation, /// /// The message box contains a symbol consisting of a lowercase letter i in a circle. /// Information, /// /// The message box contains a symbol consisting of white X in a circle with a red background. /// Stop, /// /// The message box contains a symbol consisting of an exclamation point in a triangle with a yellow background. /// Warning } ================================================ FILE: src/MvvmDialogs/FrameworkDialogs/MessageBoxSettings.cs ================================================  namespace HanumanInstitute.MvvmDialogs.FrameworkDialogs; /// /// Settings for a MessageBox. /// public class MessageBoxSettings : DialogSettingsBase { /// /// Gets or sets the value that specifies which button or /// buttons to display. Default value is . /// public MessageBoxButton Button { get; set; } = MessageBoxButton.Ok; /// /// Gets or sets the value of the button selected by default. True=OK/Yes, False=No, Null=Cancel. /// public bool? DefaultValue { get; set; } = true; /// /// Gets or sets the value that specifies the icon to /// display. Default value is . /// public MessageBoxImage Icon { get; set; } = MessageBoxImage.None; /// /// Gets or sets the that specifies the text to display. /// public string Content { get; set; } = string.Empty; } ================================================ FILE: src/MvvmDialogs/FrameworkDialogs/OpenFileDialogSettings.cs ================================================  namespace HanumanInstitute.MvvmDialogs.FrameworkDialogs; /// /// Settings for OpenFileDialog. /// public class OpenFileDialogSettings : FileDialogSettings { /// /// DO NOT USE. Use OpenFileDialog / OpenFilesDialog instead. /// public bool? AllowMultiple { get; set; } /// /// Gets or sets a value indicating whether the open file dialog contains a read-only check box. /// Only supported in WPF. /// public bool ShowReadOnly { get; set; } /// /// Gets or sets a value indicating whether the read-only check box displayed by the open file dialog is selected. /// public bool ReadOnlyChecked { get; set; } } ================================================ FILE: src/MvvmDialogs/FrameworkDialogs/OpenFolderDialogSettings.cs ================================================ namespace HanumanInstitute.MvvmDialogs.FrameworkDialogs; /// /// Settings for FolderBrowserDialog. /// public class OpenFolderDialogSettings : PickerDialogSettings { /// /// DO NOT USE. Use OpenFolderDialog / OpenFoldersDialog instead. /// public bool? AllowMultiple { get; set; } /// /// Callback to invoke when the user clicks the help button. Setting this will display a help button. /// public EventHandler? HelpRequest { get; set; } } ================================================ FILE: src/MvvmDialogs/FrameworkDialogs/PickerDialogSettings.cs ================================================ using HanumanInstitute.MvvmDialogs.FileSystem; namespace HanumanInstitute.MvvmDialogs.FrameworkDialogs; /// /// Settings for file/folder picker dialogs. /// public abstract class PickerDialogSettings : DialogSettingsBase { /// /// Gets or sets the initial directory that is displayed by a file dialog. /// public IDialogStorageFolder? SuggestedStartLocation { get; set; } } ================================================ FILE: src/MvvmDialogs/FrameworkDialogs/SaveFileDialogSettings.cs ================================================ namespace HanumanInstitute.MvvmDialogs.FrameworkDialogs; /// /// Settings for SaveFileDialog. /// public class SaveFileDialogSettings : FileDialogSettings { /// /// Gets or sets the default extension to be used (including the period ".") /// if not set by the user or by a filter /// public string? DefaultExtension { get; set; } } ================================================ FILE: src/MvvmDialogs/IActivable.cs ================================================ namespace HanumanInstitute.MvvmDialogs; /// /// When implemented by a ViewModel, allows to activate the View from the ViewModel by raising the RequestActivate event. /// public interface IActivable { /// /// When raised from the ViewModel, activates the associated view. /// event EventHandler? RequestActivate; } ================================================ FILE: src/MvvmDialogs/ICloseable.cs ================================================ namespace HanumanInstitute.MvvmDialogs; /// /// When implemented by a ViewModel, allows to close the View from the ViewModel by raising the RequestClose event. /// public interface ICloseable { /// /// When raised from the ViewModel, closes the associated view. /// event EventHandler? RequestClose; } ================================================ FILE: src/MvvmDialogs/IDialogFactory.cs ================================================ namespace HanumanInstitute.MvvmDialogs; /// /// Interface representing a framework dialog. /// public interface IDialogFactory { /// /// Opens a framework dialog with specified owner. /// /// Handle to the window that owns the dialog. /// The settings for the framework dialog. /// The type of settings to use for this dialog. /// Return data specific to the dialog. Task ShowDialogAsync(IView? owner, TSettings settings); /// /// Gets or sets a reference to the . Will only be set to the root factory in the chain. /// IDialogManager? DialogManager { get; set; } /// /// If the dialog is not handled by this class, calls this other handler next. /// IDialogFactory? Chain { get; } /// /// A reference to the top of the IDialogFactory chain, used to display message boxes. /// IDialogFactory ChainTop { get; } } ================================================ FILE: src/MvvmDialogs/IDialogManager.cs ================================================ using Microsoft.Extensions.Logging; namespace HanumanInstitute.MvvmDialogs; /// /// Interface responsible for UI interactions. /// public interface IDialogManager { /// /// Gets the ILogger that captures MvvmDialogs logs. /// ILogger? Logger { get; } /// /// Whether to allow multiple framework dialogs to be displayed at once. /// public bool AllowConcurrentDialogs { get; set; } /// /// Shows a new window of specified type. /// /// A view model that represents the owner window of the dialog. /// The view model of the new dialog. void Show(INotifyPropertyChanged? ownerViewModel, INotifyPropertyChanged viewModel); /// /// Shows a new dialog of specified type. /// /// A view model that represents the owner window of the dialog. /// The view model of the new dialog. /// The dialog result. Task ShowDialogAsync(INotifyPropertyChanged ownerViewModel, IModalDialogViewModel viewModel); /// /// Shows a framework dialog whose type depends on the settings type. /// /// A view model that represents the owner window of the dialog. /// The settings to pass to the /// A function to convert the result into a string for logging. If null, ToString will be used. /// The settings type used to determine which dialog to show. /// The dialog result. Task ShowFrameworkDialogAsync(INotifyPropertyChanged? ownerViewModel, TSettings settings, Func? resultToString = null) where TSettings : DialogSettingsBase; /// /// Returns the window with a DataContext equal to specified ViewModel. /// /// The ViewModel to search for. /// A IView, or null. IView? FindViewByViewModel(INotifyPropertyChanged viewModel); /// /// Returns the main window of the application. /// /// The main window. IView? GetMainWindow(); /// /// Returns an empty window that can be used as an owner when none is specified. /// /// A dummy window. IView? GetDummyWindow(); /// /// Subscribes to View events. By default, ICloseable and IActivable are handled. /// /// The view model of the new dialog. /// The dialog being shown. void HandleDialogEvents(INotifyPropertyChanged viewModel, IView dialog); } ================================================ FILE: src/MvvmDialogs/IDialogService.cs ================================================  namespace HanumanInstitute.MvvmDialogs; /// /// Interface abstracting the interaction between view models and views when it comes to /// opening dialogs using the MVVM pattern in WPF. /// public interface IDialogService { /// /// Factory responsible for creating framework dialogs. /// IDialogManager DialogManager { get; } /// /// Displays a non-modal dialog of a type that is determined by the dialog type locator. /// /// A view model that represents the owner window of the dialog. /// The view model of the new dialog. /// No view is registered with specified owner view model as data context. void Show(INotifyPropertyChanged? ownerViewModel, INotifyPropertyChanged viewModel); /// /// Displays a non-modal dialog of specified type . /// /// A view model that represents the owner window of the dialog. /// The view model of the new dialog. /// The type of the dialog to show. /// No view is registered with specified owner view model as data context. void Show(INotifyPropertyChanged? ownerViewModel, INotifyPropertyChanged viewModel); //where T : TWindow; /// /// Displays a modal dialog of a type that is determined by the dialog type locator. /// /// A view model that represents the owner window of the dialog. /// The view model of the new dialog. /// A nullable value of type that signifies how a window was closed by the user. /// No view is registered with specified owner view model as data context. Task ShowDialogAsync(INotifyPropertyChanged ownerViewModel, IModalDialogViewModel viewModel); /// /// Displays a modal dialog of specified type . /// /// A view model that represents the owner window of the dialog. /// The view model of the new dialog. /// The type of the dialog to show. /// A nullable value of type that signifies how a window was closed by the user. /// No view is registered with specified owner view model as data context. Task ShowDialogAsync(INotifyPropertyChanged ownerViewModel, IModalDialogViewModel viewModel); // where T : TWindow; /// /// Attempts to bring the window to the foreground and activates it. /// /// The view model of the window. /// true if the window was successfully activated; otherwise, false. bool Activate(INotifyPropertyChanged viewModel); /// /// Closes a non-modal dialog that previously was opened using , /// /// The view model of the dialog to close. /// true if the window was successfully closed; otherwise, false. bool Close(INotifyPropertyChanged viewModel); /// /// Creates a view model of specified type, using the ViewModelFactory passed in the constructor. /// /// The type of the view model to create. /// The newly created view model. object CreateViewModel(Type type); /// /// Creates a view model of specified type, using the ViewModelFactory passed in the constructor. /// /// The type of the view model to create. /// The newly created view model. T CreateViewModel(); } ================================================ FILE: src/MvvmDialogs/IModalDialogViewModel.cs ================================================ namespace HanumanInstitute.MvvmDialogs; /// /// A view model representing a modal dialog opened using . /// public interface IModalDialogViewModel : INotifyPropertyChanged { /// /// Gets the dialog result value, which is the value that is returned from the /// and /// methods. /// bool? DialogResult { get; } } ================================================ FILE: src/MvvmDialogs/IView.cs ================================================ namespace HanumanInstitute.MvvmDialogs; /// /// Interface describing a generic window. /// /// /// This interface allows cross-platform support, and allows for custom windows /// not deriving from the standard types. /// public interface IView { /// /// Initializes the from specified view model and view type. /// /// The view model to display. /// The view definition including its type and how to create one. void Initialize(INotifyPropertyChanged viewModel, ViewDefinition viewDef); /// /// Initializes the from specified view model and existing view. /// /// The view model to display. /// The view to display. void InitializeExisting(INotifyPropertyChanged viewModel, object view); /// /// Gets the Window reference held by this class. /// public object RefObj { get; } /// /// Occurs when the window is loaded. /// event EventHandler Loaded; /// /// Occurs when the window is closing. /// event EventHandler Closing; /// /// Occurs when the window is closed. /// event EventHandler Closed; /// /// Gets or sets the data context for an element when it participates in data binding. /// INotifyPropertyChanged? ViewModel { get; } /// /// Opens a window and returns without waiting for the newly opened window to close. /// void Show(IView? owner); /// /// Opens a window and returns only when the newly opened window is closed. /// /// /// A task that represents the asynchronous operation. /// Task ShowDialogAsync(IView owner); /// /// Tries to activate the Window. /// void Activate(); /// /// Tries to close the Window. /// void Close(); /// /// Gets or sets whether the window is enabled. /// bool IsEnabled { get; set; } /// /// Gets whether the window is visible. /// bool IsVisible { get; } /// /// Gets or sets whether closing has been confirmed, in which case Closing event should be ignored. /// bool ClosingConfirmed { get; set; } } ================================================ FILE: src/MvvmDialogs/IViewClosed.cs ================================================ namespace HanumanInstitute.MvvmDialogs; /// /// When implemented by a ViewModel, handles the View Closed event. /// public interface IViewClosed { /// /// Called when the view is closed. /// void OnClosed(); } ================================================ FILE: src/MvvmDialogs/IViewClosing.cs ================================================ namespace HanumanInstitute.MvvmDialogs; /// /// When implemented by a ViewModel, handles the View Closing event. /// public interface IViewClosing { /// /// Called when the view is closing. If e.Cancel is set to true, will be called. /// void OnClosing(CancelEventArgs e); /// /// Called when e.Cancel is set to true in . If e.Cancel is set back to false, the window will be closed. /// Task OnClosingAsync(CancelEventArgs e); } ================================================ FILE: src/MvvmDialogs/IViewLoaded.cs ================================================ namespace HanumanInstitute.MvvmDialogs; /// /// When implemented by a ViewModel, handles the View Loaded event. /// public interface IViewLoaded { /// /// Called when the view is loaded. /// void OnLoaded(); } ================================================ FILE: src/MvvmDialogs/IViewLocator.cs ================================================ namespace HanumanInstitute.MvvmDialogs; /// /// Interface responsible for finding a dialog type matching a view model. /// public interface IViewLocator { /// /// Get the view type based on the specified view model. /// /// The view model to get the view type for. /// View not found for view model. ViewDefinition Locate(object viewModel); /// /// Creates a view based on the specified view model. /// /// The view model to create a view for. /// View not found for view model. object Create(object viewModel); } ================================================ FILE: src/MvvmDialogs/MvvmDialogs.csproj ================================================  net10.0;net8.0;net462 Library MVVM Dialogs true ../StrongName.snk HanumanInstitute.MvvmDialogs HanumanInstitute.MvvmDialogs HanumanInstitute.MvvmDialogs True True icon_64x64.png True \ StrongName.snk ================================================ FILE: src/MvvmDialogs/MvvmDialogs.csproj.DotSettings ================================================  True ================================================ FILE: src/MvvmDialogs/Private/NullableAttributes.cs ================================================ #pragma warning disable MA0048 // File name must match type name #define INTERNAL_NULLABLE_ATTRIBUTES // https://github.com/dotnet/corefx/blob/48363ac826ccf66fbe31a5dcb1dc2aab9a7dd768/src/Common/src/CoreLib/System/Diagnostics/CodeAnalysis/NullableAttributes.cs // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. // ReSharper disable once CheckNamespace namespace System.Diagnostics.CodeAnalysis; #if NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NET45 || NET451 || NET452 || NET6 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48 /// Specifies that null is allowed as an input even if the corresponding type disallows it. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class AllowNullAttribute : Attribute { } /// Specifies that null is disallowed as an input even if the corresponding type allows it. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class DisallowNullAttribute : Attribute { } /// Specifies that an output may be null even if the corresponding type disallows it. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class MaybeNullAttribute : Attribute { } /// Specifies that an output will not be null even if the corresponding type allows it. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class NotNullAttribute : Attribute { } /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class MaybeNullWhenAttribute : Attribute { /// Initializes the attribute with the specified return value condition. /// /// The return value condition. If the method returns this value, the associated parameter may be null. /// public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; /// Gets the return value condition. public bool ReturnValue { get; } } /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class NotNullWhenAttribute : Attribute { /// Initializes the attribute with the specified return value condition. /// /// The return value condition. If the method returns this value, the associated parameter will not be null. /// public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; /// Gets the return value condition. public bool ReturnValue { get; } } /// Specifies that the output will be non-null if the named parameter is non-null. [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class NotNullIfNotNullAttribute : Attribute { /// Initializes the attribute with the associated parameter name. /// /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. /// public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName; /// Gets the associated parameter name. public string ParameterName { get; } } /// Applied to a method that will never return under any circumstance. [AttributeUsage(AttributeTargets.Method, Inherited = false)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class DoesNotReturnAttribute : Attribute { } /// Specifies that the method will not return if the associated Boolean parameter is passed the specified value. [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class DoesNotReturnIfAttribute : Attribute { /// Initializes the attribute with the specified parameter value. /// /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to /// the associated parameter matches this value. /// public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue; /// Gets the condition parameter value. public bool ParameterValue { get; } } #endif // NETSTANDARD2_0 attributes #if NETSTANDARD2_1 || NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NETCOREAPP3_1 || NET45 || NET451 || NET452 || NET6 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48 /// /// Specifies that the method or property will ensure that the listed field and property members have /// not- values. /// [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class MemberNotNullAttribute : Attribute { /// Gets field or property member names. public string[] Members { get; } /// Initializes the attribute with a field or property member. /// The field or property member that is promised to be not-null. public MemberNotNullAttribute(string member) { Members = new[] { member }; } /// Initializes the attribute with the list of field and property members. /// The list of field and property members that are promised to be not-null. public MemberNotNullAttribute(params string[] members) { Members = members; } } /// /// Specifies that the method or property will ensure that the listed field and property members have /// non- values when returning with the specified return value condition. /// [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class MemberNotNullWhenAttribute : Attribute { /// Gets the return value condition. public bool ReturnValue { get; } /// Gets field or property member names. public string[] Members { get; } /// Initializes the attribute with the specified return value condition and a field or property member. /// /// The return value condition. If the method returns this value, /// the associated parameter will not be . /// /// The field or property member that is promised to be not-. public MemberNotNullWhenAttribute(bool returnValue, string member) { ReturnValue = returnValue; Members = new[] { member }; } /// Initializes the attribute with the specified return value condition and list of field and property members. /// /// /// The return value condition. If the method returns this value, /// the associated parameter will not be . /// /// The list of field and property members that are promised to be not-null. public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { ReturnValue = returnValue; Members = members; } } #endif // NETSTANDARD2_1 attributes ================================================ FILE: src/MvvmDialogs/Private/ViewIdGenerator.cs ================================================ using System.Threading; namespace HanumanInstitute.MvvmDialogs.Private; internal static class ViewIdGenerator { private static int s_id; public static int Generate() => Interlocked.Increment(ref s_id); } ================================================ FILE: src/MvvmDialogs/StrongViewLocatorBase.cs ================================================ using System.Collections.Generic; namespace HanumanInstitute.MvvmDialogs; /// /// Strongly-typed View Locator that does not rely on reflection. /// public abstract class StrongViewLocatorBase : IViewLocator { /// /// The list of registered ViewModel-View combinations. /// protected readonly Dictionary Registrations = new(); /// /// Registers specified views as being associated with specified view model type. /// If multiple views are registered, they can be selected based on factors such as platform, such as Desktop vs Mobile vs Web. /// /// The view definition including its type and how to create one. /// The type of view model to register. protected void Register(ViewDefinition viewDef) where TViewModel : INotifyPropertyChanged { Registrations.Add(typeof(TViewModel), viewDef); } /// public virtual ViewDefinition Locate(object viewModel) { if (Registrations.TryGetValue(viewModel.GetType(), out var view)) { return view; } else { var message = $"No view was registered for view model {viewModel.GetType().FullName}."; const string ErrorInfo = "This project uses a StrongViewLocator, which requires manually registering all ViewModel-View combinations."; throw new TypeLoadException(message + Environment.NewLine + ErrorInfo); } } /// public virtual object Create(object viewModel) => Locate(viewModel).Create(); } ================================================ FILE: src/MvvmDialogs/Usings.cs ================================================ global using System; global using System.ComponentModel; global using System.Threading.Tasks; ================================================ FILE: src/MvvmDialogs/ViewBase.cs ================================================ using HanumanInstitute.MvvmDialogs.Private; namespace HanumanInstitute.MvvmDialogs; /// /// Holds a weak reference to a View instance. /// public abstract class ViewBase { private readonly WeakReference _viewReference; /// /// Initializes a new instance of the class and hold a weak reference to specified object. /// /// The object to hold a weak reference for. protected ViewBase(object view) { if (view == null) throw new ArgumentNullException(nameof(view)); _viewReference = new WeakReference(view); } /// /// Occurs when the object is fully loaded. /// public virtual event EventHandler? Loaded; /// /// Returns an auto-generated unique ID for the view. /// public int Id { get; } = ViewIdGenerator.Generate(); /// /// Returns whether the weak reference is still available. /// public virtual bool IsAlive => _viewReference.IsAlive; /// /// Returns the original view reference if it is still alive. /// /// View has been garbage collected. public virtual object SourceObj { get { if (!IsAlive) throw new InvalidOperationException("View has been garbage collected."); if (_viewReference.Target == null) throw new InvalidOperationException("View has been set to null."); return _viewReference.Target; } } /// /// Returns the owner of the element, within a wrapper. /// /// A wrapper around the owner, or null. public abstract IView? GetOwner(); /// /// Returns whether referenced element is loaded. /// public abstract bool IsLoaded { get; } /// /// Returns the DataContext of referenced element. /// public abstract object? DataContext { get; } /// Determines whether specified view references the same object as the current view. /// The object to compare with the current object. /// true if specified view references the same object; otherwise, false. public override bool Equals(object? obj) => obj is ViewBase other && SourceObj.Equals(other.SourceObj); /// Returns the hash code of referenced object. /// A hash code. public override int GetHashCode() => SourceObj.GetHashCode(); /// /// Raises the Loaded event. /// protected void RaiseLoaded() => Loaded?.Invoke(this, EventArgs.Empty); } ================================================ FILE: src/MvvmDialogs/ViewDefinition.cs ================================================ namespace HanumanInstitute.MvvmDialogs; /// /// Defines a View, its type and how to create one. /// public readonly struct ViewDefinition { /// /// Initializes a new instance of the ViewDefinition class. /// /// The type of the view, must match the return type of function. /// A function to create a new instance of the view without using reflection. public ViewDefinition(Type viewType, Func createFunc) { CreateFunc = createFunc; ViewType = viewType; } /// /// The type of the view, must match the return type of function. /// public Type ViewType { get; } /// /// A function to create a new instance of the view without using reflection. /// public Func CreateFunc { get; } /// /// Executes CreateFunc to create a new view. /// /// The newly created view. public object Create() => CreateFunc.Invoke(); /// /// Returns whether the view type derives from specified class or interface. A base class instance is also accepted. /// /// The type to verify against ViewType. /// True if ViewType derives from specified type, otherwise false. public bool TypeDerivesFrom() => typeof(T).IsAssignableFrom(ViewType); } ================================================ FILE: src/MvvmDialogs/ViewNotRegisteredException.cs ================================================ #if NETSTANDARD2_0_OR_GREATER using System.Runtime.Serialization; #endif namespace HanumanInstitute.MvvmDialogs; /// /// Exception thrown by when a view isn't registered, but its /// DataContext is accessing the dialog service. /// #if NETSTANDARD2_0_OR_GREATER [Serializable] #endif public class ViewNotRegisteredException : Exception { /// /// Initializes a new instance of the class. /// /// The error message that explains the reason for the exception. /// The exception that is the cause of the current exception, or a null reference if no /// inner exception is specified. public ViewNotRegisteredException(string? message = null, Exception? innerException = null) : base(message, innerException) { } #if NETSTANDARD2_0_OR_GREATER /// /// Initializes a new instance of the class. /// /// The that holds the serialized object data about the /// exception being thrown. /// The that contains contextual information about the /// source or destination. protected ViewNotRegisteredException(SerializationInfo info, StreamingContext context) : base(info, context) { } #endif } ================================================ FILE: src/MvvmDialogs.Avalonia/Api/FrameworkDialogsApi.cs ================================================ using System.Collections.Generic; using System.Linq; using Avalonia.Platform.Storage; using HanumanInstitute.MvvmDialogs.FileSystem; namespace HanumanInstitute.MvvmDialogs.Avalonia.Api; /// internal class FrameworkDialogsApi : IFrameworkDialogsApi { public async Task> ShowOpenFileDialogAsync(ContentControl? owner, FilePickerOpenOptions options) { if (owner == null) { throw new ArgumentNullException(nameof(owner)); } var result = await GetStorage(owner).OpenFilePickerAsync(options).ConfigureAwait(true); return result.Select(x => new AvaloniaDialogStorageFile(x)).ToList(); } public async Task ShowSaveFileDialogAsync(ContentControl? owner, FilePickerSaveOptions options) { if (owner == null) { throw new ArgumentNullException(nameof(owner)); } var result = await GetStorage(owner).SaveFilePickerAsync(options).ConfigureAwait(true); return result != null ? new AvaloniaDialogStorageFile(result) : null; } public async Task> ShowOpenFolderDialogAsync(ContentControl? owner, FolderPickerOpenOptions options) { if (owner == null) { throw new ArgumentNullException(nameof(owner)); } var result = await GetStorage(owner).OpenFolderPickerAsync(options).ConfigureAwait(true); return result.Select(x => new AvaloniaDialogStorageFolder(x)).ToList(); } private static IStorageProvider GetStorage(ContentControl owner) => TopLevel.GetTopLevel(owner)?.StorageProvider ?? throw new ArgumentException("Cannot find StorageProvider for specified dialog owner.", nameof(owner)); } ================================================ FILE: src/MvvmDialogs.Avalonia/Api/IFrameworkDialogsApi.cs ================================================  using System.Collections.Generic; using Avalonia.Platform.Storage; using HanumanInstitute.MvvmDialogs.FileSystem; namespace HanumanInstitute.MvvmDialogs.Avalonia.Api; /// /// Wrapper around Win32 dialogs API that can be replaced by a mock for testing. /// internal interface IFrameworkDialogsApi { Task> ShowOpenFileDialogAsync(ContentControl? owner, FilePickerOpenOptions options); Task ShowSaveFileDialogAsync(ContentControl? owner, FilePickerSaveOptions options); Task> ShowOpenFolderDialogAsync(ContentControl? owner, FolderPickerOpenOptions options); } ================================================ FILE: src/MvvmDialogs.Avalonia/DialogFactory.cs ================================================ using System.Collections.Generic; using System.Linq; using Avalonia.Platform.Storage; using HanumanInstitute.MvvmDialogs.Avalonia.Api; using HanumanInstitute.MvvmDialogs.FileSystem; using HanumanInstitute.MvvmDialogs.FrameworkDialogs; namespace HanumanInstitute.MvvmDialogs.Avalonia; /// /// Handles OpenFileDialog, SaveFileDialog and OpenFolderDialog for Avalonia. /// public class DialogFactory : DialogFactoryBase { private readonly IFrameworkDialogsApi _api; // private readonly IPathInfoFactory _pathInfo; /// /// Initializes a new instance of a FrameworkDialog. /// /// If the dialog is not handled by this class, calls this other handler next. public DialogFactory(IDialogFactory? chain = null) : this(chain, null) { } /// /// Initializes a new instance of a FrameworkDialog. /// /// If the dialog is not handled by this class, calls this other handler next. /// An interface exposing Avalonia framework dialogs. internal DialogFactory(IDialogFactory? chain, IFrameworkDialogsApi? api) : base(chain) { _api = api ?? new FrameworkDialogsApi(); // _pathInfo = pathInfo ?? new PathInfoFactory(); } /// public override async Task ShowDialogAsync(IView? owner, TSettings settings) => settings switch { OpenFolderDialogSettings s => await ShowOpenFolderDialogAsync(owner, s).ConfigureAwait(true), OpenFileDialogSettings s => await ShowOpenFileDialogAsync(owner, s).ConfigureAwait(true), SaveFileDialogSettings s => await ShowSaveFileDialogAsync(owner, s).ConfigureAwait(true), _ => await base.ShowDialogAsync(owner, settings).ConfigureAwait(true) }; private async Task> ShowOpenFolderDialogAsync(IView? owner, OpenFolderDialogSettings settings) { var apiSettings = new FolderPickerOpenOptions() { AllowMultiple = settings.AllowMultiple ?? false }; await AddSharedSettingsAsync(apiSettings, settings); return await _api.ShowOpenFolderDialogAsync(owner.GetRef(), apiSettings).ConfigureAwait(true); } private async Task> ShowOpenFileDialogAsync(IView? owner, OpenFileDialogSettings settings) { var apiSettings = new FilePickerOpenOptions() { AllowMultiple = settings.AllowMultiple ?? false, FileTypeFilter = SyncFilters(settings.Filters) // d.ShowReadOnly = Settings.ShowReadOnly; // d.ReadOnlyChecked = Settings.ReadOnlyChecked; }; await AddSharedSettingsAsync(apiSettings, settings); return await _api.ShowOpenFileDialogAsync(owner.GetRef(), apiSettings).ConfigureAwait(true) ?? Array.Empty(); } private async Task ShowSaveFileDialogAsync(IView? owner, SaveFileDialogSettings settings) { var apiSettings = new FilePickerSaveOptions() { DefaultExtension = string.IsNullOrEmpty(settings.DefaultExtension) ? null : settings.DefaultExtension, FileTypeChoices = SyncFilters(settings.Filters), SuggestedFileName = settings.SuggestedFileName }; await AddSharedSettingsAsync(apiSettings, settings); var result = await _api.ShowSaveFileDialogAsync(owner.GetRef(), apiSettings).ConfigureAwait(true); // Add DefaultExtension. // if (result != null && !string.IsNullOrEmpty(settings.DefaultExtension) && !_pathInfo.GetFileInfo(result).Exists && !result.Contains('.')) // { // result += "." + settings.DefaultExtension.TrimStart('.'); // } return result; } private async Task AddSharedSettingsAsync(PickerOptions d, PickerDialogSettings s) { // d.DereferenceLinks = s.DereferenceLinks; // d.Directory = s.InitialDirectory; // d.InitialFileName = s.InitialFile; // d.Filters = SyncFilters(s.Filters); if (s.SuggestedStartLocation != null) { d.SuggestedStartLocation = await s.SuggestedStartLocation.ToAvaloniaAsync(); } d.Title = s.Title; } private static List SyncFilters(IList filters) => filters.Select( x => new FilePickerFileType(x.NameToString(x.ExtensionsToString())) { Patterns = x.Extensions?.Select(y => "*." + y.TrimStart('.')).ToList(), MimeTypes = x.MimeTypes, AppleUniformTypeIdentifiers = x.AppleUniformTypeIdentifiers }).ToList(); } ================================================ FILE: src/MvvmDialogs.Avalonia/DialogFactoryBase.cs ================================================  // ReSharper disable MemberCanBePrivate.Global namespace HanumanInstitute.MvvmDialogs.Avalonia; /// /// Interface representing a framework dialog. /// public abstract class DialogFactoryBase : IDialogFactory { /// public IDialogManager? DialogManager { get; set; } /// public IDialogFactory? Chain { get; } /// public IDialogFactory ChainTop { get; private set; } /// /// Initializes a new instance of a FrameworkDialog. /// /// If the dialog is not handled by this class, calls this other handler next. protected DialogFactoryBase(IDialogFactory? chain) { Chain = chain; ChainTop = this; // Set ChainTop recursively. var item = chain; while (item is DialogFactoryBase f) { f.ChainTop = this; item = f.Chain; } } /// public virtual async Task ShowDialogAsync(IView? owner, TSettings settings) { return Chain != null ? await Chain.ShowDialogAsync(owner, settings).ConfigureAwait(true) : throw new NotSupportedException($"There is no registered dialog in IDialogFactory for settings of type {typeof(TSettings).Name}."); } /// /// Returns the set on the root factory. /// /// The . public IDialogManager GetDialogManager() => ChainTop.DialogManager ?? throw new NullReferenceException("Missing IDialogManager reference in root DialogFactory."); // /// // /// Opens a framework dialog with specified owner. // /// // /// Handle to the window that owns the dialog. // /// The settings for the framework dialog. // /// Application-wide settings configured on the DialogService. // /// Return data specific to the dialog. // public virtual async Task ShowDialogAsync(ViewWrapper? owner, TSettings settings, AppDialogSettings appSettings) => // Chain != null ? await Chain.ShowDialogAsync(owner, settings, appSettings).ConfigureAwait(true) : // throw new NotSupportedException($"There is no registered dialog in IDialogFactory for settings of type {typeof(TSettings).Name}."); } ================================================ FILE: src/MvvmDialogs.Avalonia/DialogManager.cs ================================================ using System.Collections.Generic; using System.Linq; using Avalonia.Controls.ApplicationLifetimes; using Microsoft.Extensions.Logging; using Avalonia.Threading; using Avalonia.Media; using HanumanInstitute.MvvmDialogs.Avalonia.Navigation; namespace HanumanInstitute.MvvmDialogs.Avalonia; /// /// DialogManager for Avalonia. /// public class DialogManager : DialogManagerBase { private readonly NavigationManager? _navigationManager; private readonly IDispatcher _dispatcher; private readonly bool _useNavigation; /// public DialogManager( IViewLocator? viewLocator = null, IDialogFactory? dialogFactory = null, ILogger? logger = null, IDispatcher? dispatcher = null, Control? customNavigationRoot = null) : base( viewLocator ?? new ViewLocatorBase(), dialogFactory ?? new DialogFactory(), logger) { _dispatcher = dispatcher ?? Dispatcher.UIThread; _useNavigation = Application.Current?.ApplicationLifetime is ISingleViewApplicationLifetime || viewLocator is IViewLocatorNavigation { ForceSinglePageNavigation: true }; if (_useNavigation) { ForwardViewEvents = false; _navigationManager = new NavigationManager(View_Closing); _navigationManager.Launch(customNavigationRoot); } } /// /// If using single-page navigation mode, returns the navigation manager. /// public INavigationManager? NavigationManager => _navigationManager; /// protected override bool IsDesignMode => Design.IsDesignMode; /// protected override IView CreateWrapper(INotifyPropertyChanged viewModel, ViewDefinition viewDef) { var wrapper = _useNavigation ? (IView)new ViewNavigationWrapper(_navigationManager!, View_Closing) : new ViewWrapper(); wrapper.Initialize(viewModel, viewDef); return wrapper; } /// protected override IView AsWrapper(ContentControl view) => view is Window w ? w.AsWrapper() : ((UserControl)view).AsWrapper(_navigationManager!, View_Closing); private static IEnumerable Windows => (Application.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.Windows ?? Array.Empty(); /// public override IView? FindViewByViewModel(INotifyPropertyChanged viewModel) { if (_useNavigation) { return _navigationManager!.GetViewForViewModel(viewModel).AsWrapper(_navigationManager, View_Closing); } else { return Windows.FirstOrDefault(x => ReferenceEquals(viewModel, x.DataContext)).AsWrapper(); } } /// public override IView? GetMainWindow() { if (_useNavigation) { return null; } return (Application.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow.AsWrapper(); } /// public override IView? GetDummyWindow() { if (_useNavigation) { return null; } var parent = new Window() { Height = 1, Width = 1, WindowDecorations = WindowDecorations.None, ShowInTaskbar = false, CanResize = false, WindowStartupLocation = WindowStartupLocation.CenterScreen, Background = Brushes.Transparent }; parent.Show(); return parent.AsWrapper(); } /// protected override void Dispatch(Action action) { if (_dispatcher.CheckAccess()) { action(); } else { _dispatcher.Post(action, DispatcherPriority.Render); } } /// protected override Task DispatchAsync(Func action) => //_dispatcher.CheckAccess() ? Task.FromResult(action()) : _dispatcher.InvokeAsync(action, DispatcherPriority.Render); _dispatcher.CheckAccess() ? Task.FromResult(action()) : DispatchWithResult(action); /// /// Work-around for missing interface member in Avalonia v11-preview1. /// private Task DispatchWithResult(Func action) { var tcs = new TaskCompletionSource(); _dispatcher.Post( () => { tcs.SetResult(action()); }, DispatcherPriority.Render); return tcs.Task; } } ================================================ FILE: src/MvvmDialogs.Avalonia/DialogService.cs ================================================ namespace HanumanInstitute.MvvmDialogs.Avalonia; /// /// Class abstracting the interaction between view models and views when it comes to /// opening dialogs using the MVVM pattern in WPF. /// public class DialogService : DialogServiceBase { /// /// Initializes a new instance of the class. /// /// /// By default, is used as dialog type locator /// and is used as framework dialog factory. /// public DialogService() : this(null) { } /// /// Initializes a new instance of the class. /// /// Class responsible for UI interactions. /// Function used to create view model instances. This function is used only by and is not used internally. public DialogService( IDialogManager? dialogManager = null, Func? viewModelFactory = null) : base(dialogManager ?? new DialogManager(dialogFactory: new DialogFactory()), viewModelFactory) { } } ================================================ FILE: src/MvvmDialogs.Avalonia/FileSystem/AvaloniaDialogStorageFile.cs ================================================ using System.IO; using Avalonia.Platform.Storage; using HanumanInstitute.MvvmDialogs.FileSystem; namespace HanumanInstitute.MvvmDialogs.Avalonia; /// public class AvaloniaDialogStorageFile : AvaloniaDialogStorageItem, IDialogStorageFile { private readonly IStorageFile _item; /// /// Returns the Avalonia object source that was passed to the constructor. /// public IStorageFile Source => _item; /// /// Initializes a new instance of DialogStorageFile as a bridge to specified Avalonia IStorageFile. /// /// An Avalonia IStorageFile from which to get the values. public AvaloniaDialogStorageFile(IStorageFile item) : base(item) { _item = item; } /// public Task OpenReadAsync() => _item.OpenReadAsync(); /// public Task OpenWriteAsync() => _item.OpenWriteAsync(); } ================================================ FILE: src/MvvmDialogs.Avalonia/FileSystem/AvaloniaDialogStorageFolder.cs ================================================ using System.Collections.Generic; using System.Linq; using Avalonia.Platform.Storage; using HanumanInstitute.MvvmDialogs.FileSystem; namespace HanumanInstitute.MvvmDialogs.Avalonia; /// public class AvaloniaDialogStorageFolder : AvaloniaDialogStorageItem, IDialogStorageFolder { private readonly IStorageFolder _item; /// /// Returns the Avalonia object source that was passed to the constructor. /// public IStorageFolder Source => _item; /// /// Initializes a new instance of DialogStorageFolder as a bridge to specified Avalonia IStorageFolder. /// /// An Avalonia IStorageFolder from which to get the values. public AvaloniaDialogStorageFolder(IStorageFolder item) : base(item) { _item = item; } /// public IAsyncEnumerable GetItemsAsync() { var list = _item.GetItemsAsync(); return list.Select(x => x is IStorageFile f ? (IDialogStorageItem)new AvaloniaDialogStorageFile(f) : new AvaloniaDialogStorageFolder((IStorageFolder)x)); } /// public async Task CreateFileAsync(string name) { var result = await _item.CreateFileAsync(name); return result?.ToDialog(); } /// public async Task CreateFolderAsync(string name) { var result = await _item.CreateFolderAsync(name); return result?.ToDialog(); } } ================================================ FILE: src/MvvmDialogs.Avalonia/FileSystem/AvaloniaDialogStorageItem.cs ================================================ using System.IO; using Avalonia.Platform.Storage; using HanumanInstitute.MvvmDialogs.FileSystem; namespace HanumanInstitute.MvvmDialogs.Avalonia; /// public abstract class AvaloniaDialogStorageItem : IDialogStorageItem { private readonly IStorageItem _item; /// /// Initializes a new instance of DialogStorageItem as a bridge to specified Avalonia IStorageItem. /// /// An Avalonia IStorageItem from which to get the values. protected AvaloniaDialogStorageItem(IStorageItem item) { _item = item; } /// public string Name => _item.Name; /// public Uri Path => _item.Path; /// public string LocalPath => _item.Path.LocalPath; /// public async Task GetBasicPropertiesAsync() { var result = await _item.GetBasicPropertiesAsync().ConfigureAwait(true); return new DesktopDialogStorageItemProperties(result.Size, result.DateCreated, result.DateModified); } /// public bool CanBookmark => _item.CanBookmark; /// public Task SaveBookmarkAsync() => _item.SaveBookmarkAsync(); /// public async Task GetParentAsync() { var result = await _item.GetParentAsync().ConfigureAwait(true); return result != null ? new AvaloniaDialogStorageFolder(result) : null; } /// public Task DeleteAsync() => _item.DeleteAsync(); /// public async Task MoveAsync(IDialogStorageFolder destination) { var dest = await destination.ToAvaloniaAsync(); if (dest == null) { throw new FileNotFoundException($"Cannot open path '${destination.Path}'"); } return await _item.MoveAsync(dest) switch { IStorageFile file => file.ToDialog(), IStorageFolder folder => folder.ToDialog(), _ => null }; } /// public void Dispose() => _item.Dispose(); } ================================================ FILE: src/MvvmDialogs.Avalonia/FileSystem/StorageExtensions.cs ================================================ using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Platform.Storage; using HanumanInstitute.MvvmDialogs.FileSystem; namespace HanumanInstitute.MvvmDialogs.Avalonia; /// /// Provides extension methods to convert between Avalonia and MvvmDialog storage file/folder types. /// public static class StorageExtensions { /// /// Converts an Avalonia into a MvvmDialogs . /// /// The Avalonia storage object to convert. /// A MvvmDialogs storage object. public static IDialogStorageFile ToDialog(this IStorageFile item) => new AvaloniaDialogStorageFile(item); /// /// Converts an Avalonia into a MvvmDialogs . /// /// The Avalonia storage object to convert. /// A MvvmDialogs storage object. public static IDialogStorageFolder ToDialog(this IStorageFolder item) => new AvaloniaDialogStorageFolder(item); // internal static IStorageFile Convert(this IDialogStorageFile item) => new DialogStorageFileToAvalonia(item); internal static async Task ToAvaloniaAsync(this IDialogStorageFolder item) { if (item is AvaloniaDialogStorageFolder av) { return av.Source; } var storage = GetStorageProvider(); if (storage != null) { return await storage.TryGetFolderFromPathAsync(item.Path); } return null; } private static IStorageProvider? GetStorageProvider() { var result = Application.Current?.ApplicationLifetime switch { IClassicDesktopStyleApplicationLifetime d => d.MainWindow, ISingleViewApplicationLifetime s => s.MainView as TopLevel, _ => null }; return result?.StorageProvider; } } ================================================ FILE: src/MvvmDialogs.Avalonia/IViewLocatorNavigation.cs ================================================ namespace HanumanInstitute.MvvmDialogs.Avalonia; /// /// When implemented alongside IViewLocator, allows to force single page navigation even on desktop. /// public interface IViewLocatorNavigation { /// /// Gets or sets whether to force single-page navigation. Setting this to true can allow running in single-page mode on desktop. /// bool ForceSinglePageNavigation { get; set; } /// /// Gets whether the application runs in single-page navigation mode. /// bool UseSinglePageNavigation { get; } } ================================================ FILE: src/MvvmDialogs.Avalonia/MvvmDialogs.Avalonia.csproj ================================================ net10.0;net8.0 Library MVVM Dialogs for Avalonia ..\..\StrongName.snk HanumanInstitute.MvvmDialogs.Avalonia HanumanInstitute.MvvmDialogs.Avalonia HanumanInstitute.MvvmDialogs.Avalonia True True icon_64x64.png True \ StrongName.snk NavigationRootWindow.axaml Code NavigationRoot.axaml Code ================================================ FILE: src/MvvmDialogs.Avalonia/MvvmDialogs.Avalonia.csproj.DotSettings ================================================  True ================================================ FILE: src/MvvmDialogs.Avalonia/Navigation/CancellableActions.cs ================================================ using System.Collections.Generic; using System.Linq; namespace HanumanInstitute.MvvmDialogs.Avalonia.Navigation; /// /// Provides a list of cancellable dialog actions such as messageboxes or popups. Useful for mobile back navigation. /// This class is static (application-wide) because it would be difficult to connect the context between NavigationManager and the MessageBox API. /// public static class CancellableActions { private static readonly List s_list = new(); /// /// Adds a cancellable dialog action to the list. /// /// An action to cancel the dialog. public static void Add(Action action) { lock (s_list) { s_list.Add(action); } } /// /// Removes a cancellable action from the list. You must call this when the dialog is completed. /// /// The same action that was previously added. public static void Remove(Action action) { lock (s_list) { s_list.Remove(action); } } /// /// Returns whether there are active dialog actions. /// public static bool Any { get { lock (s_list) { return s_list.Any(); } } } /// /// Returns how many dialog actions are active. /// public static int Count { get { lock (s_list) { return s_list.Count; } } } /// /// Cancels the last dialog operation in the list. /// /// True if a dialog operation was cancelled; otherwise false. public static bool CancelLast() { lock (s_list) { if (s_list.Any()) { s_list.Last().Invoke(); s_list.RemoveAt(s_list.Count - 1); return true; } } return false; } } ================================================ FILE: src/MvvmDialogs.Avalonia/Navigation/DialogTask.cs ================================================ namespace HanumanInstitute.MvvmDialogs.Avalonia.Navigation; /// /// Represents a dialog shown with single-page navigation that is awaiting result. /// internal class DialogTask { /// /// Initializes a new instance of the DialogTask. /// /// The view model of the new dialog. /// A view model that represents the owner window of the dialog. public DialogTask(INotifyPropertyChanged viewModel, INotifyPropertyChanged ownerViewModel) { ViewModel = viewModel; OwnerViewModel = ownerViewModel; } /// /// Gets the view model of the new dialog. /// public INotifyPropertyChanged ViewModel { get; } /// /// Gets the view model that represents the owner of the dialog. /// public INotifyPropertyChanged? OwnerViewModel { get; } /// /// Gets a that will notify when the dialog is closed. /// public TaskCompletionSource Completion { get; } = new(); } ================================================ FILE: src/MvvmDialogs.Avalonia/Navigation/INavigationManager.cs ================================================ using System.Collections.Generic; namespace HanumanInstitute.MvvmDialogs.Avalonia.Navigation; /// /// Manages navigation for single-view applications. /// public interface INavigationManager { /// /// Returns the navigation history. /// public IReadOnlyList History { get; } /// /// Initializes a new instance of the NavigationManager class. /// /// If specified, a custom user control will be set as the main view instead of the default NavigationRoot. void Launch(Control? customNavigationRoot = null); /// /// Gets or sets the view to display in the NavigationRoot control. NavigationRoot contains a binding to this property. /// UserControl? CurrentView { get; set; } /// /// Gets the view model of the current view. /// INotifyPropertyChanged? CurrentViewModel { get; } /// /// Returns a View for specified ViewModel type. It will only work if such a View has been created before. /// /// The ViewModel to display in the View. /// The View instance, or null. UserControl? GetViewForViewModel(INotifyPropertyChanged viewModel); /// /// Shows specified view. /// /// The ViewModel to display in the View. /// The view definition including its type and how to create one. void Show(INotifyPropertyChanged viewModel, ViewDefinition viewDef); /// /// Shows specified view and waits for a response. /// /// The ViewModel to display in the View. /// The view definition including its type and how to create one. /// A view model that represents the owner window of the dialog. /// The dialog result. Task ShowDialogAsync(INotifyPropertyChanged viewModel, ViewDefinition viewDef, INotifyPropertyChanged ownerViewModel); /// /// Closes specified view and shows the previous one. /// /// The ViewModel to display in the View. void Close(INotifyPropertyChanged viewModel); /// /// Activates specified view, pumping it in front of the navigation history. /// /// The ViewModel to display in the View. /// Whether a matching view from history has been activated. bool Activate(INotifyPropertyChanged viewModel); } ================================================ FILE: src/MvvmDialogs.Avalonia/Navigation/NavigationManager.cs ================================================ using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Interactivity; namespace HanumanInstitute.MvvmDialogs.Avalonia.Navigation; /// /// /// Initializes a new instance of the NavigationManager class. /// /// A handler for the Closing event. Note that the Closing event is unsupported by the and we thus support a single listener. public class NavigationManager(ViewClosingHandler? closingHandler) : INotifyPropertyChanged, INavigationManager { /// /// Navigation history contains only ViewModels to avoid keeping all constructed user controls in memory. The Views can be reconstructed from the ViewModels. /// private readonly List _history = new(); private readonly ViewCache _viewCache = new(); private readonly List _dialogs = new(); private readonly ViewClosingHandler? _closingHandler = closingHandler; /// /// Returns the navigation history. /// public IReadOnlyList History => _history; /// /// Initializes a new instance of the NavigationManager class. /// /// If specified, a custom user control will be set as the main view instead of the default NavigationRoot. public void Launch(Control? customNavigationRoot = null) { // Initialize the NavigationRoot as the main application view. var app = Application.Current?.ApplicationLifetime; if (app is ISingleViewApplicationLifetime appSingle) { appSingle.MainView = customNavigationRoot ?? new NavigationRoot(); appSingle.MainView.DataContext = this; appSingle.MainView.Loaded += (_, _) => { TopLevel.GetTopLevel(appSingle.MainView)!.BackRequested += TopLevel_BackRequested; }; } else if (app is IClassicDesktopStyleApplicationLifetime appDesktop) { appDesktop.MainWindow = customNavigationRoot as Window ?? new NavigationRootWindow(); appDesktop.MainWindow.DataContext = this; } } /// /// Handle the mobile back button. /// private void TopLevel_BackRequested(object? sender, RoutedEventArgs e) { if (CancellableActions.Any) { // Cancel message boxes CancellableActions.CancelLast(); e.Handled = true; } else if (CurrentView != null && _history.Count > 1) { // Cancel normal views var current = CurrentViewModel!; var view = CurrentView.AsWrapper(this, _closingHandler); view.Close(); e.Handled = !ReferenceEquals(CurrentViewModel, current) || !view.ClosingConfirmed; } } /// public UserControl? CurrentView { get => _currentView; set => SetField(ref _currentView, value); } private UserControl? _currentView; /// public INotifyPropertyChanged? CurrentViewModel => (INotifyPropertyChanged?)CurrentView?.DataContext; /// public UserControl? GetViewForViewModel(INotifyPropertyChanged viewModel) => _viewCache.GetViewForViewModel(viewModel); /// public void Show(INotifyPropertyChanged viewModel, ViewDefinition viewDef) { CurrentView = _viewCache.GetView(viewModel, viewDef); _history.Remove(viewModel); if (_dialogs.Any()) { // Keep only 1 non-dialog history within a dialog. var last = _history.Last(); if (!_dialogs.Any(x => object.ReferenceEquals(x.ViewModel, last))) { _history.Remove(last); } } _history.Add(viewModel); } /// public Task ShowDialogAsync(INotifyPropertyChanged viewModel, ViewDefinition viewDef, INotifyPropertyChanged ownerViewModel) { var view = _viewCache.GetView(viewModel, viewDef); CurrentView = view; if (_dialogs.Any(x => object.ReferenceEquals(x.ViewModel, viewModel))) { throw new InvalidOperationException("Dialog is already shown."); } var dialog = new DialogTask(viewModel, ownerViewModel); _dialogs.Add(dialog); _history.Add(viewModel); return dialog.Completion.Task; } /// public void Close(INotifyPropertyChanged viewModel) { // Remove from history, whether or not it is currently visible. _history.Remove(viewModel); // If waiting for dialog result, stop waiting. var dialog = _dialogs.FirstOrDefault(x => object.ReferenceEquals(x.ViewModel, viewModel)); if (dialog != null) { dialog.Completion.SetResult(true); _dialogs.Remove(dialog); } // If visible, show previous one, or dialog owner. Ignore owner for non-dialogs. if (object.ReferenceEquals(CurrentView?.DataContext, viewModel)) { var prev = dialog?.OwnerViewModel ?? _history.LastOrDefault(); if (prev != null) { var prevView = _viewCache.GetViewForViewModel(prev); // Remove all history after owner. if (dialog?.OwnerViewModel != null) { var pos = _history.IndexOf(dialog.OwnerViewModel); if (pos > -1 && _history.Count > pos + 1) { _history.RemoveRange(pos + 1, _history.Count - pos - 1); } } CurrentView = prevView; } } } /// public bool Activate(INotifyPropertyChanged viewModel) { if (_history.Contains(viewModel)) { _history.Remove(viewModel); _history.Add(viewModel); var view = _viewCache.GetViewForViewModel(viewModel); CurrentView = view; return true; } return false; } // // public Control? GetMainView() => // (Application.Current?.ApplicationLifetime as ISingleViewApplicationLifetime)?.MainView; // public event PropertyChangedEventHandler? PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } protected bool SetField(ref T field, T value, [CallerMemberName] string? propertyName = null) { if (EqualityComparer.Default.Equals(field, value)) return false; field = value; OnPropertyChanged(propertyName); return true; } } ================================================ FILE: src/MvvmDialogs.Avalonia/Navigation/NavigationRoot.axaml ================================================ ================================================ FILE: src/MvvmDialogs.Avalonia/Navigation/NavigationRoot.axaml.cs ================================================ using Avalonia.Markup.Xaml; namespace HanumanInstitute.MvvmDialogs.Avalonia.Navigation; /// /// The default application main view for single-view applications. /// public partial class NavigationRoot : UserControl { /// /// Initializes a new instance of the NavigationRoot control. /// public NavigationRoot() => InitializeComponent(); private void InitializeComponent() => AvaloniaXamlLoader.Load(this); } ================================================ FILE: src/MvvmDialogs.Avalonia/Navigation/NavigationRootWindow.axaml ================================================ ================================================ FILE: src/MvvmDialogs.Avalonia/Navigation/NavigationRootWindow.axaml.cs ================================================ using Avalonia.Markup.Xaml; namespace HanumanInstitute.MvvmDialogs.Avalonia.Navigation; /// /// The default application main window for single-view applications on desktop. /// public partial class NavigationRootWindow : Window { /// /// Initializes a new instance of the NavigationRootWindow control. /// public NavigationRootWindow() { InitializeComponent(); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } } ================================================ FILE: src/MvvmDialogs.Avalonia/Navigation/ViewCache.cs ================================================ using System.Collections.Generic; using System.Linq; namespace HanumanInstitute.MvvmDialogs.Avalonia.Navigation; /// /// Cache of View instances with weak references. /// public class ViewCache { private readonly IList _cache = new List(); /// /// Returns a View for specified ViewModel type. It will only work if such a View has been created before. /// /// The ViewModel associated with the View. /// The View instance, or null. public UserControl? GetViewForViewModel(INotifyPropertyChanged viewModel) { var item = _cache.FirstOrDefault(x => x.ViewModelType == viewModel.GetType()); if (item != null) { if (item.View.TryGetTarget(out var result)) { result.DataContext = viewModel; return result; } else { var newView = (UserControl)item.ViewDef.Create(); item.View = new WeakReference(newView); newView.DataContext = viewModel; return newView; } } return null; } /// /// Returns an instance of specified viewType. A single instance will be returned per type, and it will be cached with a weak reference. /// /// The view model associated with the view. /// The view definition including its type and how to create one. /// The View instance. public UserControl GetView(INotifyPropertyChanged viewModel, ViewDefinition viewDef) { var item = _cache.FirstOrDefault(x => x.ViewModelType == viewModel.GetType()); if (item is null) { item = new ViewCacheItem(viewModel.GetType(), viewDef, (UserControl)viewDef.Create()); _cache.Add(item); } item.ViewDef = viewDef; if (item.View.TryGetTarget(out var result)) { result.DataContext = viewModel; return result; } var newView = (UserControl)viewDef.Create(); item.View = new WeakReference(newView); newView.DataContext = viewModel; return newView; } } ================================================ FILE: src/MvvmDialogs.Avalonia/Navigation/ViewCacheItem.cs ================================================ namespace HanumanInstitute.MvvmDialogs.Avalonia.Navigation; /// /// Represents an item in the /// internal class ViewCacheItem { public ViewCacheItem(Type viewModelType, ViewDefinition viewDef, UserControl view) { ViewModelType = viewModelType; ViewDef = viewDef; View = new WeakReference(view); } /// /// The data type of the ViewModel. /// public Type ViewModelType { get; } /// /// An action to create a view of desired type. /// public ViewDefinition ViewDef { get; set; } /// /// A weak reference to a View instance. /// public WeakReference View { get; set; } } ================================================ FILE: src/MvvmDialogs.Avalonia/Navigation/ViewNavigationWrapper.cs ================================================ #pragma warning disable CS1591 #pragma warning disable CS8618 namespace HanumanInstitute.MvvmDialogs.Avalonia.Navigation; /// /// Class wrapping an instance of Avalonia within . /// /// public class ViewNavigationWrapper : IView { private readonly INavigationManager _navigation; private readonly ViewClosingHandler? _closingHandler; /// /// Initializes a new instance of the ViewNavigationWrapper class. /// /// The to set. /// A handler for the Closing event. Note that the Closing event is unsupported in this class and we thus support a single listener. public ViewNavigationWrapper(INavigationManager navigationManager, ViewClosingHandler? closingHandler) { _navigation = navigationManager; _closingHandler = closingHandler; } /// public void Initialize(INotifyPropertyChanged viewModel, ViewDefinition viewDef) { ViewModel = viewModel; ViewDef = viewDef; } /// public void InitializeExisting(INotifyPropertyChanged viewModel, object view) { ViewModel = viewModel; ViewDef = new ViewDefinition(view.GetType(), () => (UserControl)view); Ref = (UserControl)view; } private ViewDefinition ViewDef { get; set; } public IView? Owner { get; set; } /// /// Gets the UserControl reference held by this class. /// public UserControl? Ref { get; private set; } /// public object RefObj => Ref!; /// /// Unused event. /// public event EventHandler? Loaded; /// /// Unused event. /// public event EventHandler? Closing; /// /// Unused event. /// public event EventHandler? Closed; /// public INotifyPropertyChanged ViewModel { get; private set; } private void RaiseLoaded() { if (ViewModel is IViewLoaded vm) { vm.OnLoaded(); } } private void RaiseClosed() { if (ViewModel is IViewClosed vm) { vm.OnClosed(); } } /// public async Task ShowDialogAsync(IView owner) { var task = _navigation.ShowDialogAsync(ViewModel, ViewDef, owner.ViewModel); Ref = _navigation.CurrentView!; RaiseLoaded(); await task.ConfigureAwait(true); } /// public void Show(IView? owner) { _navigation.Show(ViewModel, ViewDef); Ref = _navigation.CurrentView!; RaiseLoaded(); } /// public void Activate() { if (!ReferenceEquals(_navigation.CurrentView?.DataContext, ViewModel)) { if (_navigation.Activate(ViewModel)) { Ref = _navigation.CurrentView!; RaiseLoaded(); } } } /// public void Close() { var args = new CancelEventArgs(); if (!ClosingConfirmed) { _closingHandler?.Invoke(this, args); } if (!args.Cancel && ClosingConfirmed) { _isClosed = true; _navigation.Close(ViewModel); RaiseClosed(); } } /// public bool IsEnabled { get => Ref?.IsEnabled ?? true; set { if (Ref != null) { Ref.IsEnabled = value; } } } /// public bool IsVisible => Ref != null && ReferenceEquals(Ref, _navigation.CurrentView); /// public bool ClosingConfirmed { get; set; } private bool _isClosed; } ================================================ FILE: src/MvvmDialogs.Avalonia/Private/NullableAttributes.cs ================================================ #pragma warning disable MA0048 // File name must match type name #define INTERNAL_NULLABLE_ATTRIBUTES // https://github.com/dotnet/corefx/blob/48363ac826ccf66fbe31a5dcb1dc2aab9a7dd768/src/Common/src/CoreLib/System/Diagnostics/CodeAnalysis/NullableAttributes.cs // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. // ReSharper disable once CheckNamespace namespace System.Diagnostics.CodeAnalysis; #if NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NET45 || NET451 || NET452 || NET6 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48 /// Specifies that null is allowed as an input even if the corresponding type disallows it. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class AllowNullAttribute : Attribute { } /// Specifies that null is disallowed as an input even if the corresponding type allows it. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class DisallowNullAttribute : Attribute { } /// Specifies that an output may be null even if the corresponding type disallows it. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class MaybeNullAttribute : Attribute { } /// Specifies that an output will not be null even if the corresponding type allows it. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class NotNullAttribute : Attribute { } /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class MaybeNullWhenAttribute : Attribute { /// Initializes the attribute with the specified return value condition. /// /// The return value condition. If the method returns this value, the associated parameter may be null. /// public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; /// Gets the return value condition. public bool ReturnValue { get; } } /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class NotNullWhenAttribute : Attribute { /// Initializes the attribute with the specified return value condition. /// /// The return value condition. If the method returns this value, the associated parameter will not be null. /// public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; /// Gets the return value condition. public bool ReturnValue { get; } } /// Specifies that the output will be non-null if the named parameter is non-null. [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class NotNullIfNotNullAttribute : Attribute { /// Initializes the attribute with the associated parameter name. /// /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. /// public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName; /// Gets the associated parameter name. public string ParameterName { get; } } /// Applied to a method that will never return under any circumstance. [AttributeUsage(AttributeTargets.Method, Inherited = false)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class DoesNotReturnAttribute : Attribute { } /// Specifies that the method will not return if the associated Boolean parameter is passed the specified value. [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class DoesNotReturnIfAttribute : Attribute { /// Initializes the attribute with the specified parameter value. /// /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to /// the associated parameter matches this value. /// public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue; /// Gets the condition parameter value. public bool ParameterValue { get; } } #endif // NETSTANDARD2_0 attributes #if NETSTANDARD2_1 || NETSTANDARD2_0 || NETCOREAPP2_0 || NETCOREAPP2_1 || NETCOREAPP2_2 || NETCOREAPP3_1 || NET45 || NET451 || NET452 || NET6 || NET461 || NET462 || NET47 || NET471 || NET472 || NET48 /// /// Specifies that the method or property will ensure that the listed field and property members have /// not- values. /// [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class MemberNotNullAttribute : Attribute { /// Gets field or property member names. public string[] Members { get; } /// Initializes the attribute with a field or property member. /// The field or property member that is promised to be not-null. public MemberNotNullAttribute(string member) { Members = new[] { member }; } /// Initializes the attribute with the list of field and property members. /// The list of field and property members that are promised to be not-null. public MemberNotNullAttribute(params string[] members) { Members = members; } } /// /// Specifies that the method or property will ensure that the listed field and property members have /// non- values when returning with the specified return value condition. /// [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] #if INTERNAL_NULLABLE_ATTRIBUTES internal #else public #endif sealed class MemberNotNullWhenAttribute : Attribute { /// Gets the return value condition. public bool ReturnValue { get; } /// Gets field or property member names. public string[] Members { get; } /// Initializes the attribute with the specified return value condition and a field or property member. /// /// The return value condition. If the method returns this value, /// the associated parameter will not be . /// /// The field or property member that is promised to be not-. public MemberNotNullWhenAttribute(bool returnValue, string member) { ReturnValue = returnValue; Members = new[] { member }; } /// Initializes the attribute with the specified return value condition and list of field and property members. /// /// /// The return value condition. If the method returns this value, /// the associated parameter will not be . /// /// The list of field and property members that are promised to be not-null. public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { ReturnValue = returnValue; Members = members; } } #endif // NETSTANDARD2_1 attributes ================================================ FILE: src/MvvmDialogs.Avalonia/StrongViewLocator.cs ================================================ using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.Templates; namespace HanumanInstitute.MvvmDialogs.Avalonia; /// /// Strongly-typed View Locator that does not rely on reflection. /// public abstract class StrongViewLocator : StrongViewLocatorBase, IDataTemplate, IViewLocatorNavigation { /// /// Registers specified views as being associated with specified view model type. /// /// The type of view model to register. /// The view type to associate with the view model. public void Register() where TViewModel : INotifyPropertyChanged where TView : Control, new() => Register(new ViewDefinition(typeof(TView), () => new TView())); /// /// Registers specified views as being associated with specified view model type. /// DesktopWindow or NavigationView will be selected based on runtime needs. /// /// The type of view model to register. /// The UserControl view associated with the view model for navigation mode. /// The Window view associated with the view model for desktop applications. public void Register() where TViewModel : INotifyPropertyChanged where TNavView : UserControl, new() where TDeskView : Window, new() => Register(UseSinglePageNavigation ? new ViewDefinition(typeof(TNavView), () => new TNavView()) : new ViewDefinition(typeof(TDeskView), () => new TDeskView())); /// /// Gets or sets whether to force single-page navigation. Setting this to true can allow running in single-page mode on desktop. /// public bool ForceSinglePageNavigation { get => _forceSinglePageNavigation; set { if (Registrations.Count > 0) { throw new InvalidOperationException("ForceSinglePageNavigation must be set before registering views."); } _forceSinglePageNavigation = value; } } private bool _forceSinglePageNavigation; /// public virtual Control Build(object? data) { try { return (Control)Create(data!); } catch (Exception) { return new TextBlock { Text = $"No view registered for {data?.GetType().FullName}" }; } } /// public virtual bool Match(object? data) => data is INotifyPropertyChanged; /// /// Gets whether the application runs in single-page navigation mode. /// public bool UseSinglePageNavigation => Application.Current?.ApplicationLifetime is ISingleViewApplicationLifetime || ForceSinglePageNavigation; } ================================================ FILE: src/MvvmDialogs.Avalonia/UiExtensions.cs ================================================ // using System.Diagnostics.CodeAnalysis; // using Avalonia.LogicalTree; using System.Diagnostics.CodeAnalysis; using Avalonia.Threading; using HanumanInstitute.MvvmDialogs.Avalonia.Navigation; namespace HanumanInstitute.MvvmDialogs.Avalonia; /// /// Extension methods. /// public static class UiExtensions { // /// // /// Gets the owner of a wrapped in a . // /// // /// // /// The to find the for. // /// // /// The owning if found; otherwise null. // internal static ViewWrapper? GetOwner(this StyledElement frameworkElement) // { // var owner = frameworkElement as Window ?? frameworkElement.FindLogicalAncestorOfType(); // return owner.AsWrapper(); // } /// /// Creates a ViewWrapper around specified window. /// /// The Window to get a wrapper for. /// A ViewWrapper referencing the window. [return: NotNullIfNotNull("window")] public static ViewWrapper? AsWrapper(this Window? window) { if (window != null) { var result = new ViewWrapper(); result.InitializeExisting((INotifyPropertyChanged)window.DataContext!, window); return result; } return null; } /// /// Creates a ViewNavigationWrapper around specified user control. /// /// The UserControl to get a wrapper for. /// The to set. /// A handler for the Closing event. Not that the Closing event is unsupported in this class and we thus support a single listener. /// A ViewNavigationWrapper referencing the user control. [return: NotNullIfNotNull("view")] public static ViewNavigationWrapper? AsWrapper(this UserControl? view, INavigationManager navigationManager, ViewClosingHandler? closingHandler) { if (view != null) { var result = new ViewNavigationWrapper(navigationManager, closingHandler); result.InitializeExisting((INotifyPropertyChanged)view.DataContext!, view); return result; } return null; } /// /// Returns the RefObj property as an Avalonia ContentControl. /// /// The IView to get the Ref property for. /// The ContentControl held within the IView. public static ContentControl? GetRef(this IView? view) { if (view is ViewWrapper v) { return v.Ref; } else if (view is ViewNavigationWrapper nav) { return nav.Ref; } return null; } // /// // /// Converts an IView into a ViewWrapper. // /// // /// The IWindow to convert. // /// A ViewWrapper referencing the window. // [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("window")] // public static ViewWrapper? AsWrapper(this IView? window) => // (ViewWrapper?)window; /// /// Runs a synchronous action asynchronously on the UI thread. /// /// The action to run asynchronously. /// The return type of the action. /// The result of the action. public static Task RunUiAsync(Func action) { TaskCompletionSource completion = new(); Dispatcher.UIThread.Post(new Action(() => completion.SetResult(action()))); return completion.Task; } } ================================================ FILE: src/MvvmDialogs.Avalonia/Usings.cs ================================================ global using System; global using System.ComponentModel; global using System.Threading.Tasks; global using Avalonia; global using Avalonia.Controls; ================================================ FILE: src/MvvmDialogs.Avalonia/ViewClosingHandler.cs ================================================ using HanumanInstitute.MvvmDialogs.Avalonia.Navigation; namespace HanumanInstitute.MvvmDialogs.Avalonia; /// /// A handler for the Closing event. Note that the Closing event is unsupported by the and we thus support a single listener. /// public delegate void ViewClosingHandler(IView dialog, CancelEventArgs e); ================================================ FILE: src/MvvmDialogs.Avalonia/ViewLocatorBase.cs ================================================ using System.Reflection; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.Templates; namespace HanumanInstitute.MvvmDialogs.Avalonia; /// /// Base implementation of Avalonia ViewLocator. Override GetViewName to customize paths. /// public class ViewLocatorBase : IDataTemplate, IViewLocator, IViewLocatorNavigation { /// public bool ForceSinglePageNavigation { get; set; } /// /// Returns the view type name for specified view model type. By default, it replaces 'ViewModel' with 'View'. /// /// The view model to get the view type for. /// The view type name. protected virtual string GetViewName(object viewModel) { const string ViewModel = "ViewModel"; var result = viewModel.GetType().FullName!.Replace(".ViewModels.", ".Views."); if (result.EndsWith(ViewModel)) { result = result.Remove(result.Length - ViewModel.Length) + (UseSinglePageNavigation ? "View" : "Window"); } return result; } /// public virtual Control Build(object? data) { try { return (Control)Create(data!); } catch (Exception) { return new TextBlock { Text = "Not Found: " + GetViewName(data!) }; } } /// public virtual ViewDefinition Locate(object viewModel) { var name = GetViewName(viewModel); // var type = Type.GetType(name, x => Assembly.GetEntryAssembly(), null, false); var viewType = Assembly.GetAssembly(viewModel.GetType())?.GetType(name); if (viewType is null || (!typeof(Control).IsAssignableFrom(viewType) && !typeof(Window).IsAssignableFrom(viewType) && !typeof(IView).IsAssignableFrom(viewType))) { var message = $"Dialog view of type {name} for view model {viewModel.GetType().FullName} is missing."; const string ErrorInfo = "Avalonia project template includes ViewLocator in the project base. " + "You can customize it to map your view models to your views."; throw new TypeLoadException(message + Environment.NewLine + ErrorInfo); } return new ViewDefinition(viewType, () => CreateViewInstance(viewType)); } /// /// The method used to create the view instance from it's . /// Uses by default. /// /// The type to create a view for. /// The created view. protected virtual object CreateViewInstance(Type viewType) => Activator.CreateInstance(viewType)!; /// public virtual object Create(object viewModel) => Locate(viewModel).Create(); /// public virtual bool Match(object? data) => data is INotifyPropertyChanged; /// public bool UseSinglePageNavigation => Application.Current?.ApplicationLifetime is ISingleViewApplicationLifetime || ForceSinglePageNavigation; } ================================================ FILE: src/MvvmDialogs.Avalonia/ViewWrapper.cs ================================================ // ReSharper disable VirtualMemberCallInConstructor using System.Collections.Generic; using Avalonia.Controls.ApplicationLifetimes; namespace HanumanInstitute.MvvmDialogs.Avalonia; /// /// Class wrapping an instance of Avalonia within . /// /// public class ViewWrapper : IView { /// /// Initializes a new instance of the class. /// public void Initialize(INotifyPropertyChanged viewModel, ViewDefinition viewDef) { Ref = (Window)viewDef.Create(); ViewModel = viewModel; } /// /// Initializes a new instance of the class. /// public void InitializeExisting(INotifyPropertyChanged viewModel, object view) { Ref = (Window)view; ViewModel = viewModel; } /// /// Gets the Window reference held by this class. /// public Window Ref { get; private set; } = null!; /// /// Gets the Window reference held by this class. /// public object RefObj => Ref; /// /// Fired when the window is loaded. /// public event EventHandler? Loaded { add => Ref.Opened += value; remove => Ref.Opened -= value; } /// /// Fired when the window is closing. /// public event EventHandler? Closing { add { if (value != null) { var handler = new EventHandler(value.Invoke); _closingHandlers.Add(value, handler); Ref.Closing += handler; } } remove { if (value != null) { Ref.Closing += _closingHandlers[value]; _closingHandlers.Remove(value); } } } private readonly Dictionary, EventHandler> _closingHandlers = new(); /// /// Fired when the window is closed. /// public event EventHandler? Closed { add => Ref.Closed += value; remove => Ref.Closed -= value; } /// public INotifyPropertyChanged ViewModel { get => (INotifyPropertyChanged)Ref.DataContext!; set => Ref.DataContext = value; } /// public Task ShowDialogAsync(IView owner) { var window = (Window)owner.RefObj; SetMainWindowIfEmpty(window); return Ref.ShowDialog(window); } /// public void Show(IView? owner) { var own = owner?.RefObj as Window; SetMainWindowIfEmpty(Ref); if (own != null) { Ref.Show(own); } else { Ref.Show(); } } /// public void Activate() => Ref.Activate(); /// public void Close() => Ref.Close(); /// public bool IsEnabled { get => Ref.IsEnabled; set => Ref.IsEnabled = value; } /// public bool IsVisible => Ref.IsVisible; /// public bool ClosingConfirmed { get; set; } private void SetMainWindowIfEmpty(Window? window) { if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime { MainWindow: null } desktop) { desktop.MainWindow = window; } } } ================================================ FILE: src/MvvmDialogs.Avalonia.DialogHost/DialogFactoryExtensions.cs ================================================  // ReSharper disable CheckNamespace using HanumanInstitute.MvvmDialogs.Avalonia.DialogHost; namespace HanumanInstitute.MvvmDialogs.Avalonia; /// /// Provides extensions to IDialogFactory. /// public static class DialogFactoryExtensions { /// /// Registers DialogHost handlers in the dialog factory chain. /// /// The dialog factory to add handlers for. /// A new dialog factory that will fallback to the previous one. public static IDialogFactory AddDialogHost(this IDialogFactory factory) => new DialogHostDialogFactory(factory); } ================================================ FILE: src/MvvmDialogs.Avalonia.DialogHost/DialogHostDialogFactory.cs ================================================ namespace HanumanInstitute.MvvmDialogs.Avalonia.DialogHost; /// /// Default framework dialog factory that will create instances of standard framework dialogs. /// public class DialogHostDialogFactory : DialogFactoryBase { /// /// Initializes a new instance of a FrameworkDialog. /// /// If the dialog is not handled by this class, calls this other handler next. public DialogHostDialogFactory(IDialogFactory? chain = null) : base(chain) { } /// public override async Task ShowDialogAsync(IView? owner, TSettings settings) => settings switch { // MessageBoxSettings s => await ShowMessageBoxDialogAsync(owner, s, appSettings).ConfigureAwait(true), DialogHostSettings s => await ShowDialogHostAsync(owner, s), _ => await base.ShowDialogAsync(owner, settings).ConfigureAwait(true) }; private async Task ShowDialogHostAsync(IView? owner, DialogHostSettings settings) { if (owner == null) { throw new ArgumentNullException(nameof(owner)); } var view = new DialogHostView(settings); if (view.ViewModel != null) { GetDialogManager().HandleDialogEvents(view.ViewModel, view); } await view.ShowDialogAsync(owner).ConfigureAwait(true); return view.DialogResult; } // private Task ShowMessageBoxAsync(IView? owner, MessageBoxSettings settings, AppDialogSettingsBase appSettings) // { // return Task.FromResult(null); // } } ================================================ FILE: src/MvvmDialogs.Avalonia.DialogHost/DialogHostSettings.cs ================================================ using Avalonia.Media; using DialogHostAvalonia; using DialogHostAvalonia.Positioners; namespace HanumanInstitute.MvvmDialogs.Avalonia.DialogHost; /// /// Settings for showing DialogHost overlays. /// public class DialogHostSettings : DialogSettingsBase { /// /// Initializes a new instance of the DialogHostSettings class. /// public DialogHostSettings() { } /// /// Initializes a new instance of the DialogHostSettings class. /// /// The view model of the view to show. The view will be resolved through Avalonia's ViewLocator. public DialogHostSettings(object? content) { Content = content; } /// /// The view model of the view to show, or any content or user control. The view will be resolved through Avalonia's ViewLocator. /// public object? Content { get; set; } /// /// A handler that will be called when the view is closing, allowing to cancel the close. /// public DialogClosingEventHandler? ClosingHandler { get; set; } /// /// Whether to close the view when clicking elsewhere in the parent container. /// public bool CloseOnClickAway { get; set; } /// /// The close value to set when closing by clicking away. /// public object? CloseOnClickAwayParameter { get; set; } /// /// A class allowing to customize the positioning of the dialog. /// public IDialogPopupPositioner? PopupPositioner { get; set; } /// /// The background of the overlay. /// public IBrush? OverlayBackground { get; set; } /// /// The margin of the dialog view. /// public Thickness? DialogMargin { get; set; } /// /// Whether to disable the popup animation. /// public bool DisableOpeningAnimation { get; set; } = true; } ================================================ FILE: src/MvvmDialogs.Avalonia.DialogHost/DialogHostView.cs ================================================ using System.ComponentModel; using Avalonia.VisualTree; using HanumanInstitute.MvvmDialogs.Avalonia.Navigation; namespace HanumanInstitute.MvvmDialogs.Avalonia.DialogHost; /// /// An implementation for DialogHost. /// public class DialogHostView : IView { private static readonly object s_lockCreateHost = new(); /// /// Initializes a new instance of the DialogHostView. /// /// The DialogHost display settings. public DialogHostView(DialogHostSettings settings) { Settings = settings; } /// /// Gets or sets the display settings. /// public DialogHostSettings Settings { get; set; } /// /// Gets or sets the dialog result. /// public object? DialogResult { get; set; } /// public void Initialize(INotifyPropertyChanged viewModel, ViewDefinition viewDef) { } /// public void InitializeExisting(INotifyPropertyChanged viewModel, object view) { } /// public INotifyPropertyChanged? ViewModel => Settings.Content as INotifyPropertyChanged; /// public object RefObj => null!; /// public event EventHandler? Loaded; /// public event EventHandler? Closing; /// public event EventHandler? Closed; /// public void Show(IView? owner) => throw new NotImplementedException(); /// /// Returns a DialogHost instance to manage the dialog. /// private DialogHostAvalonia.DialogHost InitHost(ContentControl owner) { DialogHostAvalonia.DialogHost? host; lock (s_lockCreateHost) // lock to avoid creating host twice { host = owner.FindDescendantOfType(); if (host == null) { host = new DialogHostAvalonia.DialogHost(); var temp = owner.Content; owner.Content = null; host.Content = temp; owner.Content = host; } } Host = host; return host; } /// /// Returns the DialogHost that was last initiated. /// private DialogHostAvalonia.DialogHost? Host { get; set; } /// public async Task ShowDialogAsync(IView owner) { var host = InitHost(owner.GetRef()!); host.CloseOnClickAway = Settings.CloseOnClickAway; host.CloseOnClickAwayParameter = Settings.CloseOnClickAwayParameter; host.PopupPositioner = Settings.PopupPositioner; host.OverlayBackground = Settings.OverlayBackground ?? host.OverlayBackground; host.DialogMargin = Settings.DialogMargin ?? host.DialogMargin; host.DisableOpeningAnimation = Settings.DisableOpeningAnimation; var closingHandler = Settings.ClosingHandler ?? ((_, e) => { var param = new CancelEventArgs(); Closing?.Invoke(this, param); if (param.Cancel) { e.Cancel(); } }); try { host.DialogOpened += Host_DialogOpened; void Cancel() => Close(); CancellableActions.Add(Cancel); DialogResult = await DialogHostAvalonia.DialogHost.Show(Settings.Content!, host, closingHandler).ConfigureAwait(true); CancellableActions.Remove(Cancel); Closed?.Invoke(this, EventArgs.Empty); } finally { host.DialogOpened -= Host_DialogOpened; } } private void Host_DialogOpened(object sender, EventArgs e) { Loaded?.Invoke(this, EventArgs.Empty); } /// public void Activate() { } /// public void Close() { Host?.CloseDialogCommand.Execute(null); } /// public bool IsEnabled { get; set; } = true; /// public bool IsVisible => true; /// public bool ClosingConfirmed { get; set; } } ================================================ FILE: src/MvvmDialogs.Avalonia.DialogHost/DialogServiceExtensions.cs ================================================ using System.ComponentModel; using HanumanInstitute.MvvmDialogs.Avalonia.DialogHost; // ReSharper disable once CheckNamespace namespace HanumanInstitute.MvvmDialogs; /// /// Provides IDialogService extensions for fluent dialogs. /// public static class DialogServiceExtensions { /// /// Displays a DialogHost.Avalonia content dialog. /// /// The IDialogService on which to attach the extension method. /// A view model that represents the owner window of the dialog. /// The settings for the content dialog. /// The dialog button that was pressed. /// No view is registered with specified owner view model as data context. public static async Task ShowDialogHostAsync(this IDialogService service, INotifyPropertyChanged ownerViewModel, DialogHostSettings? settings = null) { if (ownerViewModel == null) throw new ArgumentNullException(nameof(ownerViewModel)); if (settings == null) throw new ArgumentNullException(nameof(settings)); if (settings.Content == null) throw new ArgumentNullException(nameof(settings.Content)); return await service.DialogManager.ShowFrameworkDialogAsync( ownerViewModel, settings).ConfigureAwait(true); } } ================================================ FILE: src/MvvmDialogs.Avalonia.DialogHost/MvvmDialogs.Avalonia.DialogHost.csproj ================================================  net10.0;net8.0 default enable Library MvvmDialogs with DialogHost.Avalonia MvvmDialogs with DialogHost.Avalonia ..\..\StrongName.snk HanumanInstitute.MvvmDialogs.Avalonia.DialogHost HanumanInstitute.MvvmDialogs.Avalonia.DialogHost HanumanInstitute.MvvmDialogs.Avalonia.DialogHost True True icon_64x64.png True / icon_64x64.png ================================================ FILE: src/MvvmDialogs.Avalonia.DialogHost/Usings.cs ================================================ global using System; global using System.Threading.Tasks; global using Avalonia; global using Avalonia.Controls; ================================================ FILE: src/MvvmDialogs.Avalonia.Fluent/ContentDialogSettings.cs ================================================  namespace HanumanInstitute.MvvmDialogs.Avalonia.Fluent; /// /// Represents the content dialog settings. /// public class ContentDialogSettings : DialogSettingsBase { /// /// Initializes a new instance of the ContentDialogSettings class. /// public ContentDialogSettings() { } /// /// Initializes a new instance of the ContentDialogSettings class with specified content. /// /// The content of the dialog. Can be a ViewModel, Control, or any content. public ContentDialogSettings(object? content) { Content = content; } /// /// Gets or sets the content of the dialog. /// public object? Content { get; set; } /// /// Gets or sets the text to display on the close button. /// public string CloseButtonText { get; set; } = string.Empty; /// /// Gets or sets the text to display on the primary button. /// public string PrimaryButtonText { get; set; } = string.Empty; /// /// Gets or sets the text to be displayed on the secondary button. /// public string SecondaryButtonText { get; set; } = string.Empty; /// /// Gets or sets a value that indicates which button on the dialog is the default action. /// public FAContentDialogButton DefaultButton { get; set; } = FAContentDialogButton.None; /// /// Gets or sets whether the dialog's primary button is enabled. /// public bool IsPrimaryButtonEnabled { get; set; } = true; /// /// Gets or sets whether the dialog's secondary button is enabled. /// public bool IsSecondaryButtonEnabled { get; set; } = true; /// /// Gets or sets whether the Dialog should show full screen /// On WinUI3, at least desktop, this just show the dialog at /// the maximum size of a ContentDialog. /// public bool FullSizeDesired { get; set; } } ================================================ FILE: src/MvvmDialogs.Avalonia.Fluent/DialogFactoryExtensions.cs ================================================ using HanumanInstitute.MvvmDialogs.Avalonia.Fluent; // ReSharper disable CheckNamespace namespace HanumanInstitute.MvvmDialogs.Avalonia; /// /// Provides extensions to IDialogFactory. /// public static class DialogFactoryExtensions { /// /// Registers Fluent handlers in the dialog factory chain. /// /// The dialog factory to add handlers for. /// Specifies how MessageBox dialogs will be handled. /// A new dialog factory that will fallback to the previous one. public static IDialogFactory AddFluent(this IDialogFactory factory, FluentMessageBoxType messageBoxType = FluentMessageBoxType.TaskDialog) => new FluentDialogFactory(messageBoxType, factory); } ================================================ FILE: src/MvvmDialogs.Avalonia.Fluent/DialogServiceExtensions.cs ================================================ using System.ComponentModel; using HanumanInstitute.MvvmDialogs.Avalonia.Fluent; // ReSharper disable once CheckNamespace namespace HanumanInstitute.MvvmDialogs; /// /// Provides IDialogService extensions for fluent dialogs. /// public static class DialogServiceExtensions { /// /// Displays a FluentAvalonia content dialog. /// /// The IDialogService on which to attach the extension method. /// A view model that represents the owner window of the dialog. /// The settings for the content dialog. /// The dialog button that was pressed. /// No view is registered with specified owner view model as data context. public static async Task ShowContentDialogAsync(this IDialogService service, INotifyPropertyChanged ownerViewModel, ContentDialogSettings? settings = null) { ArgumentNullException.ThrowIfNull(ownerViewModel); return (FAContentDialogResult)(await service.DialogManager.ShowFrameworkDialogAsync( ownerViewModel, settings ?? new ContentDialogSettings()).ConfigureAwait(true) ?? FAContentDialogResult.None); } /// /// Displays the FolderBrowserDialog. /// /// The IDialogService on which to attach the extension method. /// A view model that represents the owner window of the dialog. /// The settings for the task dialog. /// The dialog return value. /// No view is registered with specified owner view model as data context. public static async Task ShowTaskDialogAsync(this IDialogService service, INotifyPropertyChanged ownerViewModel, TaskDialogSettings? settings = null) { ArgumentNullException.ThrowIfNull(ownerViewModel); return (FATaskDialogStandardResult)(await service.DialogManager.ShowFrameworkDialogAsync( ownerViewModel, settings ?? new TaskDialogSettings()).ConfigureAwait(true) ?? FATaskDialogStandardResult.None); } } ================================================ FILE: src/MvvmDialogs.Avalonia.Fluent/FluentApi.cs ================================================ // using HanumanInstitute.MvvmDialogs.Avalonia.Navigation; // // namespace HanumanInstitute.MvvmDialogs.Avalonia.Fluent; // // internal class FluentApi : IFluentApi // { // public async Task ShowContentDialog(ContentControl? owner, ContentDialogSettings settings) // { // var dialog = new ContentDialog() // { // Title = settings.Title, // Content = settings.Content, // CloseButtonText = settings.CloseButtonText, // PrimaryButtonText = settings.PrimaryButtonText, // SecondaryButtonText = settings.SecondaryButtonText, // DefaultButton = settings.DefaultButton, // IsPrimaryButtonEnabled = settings.IsPrimaryButtonEnabled, // IsSecondaryButtonEnabled = settings.IsSecondaryButtonEnabled, // FullSizeDesired = settings.FullSizeDesired // }; // // // Allow the dialog to be closed by mobile back navigation. // void Cancel() => dialog.Hide(); // CancellableActions.Add(Cancel); // var result = await dialog.ShowAsync().ConfigureAwait(true); // CancellableActions.Remove(Cancel); // return result; // } // // public async Task ShowTaskDialog(ContentControl? owner, TaskDialogSettings settings) // { // var dialog = new TaskDialog() // { // Title = settings.Title, // Header = settings.Header, // SubHeader = settings.SubHeader, // Content = settings.Content, // IconSource = settings.IconSource, // FooterVisibility = settings.FooterVisibility, // IsFooterExpanded = settings.IsFooterExpanded, // Footer = settings.Footer, // ShowProgressBar = settings.ShowProgressBar // }; // foreach (var button in settings.Buttons) // { // dialog.Buttons.Add(button); // } // if (owner != null) // { // dialog.XamlRoot = TopLevel.GetTopLevel(owner); // } // // // Allow the dialog to be closed by mobile back navigation. // void Cancel() => dialog.Hide(); // CancellableActions.Add(Cancel); // var result = await dialog.ShowAsync().ConfigureAwait(true); // CancellableActions.Remove(Cancel); // return result; // } // } ================================================ FILE: src/MvvmDialogs.Avalonia.Fluent/FluentContentView.cs ================================================ using System.ComponentModel; using HanumanInstitute.MvvmDialogs.Avalonia.Navigation; namespace HanumanInstitute.MvvmDialogs.Avalonia.Fluent; /// /// An implementation for FluentContentDialog. /// public class FluentContentView : IView { /// /// Initializes a new instance of the FluentContentView. /// /// The ContentDialog display settings. public FluentContentView(ContentDialogSettings settings) { Settings = settings; } /// /// Gets or sets the display settings. /// public ContentDialogSettings Settings { get; set; } /// /// Gets or sets the dialog result. /// public FAContentDialogResult DialogResult { get; set; } = FAContentDialogResult.None; /// public void Initialize(INotifyPropertyChanged viewModel, ViewDefinition viewDef) { } /// public void InitializeExisting(INotifyPropertyChanged viewModel, object view) { } /// public INotifyPropertyChanged? ViewModel => Settings.Content as INotifyPropertyChanged; /// /// Gets a reference to the displayed ContentDialog. /// public FAContentDialog? Ref { get; private set; } /// public object RefObj => Ref!; /// public event EventHandler? Loaded; /// public event EventHandler? Closing; /// public event EventHandler? Closed; /// public void Show(IView? owner) => throw new NotImplementedException(); /// public async Task ShowDialogAsync(IView owner) { var dialog = new FAContentDialog() { Title = Settings.Title, Content = Settings.Content, CloseButtonText = Settings.CloseButtonText, PrimaryButtonText = Settings.PrimaryButtonText, SecondaryButtonText = Settings.SecondaryButtonText, DefaultButton = Settings.DefaultButton, IsPrimaryButtonEnabled = Settings.IsPrimaryButtonEnabled, IsSecondaryButtonEnabled = Settings.IsSecondaryButtonEnabled, FullSizeDesired = Settings.FullSizeDesired }; Ref = dialog; dialog.Loaded += (s, e) => Loaded?.Invoke(s, e); dialog.Closing += (s, e) => { var args = new CancelEventArgs(); Closing?.Invoke(s, args); if (args.Cancel) { e.Cancel = true; } }; dialog.Closed += (s, e) => Closed?.Invoke(s, e); // Allow the dialog to be closed by mobile back navigation. void Cancel() => dialog.Hide(); CancellableActions.Add(Cancel); DialogResult = await dialog.ShowAsync().ConfigureAwait(true); CancellableActions.Remove(Cancel); Ref = null; } /// public void Activate() { } /// public void Close() { Ref?.Hide(); } /// public bool IsEnabled { get; set; } = true; /// public bool IsVisible => Ref != null; /// public bool ClosingConfirmed { get; set; } } ================================================ FILE: src/MvvmDialogs.Avalonia.Fluent/FluentDialogFactory.cs ================================================ using HanumanInstitute.MvvmDialogs.FrameworkDialogs; // ReSharper disable MemberCanBePrivate.Global // ReSharper disable CheckNamespace namespace HanumanInstitute.MvvmDialogs.Avalonia.Fluent; /// /// Default framework dialog factory that will create instances of standard Windows dialogs. /// public class FluentDialogFactory : DialogFactoryBase { private readonly FluentMessageBoxType _messageBoxType; /// /// Initializes a new instance of a FrameworkDialog. /// /// Specifies how MessageBox dialogs will be handled. /// If the dialog is not handled by this class, calls this other handler next. public FluentDialogFactory(FluentMessageBoxType messageBoxType = FluentMessageBoxType.TaskDialog, IDialogFactory? chain = null) : base(chain) { _messageBoxType = messageBoxType; } /// public override async Task ShowDialogAsync(IView? owner, TSettings settings) => settings switch { ContentDialogSettings s => await ShowContentDialogAsync(owner, s).ConfigureAwait(true), TaskDialogSettings s => await ShowTaskDialogAsync(owner, s).ConfigureAwait(true), MessageBoxSettings s when _messageBoxType == FluentMessageBoxType.ContentDialog => await ShowMessageBoxContentDialogAsync(owner, s) .ConfigureAwait(true), MessageBoxSettings s when _messageBoxType == FluentMessageBoxType.TaskDialog => await ShowMessageBoxTaskDialogAsync(owner, s).ConfigureAwait(true), _ => await base.ShowDialogAsync(owner, settings).ConfigureAwait(true) }; private async Task ShowContentDialogAsync(IView? owner, ContentDialogSettings settings) { ArgumentNullException.ThrowIfNull(owner); var view = new FluentContentView(settings); if (view.ViewModel != null) { GetDialogManager().HandleDialogEvents(view.ViewModel, view); } await view.ShowDialogAsync(owner).ConfigureAwait(true); return view.DialogResult; } private async Task ShowTaskDialogAsync(IView? owner, TaskDialogSettings settings) { ArgumentNullException.ThrowIfNull(owner); var view = new FluentTaskView(settings); if (view.ViewModel != null) { GetDialogManager().HandleDialogEvents(view.ViewModel, view); } await view.ShowDialogAsync(owner).ConfigureAwait(true); return view.DialogResult; } private async Task ShowMessageBoxContentDialogAsync(IView? owner, MessageBoxSettings settings) { var apiSettings = new ContentDialogSettings() { Title = settings.Title, Content = settings.Content, DefaultButton = FAContentDialogButton.Primary }; var yes = FAContentDialogResult.Primary; var no = FAContentDialogResult.Secondary; if (settings.Button == MessageBoxButton.Ok) { apiSettings.CloseButtonText = "OK"; apiSettings.DefaultButton = FAContentDialogButton.Close; yes = FAContentDialogResult.None; } else if (settings.Button == MessageBoxButton.OkCancel) { apiSettings.PrimaryButtonText = "OK"; apiSettings.CloseButtonText = "Cancel"; } else if (settings.Button == MessageBoxButton.YesNo) { apiSettings.PrimaryButtonText = "Yes"; apiSettings.SecondaryButtonText = "No"; } else if (settings.Button == MessageBoxButton.YesNoCancel) { apiSettings.PrimaryButtonText = "Yes"; apiSettings.SecondaryButtonText = "No"; apiSettings.CloseButtonText = "Cancel"; } var result = await ShowContentDialogAsync(owner, apiSettings).ConfigureAwait(true); return result == yes ? true : result == no ? false : null; } private async Task ShowMessageBoxTaskDialogAsync(IView? owner, MessageBoxSettings settings) { var apiSettings = new TaskDialogSettings() { Title = settings.Title, Content = settings.Content, Buttons = SyncButton(settings.Button, settings.DefaultValue), // Icon = SyncIcon(settings.Icon) }; var result = await ShowTaskDialogAsync(owner, apiSettings).ConfigureAwait(true); return result as bool?; // It can be TaskDialogStandardResult.None if we press Escape } private static FATaskDialogButton[] SyncButton(MessageBoxButton value, bool? defaultValue) => (value) switch { MessageBoxButton.YesNo => [ GetButton("Yes", true, defaultValue), GetButton("No", false, defaultValue) ], MessageBoxButton.OkCancel => [ GetButton("OK", true, defaultValue), GetButton("Cancel", null, defaultValue) ], MessageBoxButton.YesNoCancel => [ GetButton("Yes", true, defaultValue), GetButton("No", false, defaultValue), GetButton("Cancel", null, defaultValue) ], _ => [ GetButton("OK", true, true) ] }; private static FATaskDialogButton GetButton(string text, bool? value, bool? defaultValue) => new(text, value) { IsDefault = defaultValue == value }; } ================================================ FILE: src/MvvmDialogs.Avalonia.Fluent/FluentMessageBoxType.cs ================================================ // ReSharper disable CheckNamespace namespace HanumanInstitute.MvvmDialogs.Avalonia; /// /// Represents how to display message boxes. /// public enum FluentMessageBoxType { /// /// MessageBox dialogs will not be handled by FluentAvalonia. /// None, /// /// MessageBox dialogs will be shown in content dialogs. /// ContentDialog, /// /// MessageBox dialogs will be shown in task dialogs. /// TaskDialog } ================================================ FILE: src/MvvmDialogs.Avalonia.Fluent/FluentTaskView.cs ================================================ using System.ComponentModel; using HanumanInstitute.MvvmDialogs.Avalonia.Navigation; namespace HanumanInstitute.MvvmDialogs.Avalonia.Fluent; /// /// An implementation for FluentContentDialog. /// /// The TaskDialog display settings. public class FluentTaskView(TaskDialogSettings settings) : IView { /// /// Gets or sets the display settings. /// public TaskDialogSettings Settings { get; set; } = settings; /// /// Gets or sets the dialog result. /// public object? DialogResult { get; set; } /// public void Initialize(INotifyPropertyChanged viewModel, ViewDefinition viewDef) { } /// public void InitializeExisting(INotifyPropertyChanged viewModel, object view) { } /// public INotifyPropertyChanged? ViewModel => Settings.Content as INotifyPropertyChanged; /// /// Gets a reference to the displayed TaskDialog. /// public FATaskDialog? Ref { get; private set; } /// public object RefObj => Ref!; /// public event EventHandler? Loaded; /// public event EventHandler? Closing; /// public event EventHandler? Closed; /// public void Show(IView? owner) => throw new NotImplementedException(); /// public async Task ShowDialogAsync(IView owner) { var dialog = new FATaskDialog() { Title = Settings.Title, Header = Settings.Header, SubHeader = Settings.SubHeader, Content = Settings.Content, IconSource = Settings.IconSource, FooterVisibility = Settings.FooterVisibility, IsFooterExpanded = Settings.IsFooterExpanded, Footer = Settings.Footer, ShowProgressBar = Settings.ShowProgressBar }; Ref = dialog; foreach (var button in Settings.Buttons) { dialog.Buttons.Add(button); } if (owner.GetRef() != null) { dialog.XamlRoot = TopLevel.GetTopLevel(owner.GetRef()); } dialog.Loaded += (s, e) => Loaded?.Invoke(s, e); dialog.Closing += (s, e) => { var args = new CancelEventArgs(); Closing?.Invoke(s, args); if (args.Cancel) { e.Cancel = true; } }; dialog.Closed += (s, e) => Closed?.Invoke(s, e); // Allow the dialog to be closed by mobile back navigation. void Cancel() => dialog.Hide(); CancellableActions.Add(Cancel); DialogResult = await dialog.ShowAsync().ConfigureAwait(true); CancellableActions.Remove(Cancel); Ref = null; } /// public void Activate() { } /// public void Close() { Ref?.Hide(); } /// public bool IsEnabled { get; set; } = true; /// public bool IsVisible => Ref != null; /// public bool ClosingConfirmed { get; set; } } ================================================ FILE: src/MvvmDialogs.Avalonia.Fluent/MvvmDialogs.Avalonia.Fluent.csproj ================================================  net10.0 default enable Library MvvmDialogs with FluentAvalonia MvvmDialogs with FluentAvalonia ..\StrongName.snk HanumanInstitute.MvvmDialogs.Avalonia.Fluent HanumanInstitute.MvvmDialogs.Avalonia.Fluent HanumanInstitute.MvvmDialogs.Avalonia.Fluent True True icon_64x64.png True / icon_64x64.png ================================================ FILE: src/MvvmDialogs.Avalonia.Fluent/TaskDialogSettings.cs ================================================  using System.Collections.Generic; namespace HanumanInstitute.MvvmDialogs.Avalonia.Fluent; /// /// Represents the task dialog settings. /// public class TaskDialogSettings : DialogSettingsBase { /// /// Initializes a new instance of the TaskDialogSettings class. /// public TaskDialogSettings() { } /// /// Initializes a new instance of the TaskDialogSettings class with specified content. /// /// The content of the dialog. Can be a ViewModel, Control, or any content. public TaskDialogSettings(object? content) { Content = content; } /// /// Gets or sets the dialog header text /// public string Header { get; set; } = string.Empty; /// /// Gets or sets the dialog sub header text /// public string SubHeader { get; set; } = string.Empty; /// /// Gets or sets the content of the dialog. /// public object? Content { get; set; } /// /// Gets or sets the dialog Icon /// public FAIconSource? IconSource { get; set; } /// /// Gets the list of buttons that display at the bottom of the TaskDialog /// public IList Buttons { get; set; } = []; /// /// Gets the list of Commands displayed in the TaskDialog /// public IList Commands { get; set; } = []; /// /// Gets or sets the visibility of the Footer area /// public FATaskDialogFooterVisibility FooterVisibility { get; set; } /// /// Gets or sets whether the footer is visible /// public bool IsFooterExpanded { get; set; } /// /// Gets or sets the footer content /// public object? Footer { get; set; } /// /// Gets or sets whether this TaskDialog shows a progress bar /// public bool ShowProgressBar { get; set; } } ================================================ FILE: src/MvvmDialogs.Avalonia.Fluent/Usings.cs ================================================ global using System; global using System.Threading.Tasks; global using Avalonia; global using Avalonia.Controls; global using FluentAvalonia; global using FluentAvalonia.UI.Controls; ================================================ FILE: src/MvvmDialogs.Avalonia.MessageBox/DialogFactoryExtensions.cs ================================================ using Avalonia.Controls.ApplicationLifetimes; using HanumanInstitute.MvvmDialogs.Avalonia.MessageBox; // ReSharper disable CheckNamespace namespace HanumanInstitute.MvvmDialogs.Avalonia; /// /// Provides extensions to IDialogFactory. /// public static class DialogFactoryExtensions { /// /// Registers MessageBox handlers in the dialog factory chain. /// /// The dialog factory to add handlers for. /// The message box type to show. /// A new dialog factory that will fallback to the previous one. public static IDialogFactory AddMessageBox(this IDialogFactory factory, MessageBoxMode mode = MessageBoxMode.Window) { if (Application.Current?.ApplicationLifetime is ISingleViewApplicationLifetime && mode == MessageBoxMode.Window) { throw new NotSupportedException("Avalonia.MessageBox with mode=Window is only supported in Desktop applications. Consider using mode=Popup or a different MessageBox implementation."); } return new MessageBoxDialogFactory(factory) { Mode = mode }; } } ================================================ FILE: src/MvvmDialogs.Avalonia.MessageBox/IMessageBoxApi.cs ================================================ namespace HanumanInstitute.MvvmDialogs.Avalonia.MessageBox; internal interface IMessageBoxApi { Task ShowMessageBoxAsync(Window? owner, MessageBoxApiSettings settings, MessageBoxMode mode); } ================================================ FILE: src/MvvmDialogs.Avalonia.MessageBox/MessageBoxApi.cs ================================================ using MsBox.Avalonia.Dto; namespace HanumanInstitute.MvvmDialogs.Avalonia.MessageBox; internal class MessageBoxApi : IMessageBoxApi { public Task ShowMessageBoxAsync(Window? owner, MessageBoxApiSettings settings, MessageBoxMode mode) { var msgBox = MessageBoxManager.GetMessageBoxStandard( new MessageBoxStandardParams() { ContentTitle = settings.Title, ContentMessage = settings.Text, ButtonDefinitions = settings.Buttons, Icon = settings.Icon, WindowStartupLocation = settings.StartupLocation, EnterDefaultButton = settings.EnterDefaultButton, EscDefaultButton = settings.EscDefaultButton }); return mode == MessageBoxMode.Popup ? msgBox.ShowAsPopupAsync(owner) : msgBox.ShowWindowDialogAsync(owner); } } ================================================ FILE: src/MvvmDialogs.Avalonia.MessageBox/MessageBoxApiSettings.cs ================================================  namespace HanumanInstitute.MvvmDialogs.Avalonia.MessageBox; internal class MessageBoxApiSettings { public string Title { get; set; } = string.Empty; public string Text { get; set; } = string.Empty; public ButtonEnum Buttons { get; set; } = ButtonEnum.Ok; public Icon Icon { get; set; } = Icon.None; public WindowStartupLocation StartupLocation { get; set; } = WindowStartupLocation.CenterScreen; public ClickEnum EnterDefaultButton { get; set; } = ClickEnum.Default; public ClickEnum EscDefaultButton { get; set; } = ClickEnum.Default; } ================================================ FILE: src/MvvmDialogs.Avalonia.MessageBox/MessageBoxDialogFactory.cs ================================================ using HanumanInstitute.MvvmDialogs.FrameworkDialogs; // ReSharper disable CheckNamespace namespace HanumanInstitute.MvvmDialogs.Avalonia.MessageBox; /// /// Default framework dialog factory that will create instances of standard Windows dialogs. /// public class MessageBoxDialogFactory : DialogFactoryBase { private readonly IMessageBoxApi _api; /// /// Gets or sets the message box type to show. /// public MessageBoxMode Mode { get; set; } /// /// Initializes a new instance of a FrameworkDialog. /// /// If the dialog is not handled by this class, calls this other handler next. public MessageBoxDialogFactory(IDialogFactory? chain = null) : this(chain, null) { } /// /// Initializes a new instance of a FrameworkDialog. /// /// If the dialog is not handled by this class, calls this other handler next. /// An interface exposing Avalonia messagebox dialogs API. internal MessageBoxDialogFactory(IDialogFactory? chain, IMessageBoxApi? api) : base(chain) { _api = api ?? new MessageBoxApi(); } /// public override async Task ShowDialogAsync(IView? owner, TSettings settings) => settings switch { MessageBoxSettings s => await ShowMessageBoxDialogAsync(owner, s).ConfigureAwait(true), _ => await base.ShowDialogAsync(owner, settings).ConfigureAwait(true) }; private async Task ShowMessageBoxDialogAsync(IView? owner, MessageBoxSettings settings) { var apiSettings = new MessageBoxApiSettings() { Title = settings.Title, Text = settings.Content, Buttons = SyncButton(settings.Button), Icon = SyncIcon(settings.Icon), EnterDefaultButton = SyncDefaultEnter(settings.Button, settings.DefaultValue), EscDefaultButton = SyncDefaultEsc(settings.Button) }; var ownerRef = owner.GetRef(); if (ownerRef is Window ownerWin) { var result = await _api.ShowMessageBoxAsync(ownerWin, apiSettings, Mode); return result switch { ButtonResult.Yes => true, ButtonResult.Ok => true, ButtonResult.No => false, ButtonResult.Cancel => null, _ => null }; } else { throw new InvalidCastException("Owner must be of type Window."); } } // Convert platform-agnostic types into Win32 types. private static ButtonEnum SyncButton(MessageBoxButton value) => (value) switch { MessageBoxButton.Ok => ButtonEnum.Ok, MessageBoxButton.YesNo => ButtonEnum.YesNo, MessageBoxButton.OkCancel => ButtonEnum.OkCancel, MessageBoxButton.YesNoCancel => ButtonEnum.YesNoCancel, _ => ButtonEnum.Ok }; private static Icon SyncIcon(MessageBoxImage value) => (value) switch { MessageBoxImage.None => Icon.None, MessageBoxImage.Error => Icon.Error, MessageBoxImage.Exclamation => Icon.Warning, MessageBoxImage.Information => Icon.Info, MessageBoxImage.Stop => Icon.Stop, MessageBoxImage.Warning => Icon.Warning, _ => Icon.None }; private static ClickEnum SyncDefaultEnter(MessageBoxButton buttons, bool? value) => buttons switch { MessageBoxButton.Ok => ClickEnum.Ok, MessageBoxButton.OkCancel => value == true ? ClickEnum.Ok : ClickEnum.Cancel, MessageBoxButton.YesNo => value == true ? ClickEnum.Yes : ClickEnum.No, MessageBoxButton.YesNoCancel => value switch { true => ClickEnum.Yes, false => ClickEnum.No, null => ClickEnum.Cancel }, _ => ClickEnum.Default }; private static ClickEnum SyncDefaultEsc(MessageBoxButton buttons) => buttons switch { MessageBoxButton.Ok => ClickEnum.Ok, MessageBoxButton.OkCancel => ClickEnum.Cancel, MessageBoxButton.YesNo => ClickEnum.No, MessageBoxButton.YesNoCancel => ClickEnum.Cancel, _ => ClickEnum.Default }; } ================================================ FILE: src/MvvmDialogs.Avalonia.MessageBox/MessageBoxMode.cs ================================================ namespace HanumanInstitute.MvvmDialogs.Avalonia.MessageBox; /// /// Represents the type of message box to display. /// public enum MessageBoxMode { /// /// Show message boxes as modal windows. /// Window, /// /// Show message boxes as popups. /// Popup } ================================================ FILE: src/MvvmDialogs.Avalonia.MessageBox/MvvmDialogs.Avalonia.MessageBox.csproj ================================================  net10.0;net8.0 default enable Library MvvmDialogs with MessageBox.Avalonia MvvmDialogs with MessageBox.Avalonia ..\..\StrongName.snk HanumanInstitute.MvvmDialogs.Avalonia.MessageBox HanumanInstitute.MvvmDialogs.Avalonia.MessageBox HanumanInstitute.MvvmDialogs.Avalonia.MessageBox True True icon_64x64.png 2.1.0.24361 2.1.0.24361 True / icon_64x64.png ================================================ FILE: src/MvvmDialogs.Avalonia.MessageBox/Usings.cs ================================================ global using System; global using System.Threading.Tasks; global using Avalonia; global using Avalonia.Controls; global using MsBox.Avalonia; global using MsBox.Avalonia.Enums; ================================================ FILE: src/MvvmDialogs.Avalonia.Tests/MvvmDialogs.Avalonia.Tests.csproj ================================================  net10.0;net8.0 Exe enable disable false HanumanInstitute.MvvmDialogs.Avalonia.Tests default runtime; build; native; contentfiles; analyzers; buildtransitive all runtime; build; native; contentfiles; analyzers; buildtransitive all SecondView.axaml Code SecondWindow.axaml Code ThirdView.axaml Code ThirdWindow.axaml Code ================================================ FILE: src/MvvmDialogs.Avalonia.Tests/NavigationTests.cs ================================================ // ReSharper disable MemberCanBePrivate.Global using HanumanInstitute.MvvmDialogs.Avalonia.Navigation; namespace HanumanInstitute.MvvmDialogs.Avalonia.Tests; public class NavigationTests { public IDialogService DialogService => _dialogService ??= new DialogService(DialogManager); private IDialogService _dialogService; public DialogManager DialogManager => _dialogManager ??= new DialogManager(new ViewLocatorBase() { ForceSinglePageNavigation = true }); private DialogManager _dialogManager; public INavigationManager NavigationManager => DialogManager.NavigationManager!; [Fact] public void Constructor_CurrentViewNull() { var _ = DialogService; Assert.Null(NavigationManager.CurrentView); } [Fact] public void Show_First_CurrentViewSet() { var vm = new FirstViewModel(); DialogService.Show(null, vm); Assert.NotNull(NavigationManager.CurrentView); Assert.Equal(vm, NavigationManager.CurrentView.DataContext); } [Fact] public void Show_Second_CurrentViewSet() { var vm1 = new FirstViewModel(); var vm2 = new SecondViewModel(); DialogService.Show(null, vm1); DialogService.Show(null, vm2); Assert.NotNull(NavigationManager.CurrentView); Assert.Equal(vm2, NavigationManager.CurrentView.DataContext); } [Fact] public void Show_FirstSecond_HistoryContainsFirstSecond() { var vm1 = new FirstViewModel(); var vm2 = new SecondViewModel(); DialogService.Show(null, vm1); DialogService.Show(null, vm2); Assert.Equal(2, NavigationManager.History.Count); Assert.Same(vm1, NavigationManager.History[0]); Assert.Same(vm2, NavigationManager.History[1]); } [Fact] public void Show_FirstSecondFirst_HistoryContainsSecondFirst() { var vm1 = new FirstViewModel(); var vm2 = new SecondViewModel(); DialogService.Show(null, vm1); DialogService.Show(null, vm2); DialogService.Show(null, vm1); Assert.Equal(2, NavigationManager.History.Count); Assert.Same(vm2, NavigationManager.History[0]); Assert.Same(vm1, NavigationManager.History[1]); } [Fact] public void Show_CloseSecond_CurrentViewSet() { var vm1 = new FirstViewModel(); var vm2 = new SecondViewModel(); DialogService.Show(null, vm1); DialogService.Show(null, vm2); vm2.OnRequestClose(); Assert.NotNull(NavigationManager.CurrentView); Assert.Equal(vm1, NavigationManager.CurrentView.DataContext); } [Fact] public async Task Show_SecondAndGarbageCollect_FirstReleased() { var vm1 = new FirstViewModel(); var vm2 = new SecondViewModel(); DialogService.Show(null, vm1); var view1 = new WeakReference(NavigationManager.CurrentView); DialogService.Show(null, vm2); GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); await Task.Delay(100, TestContext.Current.CancellationToken); Assert.False(view1.IsAlive); } [Fact] public void ShowDialogAsync_SecondAndGarbageCollect_FirstReleased() { var vm1 = new FirstViewModel(); var vm2 = new SecondViewModel(); DialogService.Show(null, vm1); var view1 = new WeakReference(NavigationManager.CurrentView); var _ = DialogService.ShowDialogAsync(vm1, vm2); GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); Assert.False(view1.IsAlive); } [Fact] public void Activate_NotShown_DoNothing() { var vm1 = new FirstViewModel(); vm1.OnRequestActivate(); Assert.Null(NavigationManager.CurrentView); } [Fact] public void Activate_AlreadyActive_CurrentViewRemainsSame() { var vm1 = new FirstViewModel(); DialogService.Show(null, vm1); vm1.OnRequestActivate(); Assert.Same(vm1, NavigationManager.CurrentView?.DataContext); Assert.Single(NavigationManager.History); } [Fact] public void Activate_FirstSecondFirst_CurrentViewFirst() { var vm1 = new FirstViewModel(); var vm2 = new SecondViewModel(); DialogService.Show(null, vm1); DialogService.Show(null, vm2); vm1.OnRequestActivate(); Assert.Same(vm1, NavigationManager.CurrentView?.DataContext); Assert.Equal(2, NavigationManager.History.Count); Assert.Same(vm2, NavigationManager.History[0]); Assert.Same(vm1, NavigationManager.History[1]); } [Theory] [InlineData(true)] [InlineData(false)] [InlineData(null)] public async Task ShowDialogAsync_Second_ReturnsValue(bool? dialogResult) { var vm1 = new FirstViewModel(); var vm2 = new SecondViewModel { DialogResult = dialogResult }; DialogService.Show(null, vm1); var task = DialogService.ShowDialogAsync(vm1, vm2); vm2.OnRequestClose(); var result = await task; Assert.Equal(dialogResult, result); } [Fact] public async Task ShowDialogAsync_Second_WaitUntilClosed() { var vm1 = new FirstViewModel(); var vm2 = new SecondViewModel(); DialogService.Show(null, vm1); var task = DialogService.ShowDialogAsync(vm1, vm2); await Task.Delay(10, TestContext.Current.CancellationToken); Assert.False(task.IsCompleted); vm2.OnRequestClose(); await Task.Delay(10, TestContext.Current.CancellationToken); Assert.True(task.IsCompleted); Assert.Same(vm1, NavigationManager.CurrentView?.DataContext); } [Fact] public async Task ShowDialogAsync_RecursiveDialogs_WaitUntilClosed() { var vm1 = new FirstViewModel(); var vm2 = new SecondViewModel(); var vm3 = new ThirdViewModel(); DialogService.Show(null, vm1); var t1 = DialogService.ShowDialogAsync(vm1, vm2); var t2 = DialogService.ShowDialogAsync(vm2, vm3); await Task.Delay(10, TestContext.Current.CancellationToken); Assert.False(t1.IsCompleted); Assert.False(t2.IsCompleted); vm3.OnRequestClose(); vm2.OnRequestClose(); await Task.Delay(10, TestContext.Current.CancellationToken); Assert.True(t1.IsCompleted); Assert.True(t2.IsCompleted); Assert.Same(vm1, NavigationManager.CurrentView?.DataContext); } [Fact] public void ShowDialogAsync_Second_AddToHistory() { var vm1 = new FirstViewModel(); var vm2 = new SecondViewModel(); DialogService.Show(null, vm1); var _ = DialogService.ShowDialogAsync(vm1, vm2); Assert.Equal(2, NavigationManager.History.Count); Assert.Same(vm1, NavigationManager.History[0]); Assert.Same(vm2, NavigationManager.History[1]); } [Fact] public async Task ShowDialogAsync_OwnerFirst_ShowFirstAfterClose() { var vm1 = new FirstViewModel(); var vm2 = new SecondViewModel(); var vm3 = new ThirdViewModel(); DialogService.Show(null, vm1); DialogService.Show(null, vm2); var task = DialogService.ShowDialogAsync(vm1, vm3); vm3.OnRequestClose(); await task; Assert.Same(vm1, NavigationManager.CurrentView?.DataContext); Assert.Single(NavigationManager.History); Assert.Same(vm1, NavigationManager.History[0]); } [Fact] public void Show_TwiceWithinDialog_AddOneHistory() { // Only 1 view is stored in history under a dialog. var vm1 = new FirstViewModel(); var vm2 = new SecondViewModel(); var vm3 = new ThirdViewModel(); var vm4 = new FirstViewModel(); DialogService.Show(null, vm1); var _ = DialogService.ShowDialogAsync(vm1, vm2); DialogService.Show(null, vm3); DialogService.Show(null, vm4); Assert.Same(vm4, NavigationManager.CurrentView?.DataContext); Assert.Equal(3, NavigationManager.History.Count); Assert.Same(vm1, NavigationManager.History[0]); Assert.Same(vm2, NavigationManager.History[1]); Assert.Same(vm4, NavigationManager.History[2]); } [Fact] public void Close_Normal_ClosingClosedRaised() { var vm1 = new FirstViewModel(); var vm2 = new SecondViewModel(); DialogService.Show(null, vm1); var _ = DialogService.ShowDialogAsync(vm1, vm2); vm2.OnRequestClose(); Assert.Equal(1, vm2.ClosingRaised); Assert.Equal(0, vm2.ClosingAsyncRaised); Assert.Equal(1, vm2.ClosedRaised); } [Fact] public async Task Close_Cancelled_ClosingAsyncRaised() { var vm1 = new FirstViewModel(); var vm2 = new SecondViewModel { ClosingCancel = true }; DialogService.Show(null, vm1); var _ = DialogService.ShowDialogAsync(vm1, vm2); vm2.OnRequestClose(); await Task.Delay(1, TestContext.Current.CancellationToken); // There's Task.Yield() in View_Closing Assert.Equal(1, vm2.ClosingRaised); Assert.Equal(1, vm2.ClosingAsyncRaised); Assert.Equal(0, vm2.ClosedRaised); } [Fact] public async Task Close_CancelledAndReset_ClosedRaised() { var vm1 = new FirstViewModel(); var vm2 = new SecondViewModel { ClosingCancel = true, ClosingAsyncCancel = false }; DialogService.Show(null, vm1); var _ = DialogService.ShowDialogAsync(vm1, vm2); vm2.OnRequestClose(); await Task.Delay(1, TestContext.Current.CancellationToken); // There's Task.Yield() in View_Closing Assert.Equal(1, vm2.ClosingRaised); Assert.Equal(1, vm2.ClosingAsyncRaised); Assert.Equal(1, vm2.ClosedRaised); } [Fact] public async Task Close_3Times_RaiseClosingOnce() { var vm1 = new FirstViewModel(); var vm2 = new SecondViewModel(); vm2.ClosingCancel = true; vm2.ClosingAsyncCancel = true; DialogService.Show(null, vm1); var _ = DialogService.ShowDialogAsync(vm1, vm2); vm2.OnRequestClose(); vm2.OnRequestClose(); vm2.OnRequestClose(); await Task.Delay(1, TestContext.Current.CancellationToken); // There's Task.Yield() in View_Closing Assert.Equal(1, vm2.ClosingRaised); Assert.Equal(1, vm2.ClosingAsyncRaised); Assert.Equal(0, vm2.ClosedRaised); } } ================================================ FILE: src/MvvmDialogs.Avalonia.Tests/TestsBase.cs ================================================ using Moq; namespace HanumanInstitute.MvvmDialogs.Avalonia.Tests; /// /// Base class for test classes. /// public class TestsBase { protected ITestOutputHelper Output { get; } public TestsBase(ITestOutputHelper output) => Output = output; /// /// Allows using a lambda expression after ??= operator. /// protected T Init(Func func) => func(); /// /// Initializes an new object of specified type with parameterless constructor. /// /// A lambda expression to configure the object. /// The type of object to create. /// The newly-created object. protected T Init(Action action) where T : new() { var result = new T(); action(result); return result; } /// /// Initializes a mock of specified type. /// /// A lambda expression to configure the mock. /// The type of mock to create. /// The newly-created mock. protected Mock InitMock(Action> action) where T : class { var mock = new Mock(); action(mock); return mock; } } ================================================ FILE: src/MvvmDialogs.Avalonia.Tests/Usings.cs ================================================ global using Xunit; global using HanumanInstitute.MvvmDialogs; global using HanumanInstitute.MvvmDialogs.Avalonia; global using HanumanInstitute.MvvmDialogs.Avalonia.Tests.Views; ================================================ FILE: src/MvvmDialogs.Avalonia.Tests/ViewNavigationWrapperTests.cs ================================================ // ReSharper disable MemberCanBePrivate.Global using HanumanInstitute.MvvmDialogs.Avalonia.Navigation; namespace HanumanInstitute.MvvmDialogs.Avalonia.Tests; /// /// Provides unit tests for the class. /// public class ViewNavigationWrapperTests { public FirstViewModel ViewModel => _viewModel ??= new FirstViewModel(); private FirstViewModel _viewModel; public ViewNavigationWrapper CreateView(bool existing) { var result = new ViewNavigationWrapper(NavigationManager, DialogManager.View_Closing); if (existing) { result.InitializeExisting(ViewModel, new FirstView()); } else { result.Initialize(ViewModel, new ViewDefinition(typeof(FirstView), () => new FirstView())); } return result; } public IDialogService DialogService => _dialogService ??= new DialogService(DialogManager); private IDialogService _dialogService; public DialogManager DialogManager => _dialogManager ??= new DialogManager(new ViewLocatorBase() { ForceSinglePageNavigation = true }); private DialogManager _dialogManager; public INavigationManager NavigationManager => DialogManager.NavigationManager!; [Theory] [InlineData(false)] [InlineData(true)] public void Initialize_ViewModelSet(bool existing) { var view = CreateView(existing); Assert.Equal(ViewModel, view.ViewModel); } [Theory] [InlineData(false)] [InlineData(true)] public void Initialize_IsEnabledTrue(bool existing) { var view = CreateView(existing); Assert.True(view.IsEnabled); } [Theory] [InlineData(false)] [InlineData(true)] public void Initialize_IsVisibleFalse(bool existing) { var view = CreateView(existing); Assert.False(view.IsVisible); } [Theory] [InlineData(false)] [InlineData(true)] public void Initialize_RefDoesNotThrowError(bool existing) { var view = CreateView(existing); _ = view.Ref; _ = view.RefObj; } [Theory] [InlineData(false)] [InlineData(true)] public void Show_NoOwner_RefSetAndEnabledVisible(bool existing) { var view = CreateView(existing); view.Show(null); Assert.NotNull(view.Ref); Assert.True(view.IsEnabled); Assert.True(view.IsVisible); Assert.Equal(1, ViewModel.LoadedCount); } [Theory] [InlineData(false)] [InlineData(true)] public void ShowDialog_WithOwner_RefSetAndEnabledVisible(bool existing) { var owner = CreateView(existing); var view = CreateView(existing); owner.Show(null); ViewModel.ResetCounters(); _ = view.ShowDialogAsync(owner); Assert.NotNull(view.Ref); Assert.True(view.IsEnabled); Assert.True(view.IsVisible); Assert.Equal(1, ViewModel.LoadedCount); } [Theory] [InlineData(false)] [InlineData(true)] public void Show_Close_ClosingAndClosedRaised(bool existing) { var view = CreateView(existing); view.Show(null); view.Close(); Assert.Equal(1, ViewModel.ClosingCount); Assert.Equal(1, ViewModel.ClosedCount); } [Theory] [InlineData(false)] [InlineData(true)] public void Activate_NotFound_DoNotShow(bool existing) { var view = CreateView(existing); view.Activate(); Assert.Null(NavigationManager.CurrentView); Assert.Equal(0, ViewModel.LoadedCount); } [Theory] [InlineData(false)] [InlineData(true)] public void Activate_FromHistory_ShowAndRaiseLoaded(bool existing) { var vm1 = ViewModel; var view1 = CreateView(existing); var vm2 = new FirstViewModel(); _viewModel = vm2; var view2 = CreateView(existing); view1.Show(null); view2.Show(view1); vm1.ResetCounters(); view1.Activate(); Assert.Equal(view1.Ref, NavigationManager.CurrentView); Assert.Equal(1, vm1.LoadedCount); } [Theory] [InlineData(false)] [InlineData(true)] public void Activate_AlreadyVisible_DoNotRaiseLoaded(bool existing) { var view = CreateView(existing); view.Show(null); ViewModel.ResetCounters(); view.Activate(); Assert.Equal(view.Ref, NavigationManager.CurrentView); Assert.Equal(0, ViewModel.LoadedCount); } } ================================================ FILE: src/MvvmDialogs.Avalonia.Tests/Views/FirstView.axaml ================================================ Test UserControl ================================================ FILE: src/MvvmDialogs.Avalonia.Tests/Views/FirstView.axaml.cs ================================================ using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace HanumanInstitute.MvvmDialogs.Avalonia.Tests.Views; public partial class FirstView : UserControl { public FirstView() { InitializeComponent(); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } } ================================================ FILE: src/MvvmDialogs.Avalonia.Tests/Views/FirstViewModel.cs ================================================ using System.ComponentModel; using ReactiveUI; namespace HanumanInstitute.MvvmDialogs.Avalonia.Tests.Views; public class FirstViewModel : ReactiveObject, ICloseable, IActivable, IViewLoaded, IViewClosing, IViewClosed { public event EventHandler RequestClose; public event EventHandler RequestActivate; public void OnRequestClose() => RequestClose?.Invoke(this, EventArgs.Empty); public void OnRequestActivate() => RequestActivate?.Invoke(this, EventArgs.Empty); public int LoadedCount { get; private set; } public int ClosingCount { get; private set; } public int ClosedCount { get; private set; } public void ResetCounters() { LoadedCount = 0; ClosingCount = 0; ClosedCount = 0; } public virtual void OnLoaded() => LoadedCount++; public virtual void OnClosing(CancelEventArgs e) => ClosingCount++; public virtual Task OnClosingAsync(CancelEventArgs e) => Task.CompletedTask; public virtual void OnClosed() => ClosedCount++; } ================================================ FILE: src/MvvmDialogs.Avalonia.Tests/Views/FirstWindow.axaml ================================================ Test Window ================================================ FILE: src/MvvmDialogs.Avalonia.Tests/Views/FirstWindow.axaml.cs ================================================ using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace HanumanInstitute.MvvmDialogs.Avalonia.Tests.Views; public partial class FirstWindow : Window { public FirstWindow() { InitializeComponent(); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } } ================================================ FILE: src/MvvmDialogs.Avalonia.Tests/Views/SecondView.axaml ================================================ Test UserControl ================================================ FILE: src/MvvmDialogs.Avalonia.Tests/Views/SecondView.axaml.cs ================================================ using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace HanumanInstitute.MvvmDialogs.Avalonia.Tests.Views; public partial class SecondView : UserControl { public SecondView() { InitializeComponent(); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } } ================================================ FILE: src/MvvmDialogs.Avalonia.Tests/Views/SecondViewModel.cs ================================================ using System.ComponentModel; using ReactiveUI; namespace HanumanInstitute.MvvmDialogs.Avalonia.Tests.Views; public class SecondViewModel : ReactiveObject, ICloseable, IActivable, IModalDialogViewModel, IViewClosing, IViewClosed { public event EventHandler RequestClose; public event EventHandler RequestActivate; public void OnRequestClose() => RequestClose?.Invoke(this, EventArgs.Empty); public void OnRequestActivate() => RequestActivate?.Invoke(this, EventArgs.Empty); public bool? DialogResult { get; set; } public int ClosingRaised { get; set; } public int ClosingAsyncRaised { get; set; } public int ClosedRaised { get; set; } public bool ClosingCancel { get; set; } public bool ClosingAsyncCancel { get; set; } = true; public void OnClosing(CancelEventArgs e) { e.Cancel = ClosingCancel; ClosingRaised++; } public Task OnClosingAsync(CancelEventArgs e) { e.Cancel = ClosingAsyncCancel; ClosingAsyncRaised++; return Task.CompletedTask; } public void OnClosed() => ClosedRaised++; } ================================================ FILE: src/MvvmDialogs.Avalonia.Tests/Views/SecondWindow.axaml ================================================ Test Window ================================================ FILE: src/MvvmDialogs.Avalonia.Tests/Views/SecondWindow.axaml.cs ================================================ using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace HanumanInstitute.MvvmDialogs.Avalonia.Tests.Views; public partial class SecondWindow : Window { public SecondWindow() { InitializeComponent(); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } } ================================================ FILE: src/MvvmDialogs.Avalonia.Tests/Views/ThirdView.axaml ================================================ Test UserControl ================================================ FILE: src/MvvmDialogs.Avalonia.Tests/Views/ThirdView.axaml.cs ================================================ using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace HanumanInstitute.MvvmDialogs.Avalonia.Tests.Views; public partial class ThirdView : UserControl { public ThirdView() { InitializeComponent(); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } } ================================================ FILE: src/MvvmDialogs.Avalonia.Tests/Views/ThirdViewModel.cs ================================================ using ReactiveUI; namespace HanumanInstitute.MvvmDialogs.Avalonia.Tests.Views; public class ThirdViewModel : ReactiveObject, ICloseable, IActivable, IModalDialogViewModel { public event EventHandler RequestClose; public event EventHandler RequestActivate; public void OnRequestClose() => RequestClose?.Invoke(this, EventArgs.Empty); public void OnRequestActivate() => RequestActivate?.Invoke(this, EventArgs.Empty); public bool? DialogResult { get; set; } } ================================================ FILE: src/MvvmDialogs.Avalonia.Tests/Views/ThirdWindow.axaml ================================================ Test Window ================================================ FILE: src/MvvmDialogs.Avalonia.Tests/Views/ThirdWindow.axaml.cs ================================================ using Avalonia.Controls; using Avalonia.Markup.Xaml; namespace HanumanInstitute.MvvmDialogs.Avalonia.Tests.Views; public partial class ThirdWindow : Window { public ThirdWindow() { InitializeComponent(); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } } ================================================ FILE: src/MvvmDialogs.Wpf/Api/FileApiSettings.cs ================================================ using System.Windows.Forms; namespace HanumanInstitute.MvvmDialogs.Wpf.Api; internal class FileApiSettings { public string DefaultExt { get; set; } = string.Empty; public bool AddExtension { get; set; } = true; public bool CheckFileExists { get; set; } = false; public bool CheckPathExists { get; set; } = true; public FileDialogCustomPlacesCollection CustomPlaces { get; } = new FileDialogCustomPlacesCollection(); public string InitialDirectory { get; set; } = string.Empty; public string FileName { get; set; } = string.Empty; public string[] FileNames { get; set; } = Array.Empty(); public bool DereferenceLinks { get; set; } = true; public string Filter { get; set; } = string.Empty; public string Title { get; set; } = string.Empty; public bool ShowHelp { get; set; } = false; public EventHandler? HelpRequest { get; set; } internal void ApplyTo(FileDialog d) { d.DefaultExt = DefaultExt; d.AddExtension = AddExtension; d.CheckFileExists = CheckFileExists; d.CheckPathExists = CheckPathExists; foreach (var item in CustomPlaces) { d.CustomPlaces.Add(item); } d.InitialDirectory = InitialDirectory; d.FileName = FileName; d.DereferenceLinks = DereferenceLinks; d.Filter = Filter; d.Title = Title; d.ShowHelp = ShowHelp; if (HelpRequest != null) { d.HelpRequest += HelpRequest; } } } ================================================ FILE: src/MvvmDialogs.Wpf/Api/FrameworkDialogsApi.cs ================================================ using System.Linq; using System.Windows.Forms; using HanumanInstitute.MvvmDialogs.FileSystem; namespace HanumanInstitute.MvvmDialogs.Wpf.Api; /// internal class FrameworkDialogsApi : IFrameworkDialogsApi { public FrameworkDialogsApi() { } public MessageBoxResult ShowMessageBox(Window? owner, MessageBoxApiSettings settings) => owner != null ? System.Windows.MessageBox.Show( owner, settings.MessageBoxText, settings.Caption, settings.Buttons, settings.Icon, settings.DefaultButton) : System.Windows.MessageBox.Show( settings.MessageBoxText, settings.Caption, settings.Buttons, settings.Icon, settings.DefaultButton); public IReadOnlyList ShowOpenFileDialog(Window? owner, OpenFileApiSettings settings) { var dialog = new System.Windows.Forms.OpenFileDialog(); settings.ApplyTo(dialog); var result = dialog.ShowDialog(owner); return result == DialogResult.OK ? dialog.FileNames.Select(x => new DesktopDialogStorageFile(x)).ToArray() : Array.Empty(); } public IDialogStorageFile? ShowSaveFileDialog(Window? owner, SaveFileApiSettings settings) { var dialog = new System.Windows.Forms.SaveFileDialog(); settings.ApplyTo(dialog); var result = dialog.ShowDialog(owner); return result == DialogResult.OK ? new DesktopDialogStorageFile(dialog.FileName) : null; } public IReadOnlyList ShowOpenFolderDialog(Window? owner, OpenFolderApiSettings settings) { var dialog = new FolderBrowserDialog(); settings.ApplyTo(dialog); var result = dialog.ShowDialog(owner); return result == DialogResult.OK ? new IDialogStorageFolder[] { new DesktopDialogStorageFolder(dialog.SelectedPath) } : Array.Empty(); } } ================================================ FILE: src/MvvmDialogs.Wpf/Api/IFrameworkDialogsApi.cs ================================================  using HanumanInstitute.MvvmDialogs.FileSystem; namespace HanumanInstitute.MvvmDialogs.Wpf.Api; /// /// Wrapper around Win32 dialogs API that can be replaced by a mock for testing. /// internal interface IFrameworkDialogsApi { MessageBoxResult ShowMessageBox(Window? owner, MessageBoxApiSettings settings); IReadOnlyList ShowOpenFileDialog(Window? owner, OpenFileApiSettings settings); IDialogStorageFile? ShowSaveFileDialog(Window? owner, SaveFileApiSettings settings); IReadOnlyList ShowOpenFolderDialog(Window? owner, OpenFolderApiSettings settings); } ================================================ FILE: src/MvvmDialogs.Wpf/Api/MessageBoxApiSettings.cs ================================================  namespace HanumanInstitute.MvvmDialogs.Wpf.Api; internal class MessageBoxApiSettings { public string MessageBoxText { get; set; } = string.Empty; public string Caption { get; set; } = string.Empty; public System.Windows.MessageBoxButton Buttons { get; set; } public System.Windows.MessageBoxImage Icon { get; set; } public System.Windows.MessageBoxResult DefaultButton { get; set; } public System.Windows.MessageBoxOptions Options { get; set; } } ================================================ FILE: src/MvvmDialogs.Wpf/Api/OpenFileApiSettings.cs ================================================  namespace HanumanInstitute.MvvmDialogs.Wpf.Api; internal class OpenFileApiSettings : FileApiSettings { public bool Multiselect { get; set; } public bool ReadOnlyChecked { get; set; } public bool ShowReadOnly { get; set; } internal void ApplyTo(System.Windows.Forms.OpenFileDialog d) { base.ApplyTo(d); d.Multiselect = Multiselect; d.ReadOnlyChecked = ReadOnlyChecked; d.ShowReadOnly = ShowReadOnly; } } ================================================ FILE: src/MvvmDialogs.Wpf/Api/OpenFolderApiSettings.cs ================================================  namespace HanumanInstitute.MvvmDialogs.Wpf.Api; internal class OpenFolderApiSettings { public string Description { get; set; } = string.Empty; public string? SelectedPath { get; set; } = string.Empty; public EventHandler? HelpRequest { get; set; } internal void ApplyTo(System.Windows.Forms.FolderBrowserDialog d) { d.Description = Description; d.SelectedPath = SelectedPath; if (HelpRequest != null) { d.HelpRequest += HelpRequest; } } } ================================================ FILE: src/MvvmDialogs.Wpf/Api/SaveFileApiSettings.cs ================================================  namespace HanumanInstitute.MvvmDialogs.Wpf.Api; internal class SaveFileApiSettings : FileApiSettings { public bool CreatePrompt { get; set; } public bool OverwritePrompt { get; set; } = true; internal void ApplyTo(System.Windows.Forms.SaveFileDialog d) { base.ApplyTo(d); d.CreatePrompt = CreatePrompt; d.OverwritePrompt = OverwritePrompt; } } ================================================ FILE: src/MvvmDialogs.Wpf/DialogFactory.cs ================================================ using HanumanInstitute.MvvmDialogs.Wpf.Api; using HanumanInstitute.MvvmDialogs.FrameworkDialogs; using System.Text; using Win32Button = System.Windows.MessageBoxButton; using Win32Image = System.Windows.MessageBoxImage; using Win32Result = System.Windows.MessageBoxResult; using Win32Options = System.Windows.MessageBoxOptions; using Win32MessageBox = System.Windows.MessageBox; using MessageBoxButton = HanumanInstitute.MvvmDialogs.FrameworkDialogs.MessageBoxButton; using MessageBoxImage = HanumanInstitute.MvvmDialogs.FrameworkDialogs.MessageBoxImage; using System; using HanumanInstitute.MvvmDialogs.FileSystem; namespace HanumanInstitute.MvvmDialogs.Wpf; /// /// Handles OpenFileDialog, SaveFileDialog and OpenFolderDialog for WPF. /// public class DialogFactory : DialogFactoryBase { private readonly IFrameworkDialogsApi _api; /// /// Initializes a new instance of a FrameworkDialog. /// /// If the dialog is not handled by this class, calls this other handler next. public DialogFactory(IDialogFactory? chain = null) : this(chain, null) { } /// /// Initializes a new instance of a FrameworkDialog. /// /// If the dialog is not handled by this class, calls this other handler next. /// An interface exposing WPF framework dialogs. internal DialogFactory(IDialogFactory? chain, IFrameworkDialogsApi? api) : base(chain) { _api = api ?? new FrameworkDialogsApi(); } /// /// Gets or sets whether message boxes are displayed right-to-left (RightAlign+RtlReading). /// public bool MessageBoxRightToLeft { get; set; } /// /// Gets or sets whether to display on the default desktop of the interactive window station. Specifies that the message box is displayed from a .NET Windows Service application in order to notify the user of an event. /// public bool MessageBoxDefaultDesktopOnly { get; set; } /// /// Gets or sets whether to display on the currently active desktop even if a user is not logged on to the computer. Specifies that the message box is displayed from a .NET Windows Service application in order to notify the user of an event. /// public bool MessageBoxServiceNotification { get; set; } /// public override async Task ShowDialogAsync(ViewWrapper? owner, TSettings settings) => settings switch { OpenFolderDialogSettings s => await UiExtensions.RunUiAsync(() => ShowOpenFolderDialog(owner, s)).ConfigureAwait(true), OpenFileDialogSettings s => await UiExtensions.RunUiAsync(() => ShowOpenFileDialog(owner, s)).ConfigureAwait(true), SaveFileDialogSettings s => await UiExtensions.RunUiAsync(() => ShowSaveFileDialog(owner, s)).ConfigureAwait(true), MessageBoxSettings s => await UiExtensions.RunUiAsync(() => ShowMessageBox(owner, s)).ConfigureAwait(true), _ => base.ShowDialogAsync(owner, settings) }; /// public override object? ShowDialog(ViewWrapper? owner, TSettings settings) => settings switch { OpenFolderDialogSettings s => ShowOpenFolderDialog(owner, s), OpenFileDialogSettings s => ShowOpenFileDialog(owner, s), SaveFileDialogSettings s => ShowSaveFileDialog(owner, s), MessageBoxSettings s => ShowMessageBox(owner, s), _ => base.ShowDialog(owner, settings) }; private IReadOnlyList ShowOpenFolderDialog(ViewWrapper? owner, OpenFolderDialogSettings settings) { var apiSettings = new OpenFolderApiSettings() { Description = settings.Title, SelectedPath = settings.SuggestedStartLocation?.LocalPath, HelpRequest = settings.HelpRequest }; return _api.ShowOpenFolderDialog(owner?.Ref, apiSettings); } private IReadOnlyList ShowOpenFileDialog(ViewWrapper? owner, OpenFileDialogSettings settings) { var apiSettings = new OpenFileApiSettings() { CheckFileExists = true, Multiselect = settings.AllowMultiple ?? false, ReadOnlyChecked = settings.ReadOnlyChecked, ShowReadOnly = settings.ShowReadOnly }; AddSharedSettings(apiSettings, settings); return _api.ShowOpenFileDialog(owner?.Ref, apiSettings) ?? Array.Empty(); } private IDialogStorageFile? ShowSaveFileDialog(ViewWrapper? owner, SaveFileDialogSettings settings) { var apiSettings = new SaveFileApiSettings() { DefaultExt = settings.DefaultExtension ?? string.Empty }; AddSharedSettings(apiSettings, settings); return _api.ShowSaveFileDialog(owner?.Ref, apiSettings); } private void AddSharedSettings(FileApiSettings d, FileDialogSettings s) { d.InitialDirectory = s.SuggestedStartLocation?.LocalPath ?? string.Empty; d.FileName = s.SuggestedFileName; d.DereferenceLinks = s.DereferenceLinks; d.Filter = SyncFilters(s.Filters); d.Title = s.Title; d.ShowHelp = s.HelpRequest != null; d.HelpRequest = s.HelpRequest; } /// /// Encodes the list of filters in the Win32 API format: /// "Image Files (*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*" /// /// The list of filters to encode. /// A string representation of the list compatible with Win32 API. private static string SyncFilters(IList filters) { var result = new StringBuilder(); foreach (var item in filters) { // Add separator. if (result.Length > 0) { result.Append('|'); } // Get all extensions as a string. var extDesc = item.ExtensionsToString(); // Get name including extensions. var name = item.NameToString(extDesc); // Add name+extensions for display. result.Append(name); // Add extensions again for the API. result.Append("|"); result.Append(extDesc); } return result.ToString(); } private bool? ShowMessageBox(ViewWrapper? owner, MessageBoxSettings settings) { var apiSettings = new MessageBoxApiSettings() { MessageBoxText = settings.Content, Caption = settings.Title, Buttons = SyncButton(settings.Button), Icon = SyncIcon(settings.Icon), DefaultButton = SyncDefault(settings.Button, settings.DefaultValue), Options = SyncOptions() }; var button = _api.ShowMessageBox(owner?.Ref, apiSettings); return button switch { Win32Result.Yes => true, Win32Result.OK => true, Win32Result.No => false, Win32Result.Cancel => null, _ => (bool?)null }; } private static Win32Button SyncButton(MessageBoxButton value) => (value) switch { MessageBoxButton.Ok => Win32Button.OK, MessageBoxButton.YesNo => Win32Button.YesNo, MessageBoxButton.OkCancel => Win32Button.OKCancel, MessageBoxButton.YesNoCancel => Win32Button.YesNoCancel, _ => Win32Button.OK }; private static Win32Image SyncIcon(MessageBoxImage value) => (value) switch { MessageBoxImage.None => Win32Image.None, MessageBoxImage.Error => Win32Image.Error, MessageBoxImage.Exclamation => Win32Image.Exclamation, MessageBoxImage.Information => Win32Image.Information, MessageBoxImage.Stop => Win32Image.Stop, MessageBoxImage.Warning => Win32Image.Warning, _ => Win32Image.None }; private static Win32Result SyncDefault(MessageBoxButton buttons, bool? value) => buttons switch { MessageBoxButton.Ok => Win32Result.OK, MessageBoxButton.YesNo => value == true ? Win32Result.Yes : Win32Result.No, MessageBoxButton.OkCancel => value == true ? Win32Result.OK : Win32Result.Cancel, MessageBoxButton.YesNoCancel => value switch { true => Win32Result.Yes, false => Win32Result.No, _ => Win32Result.Cancel }, _ => Win32Result.None }; private Win32Options SyncOptions() => EvalOption(MessageBoxDefaultDesktopOnly, Win32Options.DefaultDesktopOnly) | EvalOption(MessageBoxRightToLeft, Win32Options.RightAlign) | EvalOption(MessageBoxRightToLeft, Win32Options.RtlReading) | EvalOption(MessageBoxServiceNotification, Win32Options.ServiceNotification); private static Win32Options EvalOption(bool cond, Win32Options option) => cond ? option : Win32Options.None; } ================================================ FILE: src/MvvmDialogs.Wpf/DialogFactoryBase.cs ================================================  // ReSharper disable MemberCanBePrivate.Global namespace HanumanInstitute.MvvmDialogs.Wpf; /// /// Interface representing a framework dialog. /// public abstract class DialogFactoryBase : IDialogFactory, IDialogFactorySync { /// public IDialogManager? DialogManager { get; set; } /// public IDialogFactory? Chain { get; } /// public IDialogFactory ChainTop { get; private set; } /// /// Initializes a new instance of a FrameworkDialog. /// /// If the dialog is not handled by this class, calls this other handler next. protected DialogFactoryBase(IDialogFactory? chain) { Chain = chain; ChainTop = this; // Set ChainTop recursively. var item = chain; while (item is DialogFactoryBase f) { f.ChainTop = this; item = f.Chain; } } /// public Task ShowDialogAsync(IView? owner, TSettings settings) { if (owner is not null and not ViewWrapper) throw new ArgumentException($"{nameof(owner)} must be of type {nameof(ViewWrapper)}"); return ShowDialogAsync((ViewWrapper?)owner, settings); } /// public object? ShowDialog(IView? owner, TSettings settings) { if (owner is not null and not ViewWrapper) throw new ArgumentException($"{nameof(owner)} must be of type {nameof(ViewWrapper)}"); return ShowDialog((ViewWrapper?)owner, settings); } /// /// Opens a framework dialog with specified owner. /// /// Handle to the window that owns the dialog. /// The settings for the framework dialog. /// Return data specific to the dialog. public virtual Task ShowDialogAsync(ViewWrapper? owner, TSettings settings) => Chain != null ? Chain.ShowDialogAsync(owner, settings) : throw new NotSupportedException($"There is no registered dialog for settings of type {typeof(TSettings).Name}."); /// /// Opens a framework dialog with specified owner. /// /// Handle to the window that owns the dialog. /// The settings for the framework dialog. /// Return data specific to the dialog. public virtual object? ShowDialog(ViewWrapper? owner, TSettings settings) => Chain != null ? Chain.AsSync().ShowDialog(owner, settings) : throw new NotSupportedException($"There is no registered dialog for settings of type {typeof(TSettings).Name}."); } ================================================ FILE: src/MvvmDialogs.Wpf/DialogManager.cs ================================================ using System.Linq; using System.Windows.Media; using System.Windows.Threading; using Microsoft.Extensions.Logging; namespace HanumanInstitute.MvvmDialogs.Wpf { /// /// DialogManager that supports extra sync methods to show dialogs. /// public class DialogManager : DialogManagerBase, IDialogManagerSync { private readonly Dispatcher _dispatcher; /// public DialogManager(IViewLocator? viewLocator = null, IDialogFactory? dialogFactory = null, ILogger? logger = null, Dispatcher? dispatcher = null) : base(viewLocator ?? new ViewLocatorBase(), dialogFactory ?? new DialogFactory(), logger) { _dispatcher = dispatcher ?? Application.Current.Dispatcher; } /// protected override bool IsDesignMode => DesignerProperties.GetIsInDesignMode(new DependencyObject()); /// public virtual void ShowDialog(INotifyPropertyChanged ownerViewModel, IModalDialogViewModel viewModel) { var viewDef = ViewLocator.Locate(viewModel); Logger?.LogInformation("View: {View}; ViewModel: {ViewModel}; Owner: {OwnerViewModel}", viewDef.ViewType, viewModel.GetType(), ownerViewModel.GetType()); var dialog = CreateDialog(viewModel, viewDef); dialog.AsSync().ShowDialog(FindViewByViewModelOrThrow(ownerViewModel)!); Logger?.LogInformation("View: {View}; Result: {Result}", viewDef.ViewType.GetType(), viewModel.DialogResult); } /// public object? ShowFrameworkDialog(INotifyPropertyChanged? ownerViewModel, TSettings settings, Func? resultToString = null) where TSettings : DialogSettingsBase { Logger?.LogInformation("Dialog: {Dialog}; Title: {Title}", settings.GetType().Name, settings.Title); IView? owner = null; if (ownerViewModel != null) { owner = FindViewByViewModelOrThrow(ownerViewModel); } var result = DialogFactory.AsSync().ShowDialog(owner, settings); Logger?.LogInformation("Dialog: {Dialog}; Result: {Result}", settings?.GetType().Name, resultToString != null ? resultToString(result) : result?.ToString()); return result; } /// protected override IView CreateWrapper(INotifyPropertyChanged viewModel, ViewDefinition viewDef) { var wrapper = new ViewWrapper(); wrapper.Initialize(viewModel, viewDef); return wrapper; } /// protected override IView AsWrapper(Window view) => view.AsWrapper(); private static IEnumerable Windows => Application.Current.Windows.Cast(); /// public override IView? FindViewByViewModel(INotifyPropertyChanged viewModel) => Windows.FirstOrDefault(x => ReferenceEquals(viewModel, x.DataContext)).AsWrapper(); /// public override IView? GetMainWindow() => Application.Current.MainWindow.AsWrapper(); /// public override IView? GetDummyWindow() { var parent = new Window() { Height = 1, Width = 1, WindowStyle = WindowStyle.None, ShowInTaskbar = false, ResizeMode = ResizeMode.NoResize, WindowStartupLocation = WindowStartupLocation.CenterScreen, Background = Brushes.Transparent }; parent.Show(); return parent.AsWrapper(); } /// protected override void Dispatch(Action action) { if (_dispatcher.CheckAccess()) { action(); } else { _dispatcher.Invoke(action, DispatcherPriority.Render); } } /// protected override Task DispatchAsync(Func action) => _dispatcher.CheckAccess() ? Task.FromResult(action()) : _dispatcher.InvokeAsync(action, DispatcherPriority.Render).Task; } } ================================================ FILE: src/MvvmDialogs.Wpf/DialogService.cs ================================================  namespace HanumanInstitute.MvvmDialogs.Wpf; /// /// Class abstracting the interaction between view models and views when it comes to /// opening dialogs using the MVVM pattern in WPF. /// public class DialogService : DialogServiceBase, IDialogServiceSync { /// /// Initializes a new instance of the class. /// /// /// By default, is used as dialog type locator /// and is used as framework dialog factory. /// public DialogService() : this(null) { } /// /// Initializes a new instance of the class. /// /// Class responsible for UI interactions. /// Function used to create view model instances. This function is used only by and is not used internally. public DialogService( IDialogManager? dialogManager = null, Func? viewModelFactory = null) : base(dialogManager ?? new DialogManager(dialogFactory: new DialogFactory()), viewModelFactory) { } /// public bool? ShowDialog(INotifyPropertyChanged ownerViewModel, IModalDialogViewModel viewModel) => ShowDialogInternal(ownerViewModel, viewModel); /// public bool? ShowDialog(INotifyPropertyChanged ownerViewModel, IModalDialogViewModel viewModel) => ShowDialogInternal(ownerViewModel, viewModel); /// /// Displays a modal dialog of specified type. /// /// A view model that represents the owner window of the dialog. /// The view model of the new dialog. /// A nullable value of type that signifies how a window was closed by the user. /// No view is registered with specified owner view model as data context. protected bool? ShowDialogInternal(INotifyPropertyChanged ownerViewModel, IModalDialogViewModel viewModel) { if (ownerViewModel == null) throw new ArgumentNullException(nameof(ownerViewModel)); if (viewModel == null) throw new ArgumentNullException(nameof(viewModel)); DialogManager.AsSync().ShowDialog(ownerViewModel, viewModel); return viewModel.DialogResult; } } ================================================ FILE: src/MvvmDialogs.Wpf/DialogServiceExtensions.cs ================================================ using System.Windows.Forms; using HanumanInstitute.MvvmDialogs.Wpf; using HanumanInstitute.MvvmDialogs.FrameworkDialogs; using MessageBoxButton = HanumanInstitute.MvvmDialogs.FrameworkDialogs.MessageBoxButton; using MessageBoxImage = HanumanInstitute.MvvmDialogs.FrameworkDialogs.MessageBoxImage; using HanumanInstitute.MvvmDialogs.FileSystem; using System.Linq; namespace HanumanInstitute.MvvmDialogs; /// /// Extension methods. /// public static class DialogServiceExtensions { /// /// Displays a modal dialog of a type that is determined by the dialog type locator. /// /// The IDialogService. /// A view model that represents the owner window of the dialog. /// The view model of the new dialog. /// A nullable value of type that signifies how a window was closed by the user. /// No view is registered with specified owner view model as data context. public static bool? ShowDialog(this IDialogService service, INotifyPropertyChanged ownerViewModel, IModalDialogViewModel viewModel) => service.AsSync().ShowDialog(ownerViewModel, viewModel); /// /// Displays a modal dialog of specified type . /// /// The IDialogService. /// A view model that represents the owner window of the dialog. /// The view model of the new dialog. /// The type of the dialog to show. /// A nullable value of type that signifies how a window was closed by the user. /// No view is registered with specified owner view model as data context. public static bool? ShowDialog(this IDialogService service, INotifyPropertyChanged ownerViewModel, IModalDialogViewModel viewModel) => service.AsSync().ShowDialog(ownerViewModel, viewModel); /// /// Shows a modal dialog in a synchronous way. /// /// The window to show. public static bool? ShowDialog(this Window window) => window.ShowDialog(); /// /// Shows a modal dialog in a synchronous way. /// /// The dialog to show. /// The owner of the modal dialog. public static DialogResult ShowDialog(this CommonDialog dialog, Window? owner) => dialog.ShowDialog(owner != null ? new Win32Window(owner) : null); /// /// Displays a message box that has a message, title bar caption, button, and icon; and /// that accepts a default message box result and returns a result. /// /// The IDialogService on which to attach the extension method. /// A view model that represents the owner window of the dialog. /// A that specifies the text to display. /// A that specifies the title bar caption to display. Default value is an empty string. /// A value that specifies which button or buttons to display. /// Default value is . /// A value that specifies the icon to display. /// Default value is . /// Specifies the value of the button selected by default. Default value is true. /// A value that specifies which message box button is clicked by the user. True=OK/Yes, False=No, Null=Cancel /// No view is registered with specified owner view model as data context. public static bool? ShowMessageBox( this IDialogService service, INotifyPropertyChanged? ownerViewModel, string text, string title = "", MessageBoxButton button = MessageBoxButton.Ok, MessageBoxImage icon = MessageBoxImage.None, bool? defaultResult = true) { var settings = new MessageBoxSettings { Content = text, Title = title, Button = button, Icon = icon, DefaultValue = defaultResult }; return ShowMessageBox(service, ownerViewModel, settings); } /// /// Displays a message box that has a message, title bar caption, button, and icon; and /// that accepts a default message box result and returns a result. /// /// The IDialogService on which to attach the extension method. /// A view model that represents the owner window of the dialog. /// The settings for the message box dialog. /// A value that specifies which message box button is clicked by the user. True=OK/Yes, False=No, Null=Cancel /// No view is registered with specified owner view model as data context. public static bool? ShowMessageBox(this IDialogService service, INotifyPropertyChanged? ownerViewModel, MessageBoxSettings? settings = null) { return (bool?)service.DialogManager.AsSync().ShowFrameworkDialog( ownerViewModel, settings ?? new MessageBoxSettings()); } /// /// Displays the OpenFileDialog to select a single file. /// /// The IDialogService on which to attach the extension method. /// A view model that represents the owner window of the dialog. /// The settings for the open file dialog. /// The file selected by the user, or null if the user cancelled. /// No view is registered with specified owner view model as data context. public static IDialogStorageFile? ShowOpenFileDialog(this IDialogService service, INotifyPropertyChanged? ownerViewModel, OpenFileDialogSettings? settings = null) { settings ??= new OpenFileDialogSettings(); settings.AllowMultiple ??= false; return ShowOpenFilesDialog(service, ownerViewModel, settings).FirstOrDefault(); } /// /// Displays the OpenFileDialog to select multiple files. /// /// The IDialogService on which to attach the extension method. /// A view model that represents the owner window of the dialog. /// The settings for the open file dialog. /// The list of files selected by the user, or empty if the user cancelled. /// No view is registered with specified owner view model as data context. public static IReadOnlyList ShowOpenFilesDialog(this IDialogService service, INotifyPropertyChanged? ownerViewModel, OpenFileDialogSettings? settings = null) { settings ??= new OpenFileDialogSettings(); settings.AllowMultiple ??= true; return service.DialogManager.AsSync().ShowFrameworkDialog( ownerViewModel, settings, x => string.Join(", ", x)) as IReadOnlyList ?? Array.Empty(); } /// /// Displays the SaveFileDialog. /// /// The IDialogService on which to attach the extension method. /// A view model that represents the owner window of the dialog. /// The settings for the save file dialog. /// The file selected by the user, or null if the user cancelled. /// No view is registered with specified owner view model as data context. public static IDialogStorageFile? ShowSaveFileDialog(this IDialogService service, INotifyPropertyChanged? ownerViewModel, SaveFileDialogSettings? settings = null) { return (IDialogStorageFile?)service.DialogManager.AsSync().ShowFrameworkDialog( ownerViewModel, settings ?? new SaveFileDialogSettings()); } /// /// Displays the FolderBrowserDialog. /// /// The IDialogService on which to attach the extension method. /// A view model that represents the owner window of the dialog. /// The settings for the folder browser dialog. /// The folder selected by the user, or null if the user cancelled. /// No view is registered with specified owner view model as data context. public static IDialogStorageFolder? ShowOpenFolderDialog(this IDialogService service, INotifyPropertyChanged? ownerViewModel, OpenFolderDialogSettings? settings = null) { return ((IReadOnlyList?)service.DialogManager.AsSync().ShowFrameworkDialog( ownerViewModel, settings ?? new OpenFolderDialogSettings()))?.FirstOrDefault(); } } ================================================ FILE: src/MvvmDialogs.Wpf/GlobalUsings.cs ================================================ global using System; global using System.Collections.Generic; global using System.ComponentModel; global using System.Threading.Tasks; global using System.Windows; global using System.Windows.Controls; ================================================ FILE: src/MvvmDialogs.Wpf/IDialogFactorySync.cs ================================================ namespace HanumanInstitute.MvvmDialogs.Wpf; /// /// Interface representing a framework dialog. /// public interface IDialogFactorySync { /// /// Opens a framework dialog with specified owner. /// /// Handle to the window that owns the dialog. /// The settings for the framework dialog. /// Return data specific to the dialog. object? ShowDialog(IView? owner, TSettings settings); } ================================================ FILE: src/MvvmDialogs.Wpf/IDialogManagerSync.cs ================================================ using HanumanInstitute.MvvmDialogs.FrameworkDialogs; namespace HanumanInstitute.MvvmDialogs.Wpf; /// /// Adds support for sync methods to IDialogManager. /// public interface IDialogManagerSync { /// /// Shows a new dialog of specified type. /// /// A view model that represents the owner window of the dialog. /// The view model of the new dialog. /// The dialog result. void ShowDialog(INotifyPropertyChanged ownerViewModel, IModalDialogViewModel viewModel); /// /// Shows a framework dialog whose type depends on the settings type. /// /// A view model that represents the owner window of the dialog. /// The settings to pass to the /// A function to convert the result into a string for logging. If null, ToString will be used. /// The settings type used to determine which dialog to show. /// The dialog result. object? ShowFrameworkDialog(INotifyPropertyChanged? ownerViewModel, TSettings settings, Func? resultToString = null) where TSettings : DialogSettingsBase; } ================================================ FILE: src/MvvmDialogs.Wpf/IDialogServiceSync.cs ================================================  namespace HanumanInstitute.MvvmDialogs.Wpf; /// /// Provides sync ShowDialog methods for IDialogService. /// public interface IDialogServiceSync { /// /// Displays a modal dialog of a type that is determined by the dialog type locator. /// /// A view model that represents the owner window of the dialog. /// The view model of the new dialog. /// A nullable value of type that signifies how a window was closed by the user. /// No view is registered with specified owner view model as data context. bool? ShowDialog(INotifyPropertyChanged ownerViewModel, IModalDialogViewModel viewModel); /// /// Displays a modal dialog of specified type . /// /// A view model that represents the owner window of the dialog. /// The view model of the new dialog. /// The type of the dialog to show. /// A nullable value of type that signifies how a window was closed by the user. /// No view is registered with specified owner view model as data context. bool? ShowDialog(INotifyPropertyChanged ownerViewModel, IModalDialogViewModel viewModel); } ================================================ FILE: src/MvvmDialogs.Wpf/IWindowSync.cs ================================================  namespace HanumanInstitute.MvvmDialogs.Wpf; /// /// Provides a sync ShowDialog compatibility method to IWindow in WPF. /// public interface IViewSync { /// /// Opens a window and returns only when the newly opened window is closed. /// void ShowDialog(IView owner); } ================================================ FILE: src/MvvmDialogs.Wpf/MvvmDialogs.Wpf.csproj ================================================ net462;net10.0-windows default enable Library MVVM Dialogs for WPF MVVM Dialogs for WPF true ../StrongName.snk HanumanInstitute.MvvmDialogs.Wpf HanumanInstitute.MvvmDialogs.Wpf HanumanInstitute.MvvmDialogs.Wpf True True true true icon_64x64.png True \ StrongName.snk ================================================ FILE: src/MvvmDialogs.Wpf/Runtime/NullableAttributes.cs ================================================ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. // This was copied from https://github.com/dotnet/runtime/blob/39b9607807f29e48cae4652cd74735182b31182e/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/NullableAttributes.cs // and updated to have the scope of the attributes be internal. namespace System.Diagnostics.CodeAnalysis; #if !NETCOREAPP /// Specifies that null is allowed as an input even if the corresponding type disallows it. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] internal sealed class AllowNullAttribute : Attribute { } /// Specifies that null is disallowed as an input even if the corresponding type allows it. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property, Inherited = false)] internal sealed class DisallowNullAttribute : Attribute { } /// Specifies that an output may be null even if the corresponding type disallows it. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] internal sealed class MaybeNullAttribute : Attribute { } /// Specifies that an output will not be null even if the corresponding type allows it. [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, Inherited = false)] internal sealed class NotNullAttribute : Attribute { } /// Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] internal sealed class MaybeNullWhenAttribute : Attribute { /// Initializes the attribute with the specified return value condition. /// /// The return value condition. If the method returns this value, the associated parameter may be null. /// public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; /// Gets the return value condition. public bool ReturnValue { get; } } /// Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] internal sealed class NotNullWhenAttribute : Attribute { /// Initializes the attribute with the specified return value condition. /// /// The return value condition. If the method returns this value, the associated parameter will not be null. /// public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; /// Gets the return value condition. public bool ReturnValue { get; } } /// Specifies that the output will be non-null if the named parameter is non-null. [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true, Inherited = false)] internal sealed class NotNullIfNotNullAttribute : Attribute { /// Initializes the attribute with the associated parameter name. /// /// The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. /// public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName; /// Gets the associated parameter name. public string ParameterName { get; } } /// Applied to a method that will never return under any circumstance. [AttributeUsage(AttributeTargets.Method, Inherited = false)] internal sealed class DoesNotReturnAttribute : Attribute { } /// Specifies that the method will not return if the associated Boolean parameter is passed the specified value. [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] internal sealed class DoesNotReturnIfAttribute : Attribute { /// Initializes the attribute with the specified parameter value. /// /// The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to /// the associated parameter matches this value. /// public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue; /// Gets the condition parameter value. public bool ParameterValue { get; } } #endif #if !NETCOREAPP || NETCOREAPP3_1 /// Specifies that the method or property will ensure that the listed field and property members have not-null values. [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] internal sealed class MemberNotNullAttribute : Attribute { /// Initializes the attribute with a field or property member. /// /// The field or property member that is promised to be not-null. /// public MemberNotNullAttribute(string member) => Members = new[] { member }; /// Initializes the attribute with the list of field and property members. /// /// The list of field and property members that are promised to be not-null. /// public MemberNotNullAttribute(params string[] members) => Members = members; /// Gets field or property member names. public string[] Members { get; } } /// Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition. [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] internal sealed class MemberNotNullWhenAttribute : Attribute { /// Initializes the attribute with the specified return value condition and a field or property member. /// /// The return value condition. If the method returns this value, the associated parameter will not be null. /// /// /// The field or property member that is promised to be not-null. /// public MemberNotNullWhenAttribute(bool returnValue, string member) { ReturnValue = returnValue; Members = new[] { member }; } /// Initializes the attribute with the specified return value condition and list of field and property members. /// /// The return value condition. If the method returns this value, the associated parameter will not be null. /// /// /// The list of field and property members that are promised to be not-null. /// public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { ReturnValue = returnValue; Members = members; } /// Gets the return value condition. public bool ReturnValue { get; } /// Gets field or property member names. public string[] Members { get; } } #endif ================================================ FILE: src/MvvmDialogs.Wpf/StrongViewLocator.cs ================================================  namespace HanumanInstitute.MvvmDialogs.Wpf { /// /// Strongly-typed View Locator that does not rely on reflection. /// public class StrongViewLocator : StrongViewLocatorBase { /// /// Registers specified views as being associated with specified view model type. /// /// The type of view model to register. /// The view type to associate with the view model. public void Register() where TViewModel : INotifyPropertyChanged where TView : Control, new() => Register( new ViewDefinition(typeof(TView), () => new TView())); } } ================================================ FILE: src/MvvmDialogs.Wpf/UiExtensions.cs ================================================ using HanumanInstitute.MvvmDialogs.FrameworkDialogs; namespace HanumanInstitute.MvvmDialogs.Wpf; /// /// Provides extension methods for WPF. /// public static class UiExtensions { /// /// Runs a synchronous action asynchronously on the UI thread. /// /// The action to run asynchronously. /// The return type of the action. /// The result of the action. public static Task RunUiAsync(Func action) { TaskCompletionSource completion = new(); Application.Current.Dispatcher.BeginInvoke(new Action(() => completion.SetResult(action()))); return completion.Task; } /// /// Runs a synchronous action asynchronously on the UI thread. /// /// The action to run asynchronously. public static Task RunUiAsync(Action action) { TaskCompletionSource completion = new(); Application.Current.Dispatcher.BeginInvoke(new Action(() => { action(); completion.SetResult(true); })); return completion.Task; } /// /// Creates a WindowWrapper around specified window. /// /// The Window to get a wrapper for. /// A WindowWrapper referencing the window. [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("window")] public static ViewWrapper? AsWrapper(this Window? window) { if (window != null) { var result = new ViewWrapper(); result.InitializeExisting((INotifyPropertyChanged)window.DataContext!, window); return result; } return null; } /// /// Converts an IWindow into a WindowWrapper. /// /// The IWindow to convert. /// A WindowWrapper referencing the window. [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("window")] public static ViewWrapper? AsWrapper(this IView? window) => (ViewWrapper?)window; /// /// Returns the RefObj property as a WPF Window. /// /// The IView to get the Ref property for. /// The Window held within the IView. public static Window? GetRef(this IView? view) { if (view is ViewWrapper v) { return v.Ref; } return null; } /// /// Gets the owner of a wrapped in a . /// /// /// The to find the for. /// /// The owning if found; otherwise null. internal static ViewWrapper GetOwner(this FrameworkElement frameworkElement) { var owner = frameworkElement as Window ?? Window.GetWindow(frameworkElement); return owner.AsWrapper(); } /// /// Returns the Sync interface of an IFrameworkDialog. /// internal static IDialogFactorySync AsSync(this IDialogFactory factory) => factory as IDialogFactorySync ?? throw new InvalidCastException("IDialogFactory instance doesn't implement IDialogFactorySync."); /// /// Returns the Sync interface of an IWindow. /// internal static IViewSync AsSync(this IView window) => window as IViewSync ?? throw new InvalidCastException("IWindow instance doesn't implement IWindowSync."); /// /// Returns the Sync interface of an IDialogService. /// internal static IDialogServiceSync AsSync(this IDialogService service) => service as IDialogServiceSync ?? throw new InvalidCastException("IDialogService instance doesn't implement IDialogServiceSync."); /// /// Returns the Sync interface of an IDialogManager. /// internal static IDialogManagerSync AsSync(this IDialogManager service) => service as IDialogManagerSync ?? throw new InvalidCastException("IDialogManager instance doesn't implement IDialogManagerSync."); } ================================================ FILE: src/MvvmDialogs.Wpf/ViewLocatorBase.cs ================================================ using System.Reflection; namespace HanumanInstitute.MvvmDialogs.Wpf; /// /// Base implementation of WPF ViewLocator. Override GetViewName to customize paths. /// public class ViewLocatorBase : IViewLocator { /// /// Returns the view type name for specified view model type. By default, it replaces 'ViewModel' with 'View'. /// /// The view model to get the view type for. /// The view type name. protected virtual string GetViewName(object viewModel) => viewModel.GetType().FullName!.Replace("ViewModel", "View"); /// /// Creates a view based on the specified view model. /// /// The view model to create a view for. public virtual ViewDefinition Locate(object viewModel) { var name = GetViewName(viewModel); //var type = Assembly.GetEntryAssembly()?.GetType(name); var viewType = Assembly.GetAssembly(viewModel.GetType())?.GetType(name); // ReSharper disable once SuspiciousTypeConversion.Global if (viewType is null || (!typeof(Window).IsAssignableFrom(viewType) && !typeof(IView).IsAssignableFrom(viewType))) { var message = $"Dialog view of type {name} for view model {viewModel.GetType().FullName} is missing."; const string ErrorInfo = "You can create a ViewLocator class in the project base to map your " + "view models to your views. See online documentation for more info."; throw new TypeLoadException(message + Environment.NewLine + ErrorInfo); } return new ViewDefinition(viewType, () => CreateViewInstance(viewType)); } /// /// The method used to create the view instance from its . /// Uses by default. /// /// The type to create a view for. /// The created view. protected virtual object CreateViewInstance(Type viewType) => Activator.CreateInstance(viewType)!; /// public virtual object Create(object viewModel) => Locate(viewModel).Create(); } ================================================ FILE: src/MvvmDialogs.Wpf/ViewWrapper.cs ================================================ using System.Windows.Forms; namespace HanumanInstitute.MvvmDialogs.Wpf; /// /// Class wrapping an instance of WPF within . /// /// public class ViewWrapper : IView, IViewSync { /// /// Initializes a new instance of the class. /// /// /// public void Initialize(INotifyPropertyChanged viewModel, ViewDefinition viewDef) { Ref = (Window)viewDef.Create(); ViewModel = viewModel; } /// /// Initializes a new instance of the class. /// public void InitializeExisting(INotifyPropertyChanged viewModel, object view) { Ref = (Window)view; ViewModel = viewModel; } /// /// Gets the Window reference held by this class. /// public Window Ref { get; private set; } = default!; /// /// Gets the Window reference held by this class. /// public object RefObj => Ref; /// /// Returns a IWin32Window class that can be used for API calls. /// public IWin32Window Win32Window => new Win32Window(Ref); /// /// Occurs when the window is loading. /// public event EventHandler? Loaded { add { if (value != null) { var handler = new RoutedEventHandler(value.Invoke); _loadedHandlers.Add(value, handler); Ref.Loaded += handler; } } remove { if (value != null) { Ref.Loaded += _loadedHandlers[value]; _loadedHandlers.Remove(value); } } } private readonly Dictionary _loadedHandlers = new(); /// /// Occurs when the window is about to close. /// public event EventHandler? Closing { add { if (value != null) { var handler = new CancelEventHandler(value.Invoke); _closingHandlers.Add(value, handler); Ref.Closing += handler; } } remove { if (value != null) { Ref.Closing += _closingHandlers[value]; _closingHandlers.Remove(value); } } } private readonly Dictionary, CancelEventHandler> _closingHandlers = new(); /// /// Occurs when the window is about to close. /// public event EventHandler? Closed { add => Ref.Closed += value; remove => Ref.Closed -= value; } ///// ///// Initializes a new instance of the class. ///// ///// The window. //public ViewWrapper(Window window) => // this.Ref = window ?? throw new ArgumentNullException(nameof(window)); /// public INotifyPropertyChanged ViewModel { get => (INotifyPropertyChanged)Ref.DataContext; set => Ref.DataContext = value; } /// public IView? Owner { get => Ref.Owner.AsWrapper(); set => Ref.Owner = value switch { null => null, ViewWrapper w => w.Ref, _ => throw new ArgumentException($"Owner must be of type {typeof(ViewWrapper).FullName}") }; } /// public Task ShowDialogAsync(IView? owner) => UiExtensions.RunUiAsync(() => ShowDialog(owner)); /// public void ShowDialog(IView? owner) { Ref.Owner = owner?.RefObj as Window; Ref.ShowDialog(); } /// public void Show(IView? owner) { Ref.Owner = owner?.RefObj as Window; Ref.Show(); } /// public void Activate() => Ref.Activate(); /// public void Close() => Ref.Close(); /// public bool IsEnabled { get => Ref.IsEnabled; set => Ref.IsEnabled = value; } /// public bool IsVisible => Ref.IsVisible; /// public bool ClosingConfirmed { get; set; } } ================================================ FILE: src/MvvmDialogs.Wpf/Win32Window.cs ================================================ using System.Windows.Interop; using IWin32Window = System.Windows.Forms.IWin32Window; namespace HanumanInstitute.MvvmDialogs.Wpf; /// /// Class describing a wrapper around a WPF window. /// internal class Win32Window : IWin32Window { /// /// Initializes a new instance of the class. /// /// The WPF window to wrap. public Win32Window(Window window) => Handle = new WindowInteropHelper(window).Handle; /// public IntPtr Handle { get; } }