diff --git a/.editorconfig b/.editorconfig index d4fbd188..4e835e23 100644 --- a/.editorconfig +++ b/.editorconfig @@ -33,9 +33,9 @@ dotnet_style_coalesce_expression = true:suggestion dotnet_style_null_propagation = true:suggestion dotnet_style_explicit_tuple_names = true:suggestion # Prefer "var" everywhere -csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_for_built_in_types = false:suggestion csharp_style_var_when_type_is_apparent = true:suggestion -csharp_style_var_elsewhere = true:suggestion +csharp_style_var_elsewhere = false:suggestion # Prefer method-like constructs to have a expression body csharp_style_expression_bodied_methods = true:suggestion csharp_style_expression_bodied_constructors = true:suggestion diff --git a/CHANGELOG.md b/CHANGELOG.md index b85cb084..14837e96 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ This project adheres to [Semantic Versioning](http://semver.org/) and is followi ## Unreleased +### :syringe: Fixed + +- [#263](https://github.com/FantasticFiasco/mvvm-dialogs/issues/263) Exception is thrown when used in a multiple Single Threaded Apartment (STA) application (contributed by [@HeedfulCrayon](https://github.com/HeedfulCrayon)) + ## 9.1.0 - 2022-09-26 ### :zap: Added diff --git a/MvvmDialogs.sln b/MvvmDialogs.sln index b47f70e0..66f0d068 100644 --- a/MvvmDialogs.sln +++ b/MvvmDialogs.sln @@ -75,6 +75,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestBaseClasses", "samples\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.CustomDialogTypeLocator.Test", "samples\Demo.CustomDialogTypeLocator.Test\Demo.CustomDialogTypeLocator.Test.csproj", "{2F0419C7-BCF0-42B2-B95B-25A1BC960697}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.StaThreads", "samples\Demo.StaThreads\Demo.StaThreads.csproj", "{8F535A7F-BCC5-41D5-B5F9-D8CAAFD7D583}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Demo.StaThreads.Test", "samples\Demo.StaThreads.Test\Demo.StaThreads.Test.csproj", "{F0215BE6-48A3-4F4D-85D2-E6EE57CB0793}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -213,6 +217,14 @@ Global {2F0419C7-BCF0-42B2-B95B-25A1BC960697}.Debug|Any CPU.Build.0 = Debug|Any CPU {2F0419C7-BCF0-42B2-B95B-25A1BC960697}.Release|Any CPU.ActiveCfg = Release|Any CPU {2F0419C7-BCF0-42B2-B95B-25A1BC960697}.Release|Any CPU.Build.0 = Release|Any CPU + {8F535A7F-BCC5-41D5-B5F9-D8CAAFD7D583}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8F535A7F-BCC5-41D5-B5F9-D8CAAFD7D583}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8F535A7F-BCC5-41D5-B5F9-D8CAAFD7D583}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8F535A7F-BCC5-41D5-B5F9-D8CAAFD7D583}.Release|Any CPU.Build.0 = Release|Any CPU + {F0215BE6-48A3-4F4D-85D2-E6EE57CB0793}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F0215BE6-48A3-4F4D-85D2-E6EE57CB0793}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F0215BE6-48A3-4F4D-85D2-E6EE57CB0793}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F0215BE6-48A3-4F4D-85D2-E6EE57CB0793}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -251,6 +263,8 @@ Global {6760EB09-F75D-44DE-BEB3-5C3DF1D57DCE} = {62592C78-61AA-44B4-A7C3-EAC678A568A2} {B6AD17E0-892C-460E-97F3-58A0EFFC3C33} = {62592C78-61AA-44B4-A7C3-EAC678A568A2} {2F0419C7-BCF0-42B2-B95B-25A1BC960697} = {62592C78-61AA-44B4-A7C3-EAC678A568A2} + {8F535A7F-BCC5-41D5-B5F9-D8CAAFD7D583} = {62592C78-61AA-44B4-A7C3-EAC678A568A2} + {F0215BE6-48A3-4F4D-85D2-E6EE57CB0793} = {62592C78-61AA-44B4-A7C3-EAC678A568A2} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {983A22B3-AE5B-4B67-A798-F6A6697B82A8} diff --git a/samples/Demo.ActivateNonModalDialog.Test/Demo.ActivateNonModalDialog.Test.csproj b/samples/Demo.ActivateNonModalDialog.Test/Demo.ActivateNonModalDialog.Test.csproj index ff0917bd..ee215fd4 100644 --- a/samples/Demo.ActivateNonModalDialog.Test/Demo.ActivateNonModalDialog.Test.csproj +++ b/samples/Demo.ActivateNonModalDialog.Test/Demo.ActivateNonModalDialog.Test.csproj @@ -27,8 +27,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/samples/Demo.CloseNonModalDialog.Test/Demo.CloseNonModalDialog.Test.csproj b/samples/Demo.CloseNonModalDialog.Test/Demo.CloseNonModalDialog.Test.csproj index 8e760857..65732aa7 100644 --- a/samples/Demo.CloseNonModalDialog.Test/Demo.CloseNonModalDialog.Test.csproj +++ b/samples/Demo.CloseNonModalDialog.Test/Demo.CloseNonModalDialog.Test.csproj @@ -27,8 +27,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/samples/Demo.CustomDialogTypeLocator.Test/Demo.CustomDialogTypeLocator.Test.csproj b/samples/Demo.CustomDialogTypeLocator.Test/Demo.CustomDialogTypeLocator.Test.csproj index d5286dfc..73a19d97 100644 --- a/samples/Demo.CustomDialogTypeLocator.Test/Demo.CustomDialogTypeLocator.Test.csproj +++ b/samples/Demo.CustomDialogTypeLocator.Test/Demo.CustomDialogTypeLocator.Test.csproj @@ -27,8 +27,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/samples/Demo.CustomFolderBrowserDialog.Test/Demo.CustomFolderBrowserDialog.Test.csproj b/samples/Demo.CustomFolderBrowserDialog.Test/Demo.CustomFolderBrowserDialog.Test.csproj index 31bb90a9..cdbfa95a 100644 --- a/samples/Demo.CustomFolderBrowserDialog.Test/Demo.CustomFolderBrowserDialog.Test.csproj +++ b/samples/Demo.CustomFolderBrowserDialog.Test/Demo.CustomFolderBrowserDialog.Test.csproj @@ -27,8 +27,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/samples/Demo.CustomMessageBox.Test/Demo.CustomMessageBox.Test.csproj b/samples/Demo.CustomMessageBox.Test/Demo.CustomMessageBox.Test.csproj index 6787079f..8faff66c 100644 --- a/samples/Demo.CustomMessageBox.Test/Demo.CustomMessageBox.Test.csproj +++ b/samples/Demo.CustomMessageBox.Test/Demo.CustomMessageBox.Test.csproj @@ -27,8 +27,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/samples/Demo.CustomOpenFileDialog.Test/Demo.CustomOpenFileDialog.Test.csproj b/samples/Demo.CustomOpenFileDialog.Test/Demo.CustomOpenFileDialog.Test.csproj index 75d7133b..384640a8 100644 --- a/samples/Demo.CustomOpenFileDialog.Test/Demo.CustomOpenFileDialog.Test.csproj +++ b/samples/Demo.CustomOpenFileDialog.Test/Demo.CustomOpenFileDialog.Test.csproj @@ -27,8 +27,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/samples/Demo.CustomSaveFileDialog.Test/Demo.CustomSaveFileDialog.Test.csproj b/samples/Demo.CustomSaveFileDialog.Test/Demo.CustomSaveFileDialog.Test.csproj index 481ca690..4c830cb3 100644 --- a/samples/Demo.CustomSaveFileDialog.Test/Demo.CustomSaveFileDialog.Test.csproj +++ b/samples/Demo.CustomSaveFileDialog.Test/Demo.CustomSaveFileDialog.Test.csproj @@ -27,8 +27,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/samples/Demo.FolderBrowserDialog.Test/Demo.FolderBrowserDialog.Test.csproj b/samples/Demo.FolderBrowserDialog.Test/Demo.FolderBrowserDialog.Test.csproj index b197ae40..e662d238 100644 --- a/samples/Demo.FolderBrowserDialog.Test/Demo.FolderBrowserDialog.Test.csproj +++ b/samples/Demo.FolderBrowserDialog.Test/Demo.FolderBrowserDialog.Test.csproj @@ -27,8 +27,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/samples/Demo.MessageBox.Test/Demo.MessageBox.Test.csproj b/samples/Demo.MessageBox.Test/Demo.MessageBox.Test.csproj index 5ce066bc..75b67e11 100644 --- a/samples/Demo.MessageBox.Test/Demo.MessageBox.Test.csproj +++ b/samples/Demo.MessageBox.Test/Demo.MessageBox.Test.csproj @@ -27,8 +27,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/samples/Demo.ModalCustomDialog.Test/Demo.ModalCustomDialog.Test.csproj b/samples/Demo.ModalCustomDialog.Test/Demo.ModalCustomDialog.Test.csproj index 274bff54..56a1afbc 100644 --- a/samples/Demo.ModalCustomDialog.Test/Demo.ModalCustomDialog.Test.csproj +++ b/samples/Demo.ModalCustomDialog.Test/Demo.ModalCustomDialog.Test.csproj @@ -27,8 +27,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/samples/Demo.ModalDialog.Test/Demo.ModalDialog.Test.csproj b/samples/Demo.ModalDialog.Test/Demo.ModalDialog.Test.csproj index 3abeda64..132e6e61 100644 --- a/samples/Demo.ModalDialog.Test/Demo.ModalDialog.Test.csproj +++ b/samples/Demo.ModalDialog.Test/Demo.ModalDialog.Test.csproj @@ -27,8 +27,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/samples/Demo.NonModalCustomDialog.Test/Demo.NonModalCustomDialog.Test.csproj b/samples/Demo.NonModalCustomDialog.Test/Demo.NonModalCustomDialog.Test.csproj index aa371728..afe1a54c 100644 --- a/samples/Demo.NonModalCustomDialog.Test/Demo.NonModalCustomDialog.Test.csproj +++ b/samples/Demo.NonModalCustomDialog.Test/Demo.NonModalCustomDialog.Test.csproj @@ -27,8 +27,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/samples/Demo.NonModalDialog.Test/Demo.NonModalDialog.Test.csproj b/samples/Demo.NonModalDialog.Test/Demo.NonModalDialog.Test.csproj index f7a18de3..fa9a25d0 100644 --- a/samples/Demo.NonModalDialog.Test/Demo.NonModalDialog.Test.csproj +++ b/samples/Demo.NonModalDialog.Test/Demo.NonModalDialog.Test.csproj @@ -27,8 +27,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/samples/Demo.OpenFileDialog.Test/Demo.OpenFileDialog.Test.csproj b/samples/Demo.OpenFileDialog.Test/Demo.OpenFileDialog.Test.csproj index 33452669..6ef44c45 100644 --- a/samples/Demo.OpenFileDialog.Test/Demo.OpenFileDialog.Test.csproj +++ b/samples/Demo.OpenFileDialog.Test/Demo.OpenFileDialog.Test.csproj @@ -27,8 +27,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/samples/Demo.SaveFileDialog.Test/Demo.SaveFileDialog.Test.csproj b/samples/Demo.SaveFileDialog.Test/Demo.SaveFileDialog.Test.csproj index fb07e87d..1b91e995 100644 --- a/samples/Demo.SaveFileDialog.Test/Demo.SaveFileDialog.Test.csproj +++ b/samples/Demo.SaveFileDialog.Test/Demo.SaveFileDialog.Test.csproj @@ -28,8 +28,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/samples/Demo.StaThreads.Test/Demo.StaThreads.Test.csproj b/samples/Demo.StaThreads.Test/Demo.StaThreads.Test.csproj new file mode 100644 index 00000000..a4ccf665 --- /dev/null +++ b/samples/Demo.StaThreads.Test/Demo.StaThreads.Test.csproj @@ -0,0 +1,41 @@ + + + + net472 + + Demo.StaThreads + + true + + enable + enable + + false + true + + + + + + + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + diff --git a/samples/Demo.StaThreads.Test/MainWindowViewModelTest.cs b/samples/Demo.StaThreads.Test/MainWindowViewModelTest.cs new file mode 100644 index 00000000..54712136 --- /dev/null +++ b/samples/Demo.StaThreads.Test/MainWindowViewModelTest.cs @@ -0,0 +1,34 @@ +using System.Windows; +using Moq; +using MvvmDialogs; +using Xunit; + +namespace Demo.StaThreads; + +public class MainWindowViewModelTest +{ + [Fact] + public void ShowMessageBox() + { + // Arrange + var dialogService = new Mock(); + var viewModel = new MainWindowViewModel(dialogService.Object); + + dialogService + .Setup(mock => + mock.ShowMessageBox( + viewModel, + It.IsAny(), + "", + MessageBoxButton.OK, + MessageBoxImage.None, + MessageBoxResult.None)) + .Returns(MessageBoxResult.OK); + + // Act + viewModel.ShowMessageBoxCommand.Execute(null); + + // Assert + dialogService.VerifyAll(); + } +} diff --git a/samples/Demo.StaThreads.Test/ScreenObjects/MainScreen.cs b/samples/Demo.StaThreads.Test/ScreenObjects/MainScreen.cs new file mode 100644 index 00000000..7b30d536 --- /dev/null +++ b/samples/Demo.StaThreads.Test/ScreenObjects/MainScreen.cs @@ -0,0 +1,26 @@ +using FlaUI.Core.AutomationElements; +using FlaUI.Core.Input; +using TestBaseClasses; + +namespace Demo.StaThreads.ScreenObjects; + +public class MainScreen : Screen +{ + public MainScreen(Window window) + : base(window) + { + } + + private Button MessageBoxButton => ElementByAutomationId + + + diff --git a/samples/Demo.StaThreads/MainWindow.xaml.cs b/samples/Demo.StaThreads/MainWindow.xaml.cs new file mode 100644 index 00000000..001c6107 --- /dev/null +++ b/samples/Demo.StaThreads/MainWindow.xaml.cs @@ -0,0 +1,9 @@ +namespace Demo.StaThreads; + +public partial class MainWindow +{ + public MainWindow() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/samples/Demo.StaThreads/MainWindowViewModel.cs b/samples/Demo.StaThreads/MainWindowViewModel.cs new file mode 100644 index 00000000..284412ac --- /dev/null +++ b/samples/Demo.StaThreads/MainWindowViewModel.cs @@ -0,0 +1,56 @@ +using System; +using System.Windows; +using System.Windows.Input; +using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; +using MvvmDialogs; + +namespace Demo.StaThreads; + +public class MainWindowViewModel : ObservableObject +{ + private readonly IDialogService dialogService; + + private string? confirmation; + + public MainWindowViewModel(IDialogService dialogService) + { + this.dialogService = dialogService; + + ShowMessageBoxCommand = new RelayCommand(ShowMessageBox); + } + + public ICommand ShowMessageBoxCommand { get; } + + public string? Confirmation + { + get => confirmation; + private set => SetProperty(ref confirmation, value); + } + + private void ShowMessageBox() + { + MessageBoxResult result = dialogService.ShowMessageBox( + this, + "This is the text."); + + UpdateResult(result); + } + + private void UpdateResult(MessageBoxResult result) + { + switch (result) + { + case MessageBoxResult.OK: + Confirmation = "We got confirmation to continue!"; + break; + + case MessageBoxResult.Cancel: + Confirmation = string.Empty; + break; + + default: + throw new NotSupportedException($"{confirmation} is not supported."); + } + } +} \ No newline at end of file diff --git a/samples/TestBaseClasses/App.cs b/samples/TestBaseClasses/App.cs index ecfb2946..c1a98866 100644 --- a/samples/TestBaseClasses/App.cs +++ b/samples/TestBaseClasses/App.cs @@ -37,10 +37,18 @@ public Window GetMainWindow(string title) return window; } + public Window GetMainWindowThatStartsWith(string title) + { + var window = app.GetMainWindow(automation, TimeSpan.FromSeconds(3)); + Assert.StartsWith(title, window.Title); + + return window; + } + public void Dispose() { app.Close(); app.Dispose(); automation.Dispose(); } -} \ No newline at end of file +} diff --git a/samples/TestBaseClasses/TestBaseClasses.csproj b/samples/TestBaseClasses/TestBaseClasses.csproj index eb26a2e6..f3cd2921 100644 --- a/samples/TestBaseClasses/TestBaseClasses.csproj +++ b/samples/TestBaseClasses/TestBaseClasses.csproj @@ -15,8 +15,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/src/DialogService.cs b/src/DialogService.cs index aac29ded..a73f9b22 100644 --- a/src/DialogService.cs +++ b/src/DialogService.cs @@ -360,4 +360,4 @@ private static void UnregisterDialogResult( viewModel.PropertyChanged -= handler; -} \ No newline at end of file +} diff --git a/src/DialogServiceViews.cs b/src/DialogServiceViews.cs index f3b9510b..3fac3a57 100644 --- a/src/DialogServiceViews.cs +++ b/src/DialogServiceViews.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using System.Linq; using System.Windows; +using System.Windows.Threading; using MvvmDialogs.Logging; using MvvmDialogs.Views; @@ -18,7 +19,9 @@ public static class DialogServiceViews /// /// The registered views. /// - private static readonly List InternalViews = new List(); + private static readonly List InternalViews = new List(); + + private static readonly object SyncRoot = new object(); #region Attached properties @@ -82,12 +85,40 @@ private static void IsRegisteredChanged( #endregion /// - /// Gets the registered views. + /// Gets the registered views on the current thread. + /// + internal static IEnumerable Views + { + get + { + lock (SyncRoot) + { + return InternalViews + .Where(threadedView => + threadedView.ThreadId == Dispatcher.CurrentDispatcher.Thread.ManagedThreadId && + threadedView.View.IsAlive) + .Select(view => view.View) + .ToArray(); + } + } + } + + /// + /// Gets the registered views on all thread. /// - internal static IEnumerable Views => - InternalViews - .Where(view => view.IsAlive) - .ToArray(); + internal static IEnumerable AllViews + { + get + { + lock (SyncRoot) + { + return InternalViews + .Where(threadedView => threadedView.View.IsAlive) + .Select(view => view.View) + .ToArray(); + } + } + } /// /// Registers specified view. @@ -116,17 +147,31 @@ internal static void Register(IView view) owner.Closed += OwnerClosed; Logger.Write($"Register view {view.Id}"); - InternalViews.Add(view); - Logger.Write($"Registered view {view.Id} ({InternalViews.Count} registered)"); + int threadId = Dispatcher.CurrentDispatcher.Thread.ManagedThreadId; + int count; + + lock (SyncRoot) + { + InternalViews.Add(new ThreadedView(view, threadId)); + count = InternalViews.Count; + } + + Logger.Write($"Registered view {view.Id} ({count} registered)"); } + /// /// Clears the registered views. /// internal static void Clear() { Logger.Write("Clearing views"); - InternalViews.Clear(); + + lock (SyncRoot) + { + InternalViews.Clear(); + } + Logger.Write("Cleared views"); } @@ -141,8 +186,19 @@ private static void Unregister(IView view) PruneInternalViews(); Logger.Write($"Unregister view {view.Id}"); - InternalViews.RemoveAll(registeredView => ReferenceEquals(registeredView.Source, view.Source)); - Logger.Write($"Unregistered view {view.Id} ({InternalViews.Count} registered)"); + int threadId = Dispatcher.CurrentDispatcher.Thread.ManagedThreadId; + int count; + + lock (SyncRoot) + { + InternalViews.RemoveAll(threadedView => + threadedView.ThreadId == threadId && + ReferenceEquals(threadedView.View.Source, view.Source)); + + count = InternalViews.Count; + } + + Logger.Write($"Unregistered view {view.Id} ({count} registered)"); } /// @@ -192,8 +248,30 @@ private static void OwnerClosed(object? sender, EventArgs e) private static void PruneInternalViews() { - Logger.Write($"Before pruning ({InternalViews.Count} registered)"); - InternalViews.RemoveAll(reference => !reference.IsAlive); - Logger.Write($"After pruning ({InternalViews.Count} registered)"); + int beforeCount; + int afterCount; + + lock (SyncRoot) + { + beforeCount = InternalViews.Count; + InternalViews.RemoveAll(threadView => !threadView.View.IsAlive); + afterCount = InternalViews.Count; + } + + Logger.Write($"Before pruning ({beforeCount} registered)"); + Logger.Write($"After pruning ({afterCount} registered)"); + } + + private class ThreadedView + { + public ThreadedView(IView view, int threadId) + { + View = view; + ThreadId = threadId; + } + + public IView View { get; } + + public int ThreadId { get; } } -} \ No newline at end of file +} diff --git a/test/DialogServiceViewsTest.cs b/test/DialogServiceViewsTest.cs index 689bc771..ad54a637 100644 --- a/test/DialogServiceViewsTest.cs +++ b/test/DialogServiceViewsTest.cs @@ -108,6 +108,55 @@ public void RegisterLoadedView() Assert.Equal(expected, DialogServiceViews.Views); } + [StaFact] + public void RegisterLoadedViewOnMultipleThreads() + { + // Arrange + Mock ViewProvider() + { + var view = new Mock(); + view.Setup(mock => mock.IsAlive) + .Returns(true); + view.Setup(mock => mock.GetOwner()) + .Returns(new Window()); + + return view; + } + + var firstView = ViewProvider(); + var secondView = ViewProvider(); + + var waiter = new ManualResetEvent(false); + + // Create and register a second view on a new thread + var newThread = new Thread( + () => + { + DialogServiceViews.Register(secondView.Object); + waiter.Set(); + }); + + newThread.SetApartmentState(ApartmentState.STA); + newThread.Start(); + + // Wait for the registration of the second view + waiter.WaitOne(); + + var expectedOnCurrentThread = new[] + { + firstView.Object + }; + + var expectedCountOnAllThreads = 2; + + // Act + DialogServiceViews.Register(firstView.Object); + + // Assert + Assert.Equal(expectedOnCurrentThread, DialogServiceViews.Views); + Assert.Equal(expectedCountOnAllThreads, DialogServiceViews.AllViews.Count()); + } + [StaFact] public void UnregisterLoadedView() { @@ -216,4 +265,4 @@ public abstract class FrameworkElementMock : FrameworkElement, IView } #endregion -} \ No newline at end of file +} diff --git a/test/MvvmDialogs.Test.csproj b/test/MvvmDialogs.Test.csproj index 0057b687..776640d3 100644 --- a/test/MvvmDialogs.Test.csproj +++ b/test/MvvmDialogs.Test.csproj @@ -31,8 +31,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all