From ac60f14e90e4ae13c79916f70b19762b17d39bbd Mon Sep 17 00:00:00 2001 From: AKruimink <43521957+AKruimink@users.noreply.github.com> Date: Thu, 5 Sep 2024 19:00:56 +0100 Subject: [PATCH 1/4] Updates the project to net8.0-windows --- .../Displays/DisplayServiceTests.cs | 8 ++++---- .../WinReform.Domain.Tests/WinApi/MonitorTests.cs | 10 +++++----- .../WinReform.Domain.Tests.csproj | 5 +++-- .../WinReform.Tests.Fixtures.csproj | 4 +++- src/Tests/WinReform.Tests.Process.Fixture/Program.cs | 4 ++-- .../WinReform.Tests.Process.Fixture.csproj | 4 +++- .../WinReform.Tests.WindowProcess.Fixture/App.xaml.cs | 4 ++-- .../WinReform.Tests.WindowProcess.Fixture.csproj | 4 +++- src/Tests/WinReform.Tests/WinReform.Tests.csproj | 5 +++-- src/WinReform/WinReform.Domain/WinReform.Domain.csproj | 3 ++- src/WinReform/WinReform/WinReform.csproj | 5 +++-- 11 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/Tests/WinReform.Domain.Tests/Displays/DisplayServiceTests.cs b/src/Tests/WinReform.Domain.Tests/Displays/DisplayServiceTests.cs index c434814..55c3e08 100644 --- a/src/Tests/WinReform.Domain.Tests/Displays/DisplayServiceTests.cs +++ b/src/Tests/WinReform.Domain.Tests/Displays/DisplayServiceTests.cs @@ -46,7 +46,7 @@ public void GetDisplays_NoDisplays_ShoulReturnEmptyDisplayList() { // Prepare var winApiServiceMock = new Mock(); - winApiServiceMock.Setup(x => x.GetAllMonitors()).Returns(new List()); + winApiServiceMock.Setup(x => x.GetAllMonitors()).Returns(new List()); var displayService = new DisplayService(winApiServiceMock.Object); // Act @@ -60,9 +60,9 @@ public void GetDisplays_NoDisplays_ShoulReturnEmptyDisplayList() public void GetDisplays_ExistingDisplays_ShoulReturnListWithDisplays() { // Prepare - var monitorList = new List + var monitorList = new List { - new Monitor + new Domain.WinApi.Monitor { Size = 1, MonitorSize = new Rect { Left = 1, Top = 2, Right = 3, Bottom = 4 }, @@ -70,7 +70,7 @@ public void GetDisplays_ExistingDisplays_ShoulReturnListWithDisplays() Flags = 1, MonitorHandle = (IntPtr)1 }, - new Monitor + new Domain.WinApi.Monitor { Size = 2, MonitorSize = new Rect { Left = 1, Top = 2, Right = 3, Bottom = 4 }, diff --git a/src/Tests/WinReform.Domain.Tests/WinApi/MonitorTests.cs b/src/Tests/WinReform.Domain.Tests/WinApi/MonitorTests.cs index 930421e..86d8787 100644 --- a/src/Tests/WinReform.Domain.Tests/WinApi/MonitorTests.cs +++ b/src/Tests/WinReform.Domain.Tests/WinApi/MonitorTests.cs @@ -15,7 +15,7 @@ public class MonitorTests public void Equals_EqualMonitors_ShouldReturnTrue() { // Prepare - var monitor1 = new Monitor + var monitor1 = new Domain.WinApi.Monitor { Size = 1, MonitorSize = new Rect { Left = 1, Top = 2, Right = 3, Bottom = 4 }, @@ -23,7 +23,7 @@ public void Equals_EqualMonitors_ShouldReturnTrue() Flags = 1, MonitorHandle = (IntPtr)1 }; - var monitor2 = new Monitor + var monitor2 = new Domain.WinApi.Monitor { Size = 1, MonitorSize = new Rect { Left = 1, Top = 2, Right = 3, Bottom = 4 }, @@ -40,7 +40,7 @@ public void Equals_EqualMonitors_ShouldReturnTrue() public void Equals_UnEqualMonitors_ShouldReturnFalse() { // Prepare - var monitor1 = new Monitor + var monitor1 = new Domain.WinApi.Monitor { Size = 1, MonitorSize = new Rect { Left = 1, Top = 2, Right = 3, Bottom = 4 }, @@ -48,7 +48,7 @@ public void Equals_UnEqualMonitors_ShouldReturnFalse() Flags = 1, MonitorHandle = (IntPtr)1 }; - var monitor2 = new Monitor + var monitor2 = new Domain.WinApi.Monitor { Size = 2, MonitorSize = new Rect { Left = 1, Top = 2, Right = 3, Bottom = 4 }, @@ -65,7 +65,7 @@ public void Equals_UnEqualMonitors_ShouldReturnFalse() public void Equals_InvalidType_ShouldReturnFalse() { // Prepare - var monitor = new Monitor + var monitor = new Domain.WinApi.Monitor { Size = 1, MonitorSize = new Rect { Left = 1, Top = 2, Right = 3, Bottom = 4 }, diff --git a/src/Tests/WinReform.Domain.Tests/WinReform.Domain.Tests.csproj b/src/Tests/WinReform.Domain.Tests/WinReform.Domain.Tests.csproj index 75ef010..232aabd 100644 --- a/src/Tests/WinReform.Domain.Tests/WinReform.Domain.Tests.csproj +++ b/src/Tests/WinReform.Domain.Tests/WinReform.Domain.Tests.csproj @@ -1,9 +1,10 @@  - netcoreapp3.1 - false + net8.0-windows + enable enable + false diff --git a/src/Tests/WinReform.Tests.Fixtures/WinReform.Tests.Fixtures.csproj b/src/Tests/WinReform.Tests.Fixtures/WinReform.Tests.Fixtures.csproj index 0444e77..8aa8652 100644 --- a/src/Tests/WinReform.Tests.Fixtures/WinReform.Tests.Fixtures.csproj +++ b/src/Tests/WinReform.Tests.Fixtures/WinReform.Tests.Fixtures.csproj @@ -1,7 +1,9 @@ - netcoreapp3.1 + net8.0-windows + enable + enable diff --git a/src/Tests/WinReform.Tests.Process.Fixture/Program.cs b/src/Tests/WinReform.Tests.Process.Fixture/Program.cs index 614ef46..bf04a55 100644 --- a/src/Tests/WinReform.Tests.Process.Fixture/Program.cs +++ b/src/Tests/WinReform.Tests.Process.Fixture/Program.cs @@ -12,7 +12,7 @@ internal class Program /// /// that triggers an automatic close of the application /// - private static Timer s_autoCloseTimer; + private static System.Timers.Timer s_autoCloseTimer; /// /// Entry point of the application @@ -20,7 +20,7 @@ internal class Program /// Arguments passed on startup private static void Main() { - s_autoCloseTimer = new Timer(20000); // 20 seconds + s_autoCloseTimer = new System.Timers.Timer(20000); // 20 seconds s_autoCloseTimer.Elapsed += OnAutoCloseTimer; s_autoCloseTimer.Start(); diff --git a/src/Tests/WinReform.Tests.Process.Fixture/WinReform.Tests.Process.Fixture.csproj b/src/Tests/WinReform.Tests.Process.Fixture/WinReform.Tests.Process.Fixture.csproj index c73e0d1..4de3eff 100644 --- a/src/Tests/WinReform.Tests.Process.Fixture/WinReform.Tests.Process.Fixture.csproj +++ b/src/Tests/WinReform.Tests.Process.Fixture/WinReform.Tests.Process.Fixture.csproj @@ -1,8 +1,10 @@ + net8.0-windows + enable + enable Exe - netcoreapp3.1 diff --git a/src/Tests/WinReform.Tests.WindowProcess.Fixture/App.xaml.cs b/src/Tests/WinReform.Tests.WindowProcess.Fixture/App.xaml.cs index c612429..00b1011 100644 --- a/src/Tests/WinReform.Tests.WindowProcess.Fixture/App.xaml.cs +++ b/src/Tests/WinReform.Tests.WindowProcess.Fixture/App.xaml.cs @@ -13,7 +13,7 @@ public partial class App : Application /// /// that triggers an automatic close of the application /// - private Timer _autoCloseTimer; + private System.Timers.Timer _autoCloseTimer; /// /// Sets up the project @@ -23,7 +23,7 @@ protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); - _autoCloseTimer = new Timer(20000); // 20 seconds + _autoCloseTimer = new System.Timers.Timer(20000); // 20 seconds _autoCloseTimer.Elapsed += OnAutoCloseTimer; _autoCloseTimer.Start(); diff --git a/src/Tests/WinReform.Tests.WindowProcess.Fixture/WinReform.Tests.WindowProcess.Fixture.csproj b/src/Tests/WinReform.Tests.WindowProcess.Fixture/WinReform.Tests.WindowProcess.Fixture.csproj index 6c68d0e..5a5f9a8 100644 --- a/src/Tests/WinReform.Tests.WindowProcess.Fixture/WinReform.Tests.WindowProcess.Fixture.csproj +++ b/src/Tests/WinReform.Tests.WindowProcess.Fixture/WinReform.Tests.WindowProcess.Fixture.csproj @@ -1,8 +1,10 @@  + net8.0-windows + enable + enable WinExe - netcoreapp3.1 true diff --git a/src/Tests/WinReform.Tests/WinReform.Tests.csproj b/src/Tests/WinReform.Tests/WinReform.Tests.csproj index ebd0ae6..da2a904 100644 --- a/src/Tests/WinReform.Tests/WinReform.Tests.csproj +++ b/src/Tests/WinReform.Tests/WinReform.Tests.csproj @@ -1,9 +1,10 @@  - netcoreapp3.1 - false + net8.0-windows + enable enable + false diff --git a/src/WinReform/WinReform.Domain/WinReform.Domain.csproj b/src/WinReform/WinReform.Domain/WinReform.Domain.csproj index 803b3fc..8cc5da9 100644 --- a/src/WinReform/WinReform.Domain/WinReform.Domain.csproj +++ b/src/WinReform/WinReform.Domain/WinReform.Domain.csproj @@ -1,7 +1,8 @@  - netcoreapp3.1 + net8.0-windows + enable enable diff --git a/src/WinReform/WinReform/WinReform.csproj b/src/WinReform/WinReform/WinReform.csproj index efee242..72485fd 100644 --- a/src/WinReform/WinReform/WinReform.csproj +++ b/src/WinReform/WinReform/WinReform.csproj @@ -1,10 +1,11 @@  + net8.0-windows + enable + enable WinExe - netcoreapp3.1 true - enable app.manifest logo.ico WinReform From 99c022af1bebd0a351ffd0fcdea05417a82c6e59 Mon Sep 17 00:00:00 2001 From: AKruimink <43521957+AKruimink@users.noreply.github.com> Date: Fri, 6 Sep 2024 00:41:10 +0100 Subject: [PATCH 2/4] Fixed all the warnings that came up --- .../Messenger/EventBaseTests.cs | 2 +- .../Messenger/EventSubscriptionTests.cs | 43 +++--- .../Messenger/PubSubEventTests.cs | 68 +++++---- .../Infrastructure/Model/ModelBaseTests.cs | 8 +- .../WinReform.Domain.Tests.csproj | 16 ++- .../WinReform.Tests.Fixtures/ModelFixture.cs | 136 ++++++++++++++++-- .../Program.cs | 63 ++++---- .../App.xaml.cs | 26 ++-- ...nReform.Tests.WindowProcess.Fixture.csproj | 1 + .../WinReform.Tests/WinReform.Tests.csproj | 16 ++- .../WinReform.Domain/Settings/SettingStore.cs | 9 +- .../WinReform.Domain/WinReform.Domain.csproj | 2 +- .../WinReform.Domain/Windows/WindowService.cs | 16 ++- .../ActiveWindows/ActiveWindowsViewModel.cs | 18 ++- .../Infrastructure/Command/DelegateCommand.cs | 41 ++++-- .../Command/DelegateCommandBase.cs | 10 +- .../ObservableCollectionExtensions.cs | 30 ++-- src/WinReform/WinReform/WinReform.csproj | 9 +- 18 files changed, 358 insertions(+), 156 deletions(-) diff --git a/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/EventBaseTests.cs b/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/EventBaseTests.cs index deb3e8f..e5f86d7 100644 --- a/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/EventBaseTests.cs +++ b/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/EventBaseTests.cs @@ -106,7 +106,7 @@ public void InternalPublish_NullReference_ShouldPruneStratagies() // Prepare var eventBase = new EventFixture(); var eventSubscriptionMock = new Mock(); - eventSubscriptionMock.Setup(x => x.GetExecutionStrategy()).Returns(null); + eventSubscriptionMock.Setup(x => x.GetExecutionStrategy()).Returns(null!); eventSubscriptionMock.SetupAllProperties(); var token = eventBase.Subscribe(eventSubscriptionMock.Object); diff --git a/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/EventSubscriptionTests.cs b/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/EventSubscriptionTests.cs index 222fee7..80fe38b 100644 --- a/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/EventSubscriptionTests.cs +++ b/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/EventSubscriptionTests.cs @@ -1,5 +1,4 @@ -using System; -using Moq; +using Moq; using WinReform.Domain.Infrastructure.Messenger; using WinReform.Domain.Infrastructure.Messenger.Strategies; using Xunit; @@ -19,7 +18,7 @@ public void ConstructNonGeneric_NullActionReference_ShouldThrowArgumentNullExcep // Assert Assert.Throws(() => { - var eventSubscription = new EventSubscription(null!); + _ = new EventSubscription(null!); }); } @@ -33,7 +32,7 @@ public void ConstructGeneric_NullActionReference_ShouldThrowArgumentNullExceptio // Assert Assert.Throws(() => { - var eventSubscription = new EventSubscription(null!, delegateReferenceMock.Object); + _ = new EventSubscription(null!, delegateReferenceMock.Object); }); } @@ -47,7 +46,7 @@ public void ConstructGeneric_NullFilterReference_ShouldThrowArgumentNullExceptio // Assert Assert.Throws(() => { - var eventSubscription = new EventSubscription(delegateReferenceMock.Object, null!); + _ = new EventSubscription(delegateReferenceMock.Object, null!); }); } @@ -56,12 +55,12 @@ public void ConstructNonGeneric_NullAction_ShouldThrowArgumentException() { // Prepare var delegateReferenceMock = new Mock(); - delegateReferenceMock.Setup(x => x.Delegate).Returns(null); + delegateReferenceMock.Setup(x => x.Delegate).Returns(null!); // Assert Assert.Throws(() => { - var eventSubscription = new EventSubscription(delegateReferenceMock.Object); + _ = new EventSubscription(delegateReferenceMock.Object); }); } @@ -70,14 +69,14 @@ public void ConstructGeneric_NullAction_ShouldThrowArgumentException() { // Prepare var delegateActionReferenceMock = new Mock(); - delegateActionReferenceMock.Setup(x => x.Delegate).Returns(null); + delegateActionReferenceMock.Setup(x => x.Delegate).Returns(null!); var delegateFilterReferenceMock = new Mock(); delegateFilterReferenceMock.Setup(x => x.Delegate).Returns((Predicate)delegate { return true; }); // Assert Assert.Throws(() => { - var eventSubscription = new EventSubscription(delegateActionReferenceMock.Object, delegateFilterReferenceMock.Object); + _ = new EventSubscription(delegateActionReferenceMock.Object, delegateFilterReferenceMock.Object); }); } @@ -88,12 +87,12 @@ public void ConstructGeneric_NullFilter_ShouldThrowArgumentException() var delegateActionReferenceMock = new Mock(); delegateActionReferenceMock.Setup(x => x.Delegate).Returns((Action)delegate { }); var delegateFilterReferenceMock = new Mock(); - delegateFilterReferenceMock.Setup(x => x.Delegate).Returns(null); + delegateFilterReferenceMock.Setup(x => x.Delegate).Returns(null!); // Assert Assert.Throws(() => { - var eventSubscription = new EventSubscription(delegateActionReferenceMock.Object, delegateFilterReferenceMock.Object); + _ = new EventSubscription(delegateActionReferenceMock.Object, delegateFilterReferenceMock.Object); }); } @@ -107,7 +106,7 @@ public void ConstructNonGeneric_DifferentTargetTypeActionReference_ShouldThrowAr // Assert Assert.Throws(() => { - var eventSubscription = new EventSubscription(delegateActionReferenceMock.Object); + _ = new EventSubscription(delegateActionReferenceMock.Object); }); } @@ -123,7 +122,7 @@ public void ConstructGeneric_DifferentTargetTypeActionReference_ShouldThrowArgum // Assert Assert.Throws(() => { - var eventSubscription = new EventSubscription(delegateActionReferenceMock.Object, delegateFilterReferenceMock.Object); + _ = new EventSubscription(delegateActionReferenceMock.Object, delegateFilterReferenceMock.Object); }); } @@ -139,7 +138,7 @@ public void ConstructGeneric_DifferentTargetTypeFilterReference_ShouldThrowArgum // Assert Assert.Throws(() => { - var eventSubscription = new EventSubscription(delegateActionReferenceMock.Object, delegateFilterReferenceMock.Object); + _ = new EventSubscription(delegateActionReferenceMock.Object, delegateFilterReferenceMock.Object); }); } @@ -206,7 +205,7 @@ public void GetActionNonGeneric_NullAction_ShouldReturnNull() Assert.NotNull(publishAction); // Act - delegateActionReferenceMock.Setup(x => x.Delegate).Returns(null); + delegateActionReferenceMock.Setup(x => x.Delegate).Returns(null!); publishAction = eventSubscription.GetExecutionStrategy(); // Assert @@ -232,7 +231,7 @@ public void GetActionGeneric_NullAction_ShouldReturnNull() Assert.NotNull(publishAction); // Act - delegateActionReferenceMock.Setup(x => x.Delegate).Returns(null); + delegateActionReferenceMock.Setup(x => x.Delegate).Returns(null!); publishAction = eventSubscription.GetExecutionStrategy(); // Assert @@ -267,7 +266,9 @@ public void GetExecutionStrategyGeneric_PassArgument_ShouldPassArgumentToDelegat } [Fact] - public void GetExecutionStrategyNonGeneric_NullAction_ShouldReturnNull() +#pragma warning disable S4144 // Methods should not have identical implementations + public void GetExecutionStrategy_NonGenericAction_ShouldReturnNull() +#pragma warning restore S4144 // Methods should not have identical implementations { // Prepare var delegateActionReferenceMock = new Mock(); @@ -283,7 +284,7 @@ public void GetExecutionStrategyNonGeneric_NullAction_ShouldReturnNull() Assert.NotNull(publishAction); // Act - delegateActionReferenceMock.Setup(x => x.Delegate).Returns(null); + delegateActionReferenceMock.Setup(x => x.Delegate).Returns(null!); publishAction = eventSubscription.GetExecutionStrategy(); // Assert @@ -291,7 +292,7 @@ public void GetExecutionStrategyNonGeneric_NullAction_ShouldReturnNull() } [Fact] - public void GetExecutionStrategyGeneric_NullAction_ShouldReturnNull() + public void GetExecutionStrategy_GenericAction_ShouldReturnNull() { // Prepare var delegateActionReferenceMock = new Mock(); @@ -309,7 +310,7 @@ public void GetExecutionStrategyGeneric_NullAction_ShouldReturnNull() Assert.NotNull(publishAction); // Act - delegateActionReferenceMock.Setup(x => x.Delegate).Returns(null); + delegateActionReferenceMock.Setup(x => x.Delegate).Returns(null!); publishAction = eventSubscription.GetExecutionStrategy(); // Assert @@ -335,7 +336,7 @@ public void GetExecutionStrategyGeneric_NullFilter_ShouldReturnNull() Assert.NotNull(publishAction); // Act - delegateFilterReferenceMock.Setup(x => x.Delegate).Returns(null); + delegateFilterReferenceMock.Setup(x => x.Delegate).Returns(null!); publishAction = eventSubscription.GetExecutionStrategy(); // Assert diff --git a/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/PubSubEventTests.cs b/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/PubSubEventTests.cs index 93a17ce..2c95421 100644 --- a/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/PubSubEventTests.cs +++ b/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/PubSubEventTests.cs @@ -38,14 +38,18 @@ private class PubSubEventFixture : PubSubEvent public void SubscribeNonGeneric_DefaultThread_ShouldPublishOnSubscriberThread() { // Prepare - static void ActionReference() { } + static void ActionReference() + { + // Method intentionally left empty. + } + var pubsubEvent = new PubSubEventFixture(); // Act - var token = pubsubEvent.Subscribe(ActionReference); + _ = pubsubEvent.Subscribe(ActionReference); // Assert - Assert.Equal(1, pubsubEvent.CurrentSubscriptions.Count); + Assert.Single(pubsubEvent.CurrentSubscriptions); Assert.Equal(typeof(EventSubscription), pubsubEvent.CurrentSubscriptions.ElementAt(0).GetType()); } @@ -53,14 +57,18 @@ static void ActionReference() { } public void SubscribeGeneric_DefaultThread_ShouldPublishOnSubscriberThread() { // Prepare - static void ActionReference(string arg) { } + static void ActionReference(string arg) + { + // Method intentionally left empty. + } + var pubsubEvent = new PubSubEventFixture(); // Act - var token = pubsubEvent.Subscribe(ActionReference); + _ = pubsubEvent.Subscribe(ActionReference); // Assert - Assert.Equal(1, pubsubEvent.CurrentSubscriptions.Count); + Assert.Single(pubsubEvent.CurrentSubscriptions); Assert.Equal(typeof(EventSubscription), pubsubEvent.CurrentSubscriptions.ElementAt(0).GetType()); } @@ -68,7 +76,11 @@ static void ActionReference(string arg) { } public void Subscribe_DefaultFilter_ShouldReturnTrue() { // Prepare - static void ActionReference(string arg) { } + static void ActionReference(string arg) + { + // Method intentionally left empty. + } + var pubSubEvent = new PubSubEventFixture(); // Act @@ -89,9 +101,13 @@ static void ActionReference(string arg) { } public void UnsubscribeNonGeneric_UnsubscribeByAction_ShouldUnsubscribe() { // Prepare - static void ActionReference() { } + static void ActionReference() + { + // Method intentionally left empty. + } + var pubSubEvent = new PubSubEventFixture(); - var token = pubSubEvent.Subscribe(ActionReference); + _ = pubSubEvent.Subscribe(ActionReference); // Assert Assert.True(pubSubEvent.Contains(ActionReference)); @@ -107,9 +123,13 @@ static void ActionReference() { } public void UnsubscribeGeneric_UnsubscribeByAction_ShouldUnsubscribe() { // Prepare - static void ActionReference(string arg) { } + static void ActionReference(string arg) + { + // Method intentionally left empty. + } + var pubSubEvent = new PubSubEventFixture(); - var token = pubSubEvent.Subscribe(ActionReference); + _ = pubSubEvent.Subscribe(ActionReference); // Assert Assert.True(pubSubEvent.Contains(ActionReference)); @@ -123,25 +143,19 @@ static void ActionReference(string arg) { } #endregion Unsubscribe Tests - #region Publish Tests - - [Fact] - public void PublishGeneric_NullArgument_ShouldThrowNullArgumentException() - { - // Prepare - } - - #endregion Publish Tests - #region Contains Tests [Fact] public void ContainsNonGeneric_SearchByAction_ShouldFindSubscriber() { // Prepare - static void ActionReference() { } + static void ActionReference() + { + // Method intentionally left empty. + } + var pubSubEvent = new PubSubEventFixture(); - var token = pubSubEvent.Subscribe(ActionReference); + _ = pubSubEvent.Subscribe(ActionReference); // Assert Assert.True(pubSubEvent.Contains(ActionReference)); @@ -151,9 +165,13 @@ static void ActionReference() { } public void ContainsGeneric_SearchByAction_ShouldFindSubscriber() { // Prepare - static void ActionReference(string arg) { } + static void ActionReference(string arg) + { + // Method intentionally left empty. + } + var pubSubEvent = new PubSubEventFixture(); - var token = pubSubEvent.Subscribe(ActionReference); + _ = pubSubEvent.Subscribe(ActionReference); // Assert Assert.True(pubSubEvent.Contains(ActionReference)); diff --git a/src/Tests/WinReform.Domain.Tests/Infrastructure/Model/ModelBaseTests.cs b/src/Tests/WinReform.Domain.Tests/Infrastructure/Model/ModelBaseTests.cs index 01cc2d6..a96123e 100644 --- a/src/Tests/WinReform.Domain.Tests/Infrastructure/Model/ModelBaseTests.cs +++ b/src/Tests/WinReform.Domain.Tests/Infrastructure/Model/ModelBaseTests.cs @@ -57,7 +57,7 @@ public void SetProperty_UnchangedValue_ShouldNotSet() modelFixture.PropertyChanged += (o, e) => { // Act - if (e.PropertyName.Equals(nameof(modelFixture.Number))) + if (e.PropertyName != null && e.PropertyName.Equals(nameof(modelFixture.Number))) { invoked = true; } @@ -81,7 +81,7 @@ public void SetProperty_NewValue_ShouldRaisePropertyChanged() modelFixture.PropertyChanged += (o, e) => { // Act - if (e.PropertyName.Equals(nameof(modelFixture.Number))) + if (e.PropertyName != null && e.PropertyName.Equals(nameof(modelFixture.Number))) { invoked = true; } @@ -103,7 +103,7 @@ public void SetProperty_PropertyDependency_ShouldRaisePropertyChanged() modelFixture.PropertyChanged += (o, e) => { // Act - if (e.PropertyName.Equals(nameof(modelFixture.TextDependency))) + if (e.PropertyName != null && e.PropertyName.Equals(nameof(modelFixture.TextDependency))) { invoked = true; } @@ -129,7 +129,7 @@ public void OnPropertyChanged_Raised_ShouldExtractPropertyName() modelFixture.PropertyChanged += (o, e) => { // Act - if (e.PropertyName.Equals(nameof(modelFixture.Number))) + if (e.PropertyName != null && e.PropertyName.Equals(nameof(modelFixture.Number))) { invoked = true; } diff --git a/src/Tests/WinReform.Domain.Tests/WinReform.Domain.Tests.csproj b/src/Tests/WinReform.Domain.Tests/WinReform.Domain.Tests.csproj index 232aabd..ecebc5b 100644 --- a/src/Tests/WinReform.Domain.Tests/WinReform.Domain.Tests.csproj +++ b/src/Tests/WinReform.Domain.Tests/WinReform.Domain.Tests.csproj @@ -8,11 +8,17 @@ - - - - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Tests/WinReform.Tests.Fixtures/ModelFixture.cs b/src/Tests/WinReform.Tests.Fixtures/ModelFixture.cs index 3722774..e3f8ff4 100644 --- a/src/Tests/WinReform.Tests.Fixtures/ModelFixture.cs +++ b/src/Tests/WinReform.Tests.Fixtures/ModelFixture.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; +using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using WinReform.Domain.Infrastructure.Attributes; using WinReform.Domain.Infrastructure.Model; @@ -10,7 +8,7 @@ namespace WinReform.Tests.Fixtures /// /// Defines a class that represents a model fixture that provides a fake model properties for testing puprose /// - public class ModelFixture : ModelBase, IEquatable, IComparable + public sealed class ModelFixture : ModelBase, IEquatable, IComparable, IEqualityComparer { /// /// Gets or Sets the identifier of the model @@ -66,16 +64,6 @@ public void InvokePropertyChanged(string propertyName) /// Returns containing all property names that rely on the given property names public List GetPropertyDependencies(string propertyName) => PropertyDependencies[propertyName]; - /// - /// Compares a given to the current - /// - /// to compare - /// Returns if both are equal, otherwise returns - public bool Equals([AllowNull] ModelFixture obj) - => obj?.Id == Id - && obj?.Text == Text - && obj?.Number == Number; - /// /// Compares if a given represents the same as the current instance /// @@ -96,15 +84,133 @@ public int CompareTo([AllowNull] ModelFixture obj) /// to compare /// Returns if the is equal to the current , otherwise returns /// - public override bool Equals(object obj) + public override bool Equals(object? obj) => obj is ModelFixture fixture && Equals(fixture); + /// + /// Compares a given to the current + /// + /// to compare + /// Returns if both are equal, otherwise returns + public bool Equals([AllowNull] ModelFixture obj) + => obj?.Id == Id + && obj.Text == Text + && obj.Number == Number; + + /// + /// Checks if two instances are equal. + /// + /// The left to compare. + /// The right to compare. + /// Returns if both instances are equal; otherwise, . + public static bool operator ==(ModelFixture left, ModelFixture right) + { + // Handle null comparisons + if (ReferenceEquals(left, right)) + return true; + if (left is null || right is null) + return false; + + return left.Equals(right); // Use the instance Equals method + } + + /// + /// Checks if two instances are not equal. + /// + /// The left to compare. + /// The right to compare. + /// Returns if the instances are not equal; otherwise, . + public static bool operator !=(ModelFixture left, ModelFixture right) + { + return !(left == right); // Use the == operator to simplify logic + } + + /// + /// Checks if the left is less than the right . + /// + /// The left to compare. + /// The right to compare. + /// Returns if the left instance is less than the right; otherwise, . + public static bool operator <(ModelFixture left, ModelFixture right) + { + if (left is null && right is null) return false; + if (left is null) return true; + if (right is null) return false; + + return left.CompareTo(right) < 0; + } + + /// + /// Checks if the left is greater than the right . + /// + /// The left to compare. + /// The right to compare. + /// Returns if the left instance is greater than the right; otherwise, . + public static bool operator >(ModelFixture left, ModelFixture right) + { + if (left is null && right is null) return false; + if (right is null) return true; + if (left is null) return false; + + return left.CompareTo(right) > 0; + } + + /// + /// Checks if the left is less than or equal to the right . + /// + /// The left to compare. + /// The right to compare. + /// Returns if the left instance is less than or equal to the right; otherwise, . + public static bool operator <=(ModelFixture left, ModelFixture right) + { + return left == right || left < right; + } + + /// + /// Checks if the left is greater than or equal to the right . + /// + /// The left to compare. + /// The right to compare. + /// Returns if the left instance is greater than or equal to the right; otherwise, . + public static bool operator >=(ModelFixture left, ModelFixture right) + { + return left == right || left > right; + } + /// /// Gets the hashcode of the /// /// Returns containing a unique hashcode that represents the instance of the current public override int GetHashCode() => (Id, Text, Number).GetHashCode(); + + /// + /// Determines whether the specified instances are equal. + /// + /// The first to compare. + /// The second to compare. + /// + /// Returns if the specified instances are equal; otherwise, . + /// + public bool Equals(ModelFixture? x, ModelFixture? y) + { + if (x is null && y is null) return true; + if (x is null || y is null) return false; + return x.Id == y.Id && x.Text == y.Text && x.Number == y.Number; + } + + /// + /// Returns a hash code for the specified . + /// + /// The for which a hash code is to be returned. Cannot be . + /// + /// A hash code for the specified . + /// + /// Thrown if is . + public int GetHashCode([DisallowNull] ModelFixture obj) + { + return (obj.Id, obj.Text, obj.Number).GetHashCode(); + } } } diff --git a/src/Tests/WinReform.Tests.Process.Fixture/Program.cs b/src/Tests/WinReform.Tests.Process.Fixture/Program.cs index bf04a55..7ca79da 100644 --- a/src/Tests/WinReform.Tests.Process.Fixture/Program.cs +++ b/src/Tests/WinReform.Tests.Process.Fixture/Program.cs @@ -1,42 +1,51 @@ -using System; -using System.Timers; +using System.Timers; -namespace WinReform.Tests.Process.Fixture +namespace WinReform.Tests.Process.Fixture; + +/// +/// Defines a class that represents a fixture of a process without a window +/// NOTE: The application automatically closes after x seconds, this to make sure that if the test failed and the dispose isn't triggered the app won't linger in the background forever. +/// +internal static class Program { /// - /// Defines a class that represents a fixture of a process without a window - /// NOTE: The application automaticly closes after x seconds, this to make sure that if the test failed and the dispose isnt't triggered the app wont linger in the background forever + /// that triggers an automatic close of the application + /// + private static System.Timers.Timer? s_autoCloseTimer; + + /// + /// Entry point of the application /// - internal class Program + /// Arguments passed on startup + private static void Main() { - /// - /// that triggers an automatic close of the application - /// - private static System.Timers.Timer s_autoCloseTimer; + s_autoCloseTimer = new System.Timers.Timer(20000); // 20 seconds + s_autoCloseTimer.Elapsed += OnAutoCloseTimer; + s_autoCloseTimer.Start(); - /// - /// Entry point of the application - /// - /// Arguments passed on startup - private static void Main() - { - s_autoCloseTimer = new System.Timers.Timer(20000); // 20 seconds - s_autoCloseTimer.Elapsed += OnAutoCloseTimer; - s_autoCloseTimer.Start(); + Console.ReadKey(); + } - Console.ReadKey(); + /// + /// Raised when the elapsed and automatically closes the application. + /// + /// The source of the event. + /// An that contains the event data. + private static void OnAutoCloseTimer(object? sender, ElapsedEventArgs e) + { + if (sender == null) + { + return; } - /// - /// Raised when the elapsed and automaticly closes the application - /// - /// - /// - private static void OnAutoCloseTimer(object sender, ElapsedEventArgs e) + // Safely dispose of the timer only if it's not null + if (s_autoCloseTimer != null) { s_autoCloseTimer.Close(); s_autoCloseTimer.Dispose(); - Environment.Exit(0); + s_autoCloseTimer = null; } + + Environment.Exit(0); } } diff --git a/src/Tests/WinReform.Tests.WindowProcess.Fixture/App.xaml.cs b/src/Tests/WinReform.Tests.WindowProcess.Fixture/App.xaml.cs index 00b1011..7bd2800 100644 --- a/src/Tests/WinReform.Tests.WindowProcess.Fixture/App.xaml.cs +++ b/src/Tests/WinReform.Tests.WindowProcess.Fixture/App.xaml.cs @@ -6,14 +6,14 @@ namespace WinReform.Tests.WindowProcess.Fixture { /// /// Defines a class that represents a fixture of a process with a window - /// NOTE: The application automaticly closes after x seconds, this to make sure that if the test failed and the dispose isnt't triggered the app wont linger in the background forever + /// NOTE: The application automatically closes after x seconds, this to make sure that if the test failed and the dispose isn't triggered the app won't linger in the background forever. /// public partial class App : Application { /// /// that triggers an automatic close of the application /// - private System.Timers.Timer _autoCloseTimer; + private System.Timers.Timer? _autoCloseTimer; /// /// Sets up the project @@ -32,14 +32,24 @@ protected override void OnStartup(StartupEventArgs e) } /// - /// Raised when the elapsed and automaticly closes the application + /// Raised when the elapsed and automatically closes the application /// - /// - /// - private void OnAutoCloseTimer(object sender, ElapsedEventArgs e) + /// The source of the event. + /// An that contains the event data. + private void OnAutoCloseTimer(object? sender, ElapsedEventArgs e) { - _autoCloseTimer.Close(); - _autoCloseTimer.Dispose(); + if(sender == null) + { + return; + } + + if (_autoCloseTimer != null) + { + _autoCloseTimer.Close(); + _autoCloseTimer.Dispose(); + _autoCloseTimer = null; + } + Environment.Exit(0); } } diff --git a/src/Tests/WinReform.Tests.WindowProcess.Fixture/WinReform.Tests.WindowProcess.Fixture.csproj b/src/Tests/WinReform.Tests.WindowProcess.Fixture/WinReform.Tests.WindowProcess.Fixture.csproj index 5a5f9a8..1c11cd7 100644 --- a/src/Tests/WinReform.Tests.WindowProcess.Fixture/WinReform.Tests.WindowProcess.Fixture.csproj +++ b/src/Tests/WinReform.Tests.WindowProcess.Fixture/WinReform.Tests.WindowProcess.Fixture.csproj @@ -6,6 +6,7 @@ enable WinExe true + $(NoWarn);NETSDK1137 \ No newline at end of file diff --git a/src/Tests/WinReform.Tests/WinReform.Tests.csproj b/src/Tests/WinReform.Tests/WinReform.Tests.csproj index da2a904..e16c72c 100644 --- a/src/Tests/WinReform.Tests/WinReform.Tests.csproj +++ b/src/Tests/WinReform.Tests/WinReform.Tests.csproj @@ -14,11 +14,17 @@ - - - - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/WinReform/WinReform.Domain/Settings/SettingStore.cs b/src/WinReform/WinReform.Domain/Settings/SettingStore.cs index 8794a7d..ec70d29 100644 --- a/src/WinReform/WinReform.Domain/Settings/SettingStore.cs +++ b/src/WinReform/WinReform.Domain/Settings/SettingStore.cs @@ -48,7 +48,7 @@ public SettingStore() WriteIndented = true }; - return JsonSerializer.Deserialize(settingString, serializerOptions); + return JsonSerializer.Deserialize(settingString, serializerOptions) ?? new TSetting(); } /// @@ -56,12 +56,17 @@ public void Save(TSetting settings) { var file = Path.Combine(_filePath, $"{typeof(TSetting).Name}.json"); var fileInfo = new FileInfo(file); - fileInfo.Directory.Create(); + + if (fileInfo.Directory != null && !fileInfo.Directory.Exists) + { + fileInfo.Directory.Create(); + } var serializerOptions = new JsonSerializerOptions { WriteIndented = true }; + var json = JsonSerializer.Serialize(settings, serializerOptions); File.WriteAllText(file, json); } diff --git a/src/WinReform/WinReform.Domain/WinReform.Domain.csproj b/src/WinReform/WinReform.Domain/WinReform.Domain.csproj index 8cc5da9..3acc2da 100644 --- a/src/WinReform/WinReform.Domain/WinReform.Domain.csproj +++ b/src/WinReform/WinReform.Domain/WinReform.Domain.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/WinReform/WinReform.Domain/Windows/WindowService.cs b/src/WinReform/WinReform.Domain/Windows/WindowService.cs index 17bddd4..31feea6 100644 --- a/src/WinReform/WinReform.Domain/Windows/WindowService.cs +++ b/src/WinReform/WinReform.Domain/Windows/WindowService.cs @@ -50,23 +50,33 @@ public IEnumerable GetActiveWindows() } var dimensions = _winApiService.GetWindowRect(process.MainWindowHandle); - if(dimensions.IsEmpty) + if (dimensions.IsEmpty) { continue; // Has a 0 by 0 window, and not meant to display } + Bitmap? iconBitmap = default; + if (process.MainModule?.FileName != null && File.Exists(process.MainModule.FileName)) + { + var icon = Icon.ExtractAssociatedIcon(process.MainModule.FileName); + if (icon != null) + { + iconBitmap = icon.ToBitmap(); + } + } + windows.Add(new Window() { Id = process.Id, WindowHandle = process.MainWindowHandle, Description = process.MainModule?.FileVersionInfo.FileDescription ?? string.Empty, - Icon = Icon.ExtractAssociatedIcon(process.MainModule?.FileName).ToBitmap(), + Icon = iconBitmap, Dimensions = dimensions }); } catch (Win32Exception) { - continue; + // Do nothing } } diff --git a/src/WinReform/WinReform/ActiveWindows/ActiveWindowsViewModel.cs b/src/WinReform/WinReform/ActiveWindows/ActiveWindowsViewModel.cs index f780d3c..9c5404d 100644 --- a/src/WinReform/WinReform/ActiveWindows/ActiveWindowsViewModel.cs +++ b/src/WinReform/WinReform/ActiveWindows/ActiveWindowsViewModel.cs @@ -1,9 +1,6 @@ -using System; -using System.Collections.ObjectModel; +using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; -using System.Linq; -using System.Threading.Tasks; using System.Windows; using System.Windows.Data; using System.Windows.Threading; @@ -135,9 +132,18 @@ public ActiveWindowsViewModel(IEventAggregator eventAggregator, IWindowService w } /// - /// Disposes of all event handlers + /// Disposes of the view model /// public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Disposes of all event handlers + /// + protected virtual void Dispose(bool disposing) { _autoRefreshTimer.Stop(); _autoRefreshTimer.Tick -= OnAutoRefreshEvent; @@ -189,7 +195,7 @@ private void ApplicationSettingsChanged(ISetting settings) /// /// /// - private void SelectedActiveWindowsChanged(object sender, NotifyCollectionChangedEventArgs e) + private void SelectedActiveWindowsChanged(object? sender, NotifyCollectionChangedEventArgs e) { _eventAggregator.GetEvent().Publish(SelectedActiveWindows.ToList()); } diff --git a/src/WinReform/WinReform/Infrastructure/Command/DelegateCommand.cs b/src/WinReform/WinReform/Infrastructure/Command/DelegateCommand.cs index 81f17df..ee5e457 100644 --- a/src/WinReform/WinReform/Infrastructure/Command/DelegateCommand.cs +++ b/src/WinReform/WinReform/Infrastructure/Command/DelegateCommand.cs @@ -59,13 +59,13 @@ public bool CanExecute() } /// - protected override void Execute(object parameter) + protected override void Execute(object? parameter) { Execute(); } /// - protected override bool CanExecute(object parameter) + protected override bool CanExecute(object? parameter) { return CanExecute(); } @@ -106,12 +106,9 @@ public DelegateCommand(Action executeMethod, Func? canExecuteMethod) } var typeInfo = typeof(T).GetTypeInfo(); - if (typeInfo.IsValueType) + if (typeInfo.IsValueType && (!typeInfo.IsGenericType || !typeof(Nullable<>).GetTypeInfo().IsAssignableFrom(typeInfo.GetGenericTypeDefinition().GetTypeInfo()))) { - if (!typeInfo.IsGenericType || !typeof(Nullable<>).GetTypeInfo().IsAssignableFrom(typeInfo.GetGenericTypeDefinition().GetTypeInfo())) - { - throw new InvalidCastException("Parameter type isnt a valid generic type"); - } + throw new InvalidCastException("Parameter type isnt a valid generic type"); } _executeMethod = executeMethod; @@ -138,15 +135,37 @@ public bool CanExecute(T parameter) } /// - protected override void Execute(object parameter) + protected override void Execute(object? parameter) { - Execute((T)parameter); + if (parameter is T typedParameter) + { + Execute(typedParameter); + } + else if (parameter == null && default(T) is null) + { + Execute(default!); + } + else + { + throw new ArgumentException($"Invalid parameter type. Expected {typeof(T)}, got {parameter?.GetType().Name ?? "null"}."); + } } /// - protected override bool CanExecute(object parameter) + protected override bool CanExecute(object? parameter) { - return CanExecute((T)parameter); + if (parameter is T typedParameter) + { + return CanExecute(typedParameter); + } + else if (parameter is null && default(T) is null) + { + return CanExecute(default!); + } + else + { + return false; + } } } } diff --git a/src/WinReform/WinReform/Infrastructure/Command/DelegateCommandBase.cs b/src/WinReform/WinReform/Infrastructure/Command/DelegateCommandBase.cs index 3045a9d..1f0528b 100644 --- a/src/WinReform/WinReform/Infrastructure/Command/DelegateCommandBase.cs +++ b/src/WinReform/WinReform/Infrastructure/Command/DelegateCommandBase.cs @@ -22,7 +22,7 @@ public abstract class DelegateCommandBase : ICommand /// /// A base command that provides base functionallity to a command /// - public DelegateCommandBase() + protected DelegateCommandBase() { _synchronizationContext = SynchronizationContext.Current; } @@ -31,7 +31,7 @@ public DelegateCommandBase() /// Executes the command /// /// Command parameter - void ICommand.Execute(object parameter) + void ICommand.Execute(object? parameter) { Execute(parameter); } @@ -41,7 +41,7 @@ void ICommand.Execute(object parameter) /// /// Data used to determine if the command can be executed /// Returns if the command can execute, otherwise - bool ICommand.CanExecute(object parameter) + bool ICommand.CanExecute(object? parameter) { return CanExecute(parameter); } @@ -59,13 +59,13 @@ public void RaiseCanExecuteChanged() /// /// Data used to determine if the command can be executed /// Returns if the command can execute, otherwise - protected abstract bool CanExecute(object parameter); + protected abstract bool CanExecute(object? parameter); /// /// Executes the command /// /// Command parameter - protected abstract void Execute(object parameter); + protected abstract void Execute(object? parameter); /// /// Raises the allowing every command to requery diff --git a/src/WinReform/WinReform/Infrastructure/Extensions/ObservableCollectionExtensions.cs b/src/WinReform/WinReform/Infrastructure/Extensions/ObservableCollectionExtensions.cs index 940e613..f346320 100644 --- a/src/WinReform/WinReform/Infrastructure/Extensions/ObservableCollectionExtensions.cs +++ b/src/WinReform/WinReform/Infrastructure/Extensions/ObservableCollectionExtensions.cs @@ -31,25 +31,29 @@ public static void UpdateCollection(this ObservableCollection collection, { if (collection.Count > i) { - var itemIndex = collection.IndexOf(collection.Where(i => Comparer.Default.Compare(i, item) == 0).FirstOrDefault()); + var existingItem = collection.FirstOrDefault(existing => Comparer.Default.Compare(existing, item) == 0); - if (itemIndex < 0) + if (existingItem == null! || existingItem.Equals(default(T))) { - // Item doesn't exist + // Item doesn't exist in the collection, so insert it collection.Insert(i, item); } - else if (itemIndex > i || itemIndex < i) - { - // Item exists, but has moved up or down - collection.Move(itemIndex, i); - } else { - if ((!collection[i]?.Equals(item)) ?? false) + // Get the index of the existing item, ensuring it's not null + var itemIndex = collection.IndexOf(existingItem); + + if (itemIndex != i) + { + // Item exists but is in the wrong place, so move it + collection.Move(itemIndex, i); + } + else { - // Item has changed, replace it - if (item != null) + // Check if the item has changed (considering nullability) + if (collection[i] is not null && item is not null && !collection[i]!.Equals(item)) { + // If the item has changed, copy properties foreach (var sourceProperty in item.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) { var targetProperty = collection[i]?.GetType().GetProperty(sourceProperty.Name); @@ -65,14 +69,14 @@ public static void UpdateCollection(this ObservableCollection collection, } else { - // Item doesn't exist + // Item doesn't exist in the collection, so add it collection.Add(item); } i++; } - // Remove all old items + // Remove any items left in the original collection that aren't in the new collection while (collection.Count > newCollection.Count) { collection.RemoveAt(i); diff --git a/src/WinReform/WinReform/WinReform.csproj b/src/WinReform/WinReform/WinReform.csproj index 72485fd..21f7224 100644 --- a/src/WinReform/WinReform/WinReform.csproj +++ b/src/WinReform/WinReform/WinReform.csproj @@ -9,6 +9,7 @@ app.manifest logo.ico WinReform + $(NoWarn);NETSDK1137 @@ -20,10 +21,10 @@ - - - - + + + + From 2fc04eda4e080655910999a63bc2d11c243ec535 Mon Sep 17 00:00:00 2001 From: AKruimink <43521957+AKruimink@users.noreply.github.com> Date: Fri, 6 Sep 2024 00:41:10 +0100 Subject: [PATCH 3/4] Updates Nuget packages and fixes all the warnings --- .../Messenger/EventBaseTests.cs | 2 +- .../Messenger/EventSubscriptionTests.cs | 43 +++--- .../Messenger/PubSubEventTests.cs | 68 +++++---- .../Infrastructure/Model/ModelBaseTests.cs | 8 +- .../WinReform.Domain.Tests.csproj | 16 ++- .../WinReform.Tests.Fixtures/ModelFixture.cs | 136 ++++++++++++++++-- .../Program.cs | 63 ++++---- .../App.xaml.cs | 26 ++-- ...nReform.Tests.WindowProcess.Fixture.csproj | 1 + .../WinReform.Tests/WinReform.Tests.csproj | 16 ++- .../WinReform.Domain/Settings/SettingStore.cs | 9 +- .../WinReform.Domain/WinReform.Domain.csproj | 2 +- .../WinReform.Domain/Windows/WindowService.cs | 16 ++- .../ActiveWindows/ActiveWindowsViewModel.cs | 18 ++- .../Infrastructure/Command/DelegateCommand.cs | 41 ++++-- .../Command/DelegateCommandBase.cs | 10 +- .../ObservableCollectionExtensions.cs | 30 ++-- src/WinReform/WinReform/WinReform.csproj | 9 +- 18 files changed, 358 insertions(+), 156 deletions(-) diff --git a/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/EventBaseTests.cs b/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/EventBaseTests.cs index deb3e8f..e5f86d7 100644 --- a/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/EventBaseTests.cs +++ b/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/EventBaseTests.cs @@ -106,7 +106,7 @@ public void InternalPublish_NullReference_ShouldPruneStratagies() // Prepare var eventBase = new EventFixture(); var eventSubscriptionMock = new Mock(); - eventSubscriptionMock.Setup(x => x.GetExecutionStrategy()).Returns(null); + eventSubscriptionMock.Setup(x => x.GetExecutionStrategy()).Returns(null!); eventSubscriptionMock.SetupAllProperties(); var token = eventBase.Subscribe(eventSubscriptionMock.Object); diff --git a/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/EventSubscriptionTests.cs b/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/EventSubscriptionTests.cs index 222fee7..80fe38b 100644 --- a/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/EventSubscriptionTests.cs +++ b/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/EventSubscriptionTests.cs @@ -1,5 +1,4 @@ -using System; -using Moq; +using Moq; using WinReform.Domain.Infrastructure.Messenger; using WinReform.Domain.Infrastructure.Messenger.Strategies; using Xunit; @@ -19,7 +18,7 @@ public void ConstructNonGeneric_NullActionReference_ShouldThrowArgumentNullExcep // Assert Assert.Throws(() => { - var eventSubscription = new EventSubscription(null!); + _ = new EventSubscription(null!); }); } @@ -33,7 +32,7 @@ public void ConstructGeneric_NullActionReference_ShouldThrowArgumentNullExceptio // Assert Assert.Throws(() => { - var eventSubscription = new EventSubscription(null!, delegateReferenceMock.Object); + _ = new EventSubscription(null!, delegateReferenceMock.Object); }); } @@ -47,7 +46,7 @@ public void ConstructGeneric_NullFilterReference_ShouldThrowArgumentNullExceptio // Assert Assert.Throws(() => { - var eventSubscription = new EventSubscription(delegateReferenceMock.Object, null!); + _ = new EventSubscription(delegateReferenceMock.Object, null!); }); } @@ -56,12 +55,12 @@ public void ConstructNonGeneric_NullAction_ShouldThrowArgumentException() { // Prepare var delegateReferenceMock = new Mock(); - delegateReferenceMock.Setup(x => x.Delegate).Returns(null); + delegateReferenceMock.Setup(x => x.Delegate).Returns(null!); // Assert Assert.Throws(() => { - var eventSubscription = new EventSubscription(delegateReferenceMock.Object); + _ = new EventSubscription(delegateReferenceMock.Object); }); } @@ -70,14 +69,14 @@ public void ConstructGeneric_NullAction_ShouldThrowArgumentException() { // Prepare var delegateActionReferenceMock = new Mock(); - delegateActionReferenceMock.Setup(x => x.Delegate).Returns(null); + delegateActionReferenceMock.Setup(x => x.Delegate).Returns(null!); var delegateFilterReferenceMock = new Mock(); delegateFilterReferenceMock.Setup(x => x.Delegate).Returns((Predicate)delegate { return true; }); // Assert Assert.Throws(() => { - var eventSubscription = new EventSubscription(delegateActionReferenceMock.Object, delegateFilterReferenceMock.Object); + _ = new EventSubscription(delegateActionReferenceMock.Object, delegateFilterReferenceMock.Object); }); } @@ -88,12 +87,12 @@ public void ConstructGeneric_NullFilter_ShouldThrowArgumentException() var delegateActionReferenceMock = new Mock(); delegateActionReferenceMock.Setup(x => x.Delegate).Returns((Action)delegate { }); var delegateFilterReferenceMock = new Mock(); - delegateFilterReferenceMock.Setup(x => x.Delegate).Returns(null); + delegateFilterReferenceMock.Setup(x => x.Delegate).Returns(null!); // Assert Assert.Throws(() => { - var eventSubscription = new EventSubscription(delegateActionReferenceMock.Object, delegateFilterReferenceMock.Object); + _ = new EventSubscription(delegateActionReferenceMock.Object, delegateFilterReferenceMock.Object); }); } @@ -107,7 +106,7 @@ public void ConstructNonGeneric_DifferentTargetTypeActionReference_ShouldThrowAr // Assert Assert.Throws(() => { - var eventSubscription = new EventSubscription(delegateActionReferenceMock.Object); + _ = new EventSubscription(delegateActionReferenceMock.Object); }); } @@ -123,7 +122,7 @@ public void ConstructGeneric_DifferentTargetTypeActionReference_ShouldThrowArgum // Assert Assert.Throws(() => { - var eventSubscription = new EventSubscription(delegateActionReferenceMock.Object, delegateFilterReferenceMock.Object); + _ = new EventSubscription(delegateActionReferenceMock.Object, delegateFilterReferenceMock.Object); }); } @@ -139,7 +138,7 @@ public void ConstructGeneric_DifferentTargetTypeFilterReference_ShouldThrowArgum // Assert Assert.Throws(() => { - var eventSubscription = new EventSubscription(delegateActionReferenceMock.Object, delegateFilterReferenceMock.Object); + _ = new EventSubscription(delegateActionReferenceMock.Object, delegateFilterReferenceMock.Object); }); } @@ -206,7 +205,7 @@ public void GetActionNonGeneric_NullAction_ShouldReturnNull() Assert.NotNull(publishAction); // Act - delegateActionReferenceMock.Setup(x => x.Delegate).Returns(null); + delegateActionReferenceMock.Setup(x => x.Delegate).Returns(null!); publishAction = eventSubscription.GetExecutionStrategy(); // Assert @@ -232,7 +231,7 @@ public void GetActionGeneric_NullAction_ShouldReturnNull() Assert.NotNull(publishAction); // Act - delegateActionReferenceMock.Setup(x => x.Delegate).Returns(null); + delegateActionReferenceMock.Setup(x => x.Delegate).Returns(null!); publishAction = eventSubscription.GetExecutionStrategy(); // Assert @@ -267,7 +266,9 @@ public void GetExecutionStrategyGeneric_PassArgument_ShouldPassArgumentToDelegat } [Fact] - public void GetExecutionStrategyNonGeneric_NullAction_ShouldReturnNull() +#pragma warning disable S4144 // Methods should not have identical implementations + public void GetExecutionStrategy_NonGenericAction_ShouldReturnNull() +#pragma warning restore S4144 // Methods should not have identical implementations { // Prepare var delegateActionReferenceMock = new Mock(); @@ -283,7 +284,7 @@ public void GetExecutionStrategyNonGeneric_NullAction_ShouldReturnNull() Assert.NotNull(publishAction); // Act - delegateActionReferenceMock.Setup(x => x.Delegate).Returns(null); + delegateActionReferenceMock.Setup(x => x.Delegate).Returns(null!); publishAction = eventSubscription.GetExecutionStrategy(); // Assert @@ -291,7 +292,7 @@ public void GetExecutionStrategyNonGeneric_NullAction_ShouldReturnNull() } [Fact] - public void GetExecutionStrategyGeneric_NullAction_ShouldReturnNull() + public void GetExecutionStrategy_GenericAction_ShouldReturnNull() { // Prepare var delegateActionReferenceMock = new Mock(); @@ -309,7 +310,7 @@ public void GetExecutionStrategyGeneric_NullAction_ShouldReturnNull() Assert.NotNull(publishAction); // Act - delegateActionReferenceMock.Setup(x => x.Delegate).Returns(null); + delegateActionReferenceMock.Setup(x => x.Delegate).Returns(null!); publishAction = eventSubscription.GetExecutionStrategy(); // Assert @@ -335,7 +336,7 @@ public void GetExecutionStrategyGeneric_NullFilter_ShouldReturnNull() Assert.NotNull(publishAction); // Act - delegateFilterReferenceMock.Setup(x => x.Delegate).Returns(null); + delegateFilterReferenceMock.Setup(x => x.Delegate).Returns(null!); publishAction = eventSubscription.GetExecutionStrategy(); // Assert diff --git a/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/PubSubEventTests.cs b/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/PubSubEventTests.cs index 93a17ce..2c95421 100644 --- a/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/PubSubEventTests.cs +++ b/src/Tests/WinReform.Domain.Tests/Infrastructure/Messenger/PubSubEventTests.cs @@ -38,14 +38,18 @@ private class PubSubEventFixture : PubSubEvent public void SubscribeNonGeneric_DefaultThread_ShouldPublishOnSubscriberThread() { // Prepare - static void ActionReference() { } + static void ActionReference() + { + // Method intentionally left empty. + } + var pubsubEvent = new PubSubEventFixture(); // Act - var token = pubsubEvent.Subscribe(ActionReference); + _ = pubsubEvent.Subscribe(ActionReference); // Assert - Assert.Equal(1, pubsubEvent.CurrentSubscriptions.Count); + Assert.Single(pubsubEvent.CurrentSubscriptions); Assert.Equal(typeof(EventSubscription), pubsubEvent.CurrentSubscriptions.ElementAt(0).GetType()); } @@ -53,14 +57,18 @@ static void ActionReference() { } public void SubscribeGeneric_DefaultThread_ShouldPublishOnSubscriberThread() { // Prepare - static void ActionReference(string arg) { } + static void ActionReference(string arg) + { + // Method intentionally left empty. + } + var pubsubEvent = new PubSubEventFixture(); // Act - var token = pubsubEvent.Subscribe(ActionReference); + _ = pubsubEvent.Subscribe(ActionReference); // Assert - Assert.Equal(1, pubsubEvent.CurrentSubscriptions.Count); + Assert.Single(pubsubEvent.CurrentSubscriptions); Assert.Equal(typeof(EventSubscription), pubsubEvent.CurrentSubscriptions.ElementAt(0).GetType()); } @@ -68,7 +76,11 @@ static void ActionReference(string arg) { } public void Subscribe_DefaultFilter_ShouldReturnTrue() { // Prepare - static void ActionReference(string arg) { } + static void ActionReference(string arg) + { + // Method intentionally left empty. + } + var pubSubEvent = new PubSubEventFixture(); // Act @@ -89,9 +101,13 @@ static void ActionReference(string arg) { } public void UnsubscribeNonGeneric_UnsubscribeByAction_ShouldUnsubscribe() { // Prepare - static void ActionReference() { } + static void ActionReference() + { + // Method intentionally left empty. + } + var pubSubEvent = new PubSubEventFixture(); - var token = pubSubEvent.Subscribe(ActionReference); + _ = pubSubEvent.Subscribe(ActionReference); // Assert Assert.True(pubSubEvent.Contains(ActionReference)); @@ -107,9 +123,13 @@ static void ActionReference() { } public void UnsubscribeGeneric_UnsubscribeByAction_ShouldUnsubscribe() { // Prepare - static void ActionReference(string arg) { } + static void ActionReference(string arg) + { + // Method intentionally left empty. + } + var pubSubEvent = new PubSubEventFixture(); - var token = pubSubEvent.Subscribe(ActionReference); + _ = pubSubEvent.Subscribe(ActionReference); // Assert Assert.True(pubSubEvent.Contains(ActionReference)); @@ -123,25 +143,19 @@ static void ActionReference(string arg) { } #endregion Unsubscribe Tests - #region Publish Tests - - [Fact] - public void PublishGeneric_NullArgument_ShouldThrowNullArgumentException() - { - // Prepare - } - - #endregion Publish Tests - #region Contains Tests [Fact] public void ContainsNonGeneric_SearchByAction_ShouldFindSubscriber() { // Prepare - static void ActionReference() { } + static void ActionReference() + { + // Method intentionally left empty. + } + var pubSubEvent = new PubSubEventFixture(); - var token = pubSubEvent.Subscribe(ActionReference); + _ = pubSubEvent.Subscribe(ActionReference); // Assert Assert.True(pubSubEvent.Contains(ActionReference)); @@ -151,9 +165,13 @@ static void ActionReference() { } public void ContainsGeneric_SearchByAction_ShouldFindSubscriber() { // Prepare - static void ActionReference(string arg) { } + static void ActionReference(string arg) + { + // Method intentionally left empty. + } + var pubSubEvent = new PubSubEventFixture(); - var token = pubSubEvent.Subscribe(ActionReference); + _ = pubSubEvent.Subscribe(ActionReference); // Assert Assert.True(pubSubEvent.Contains(ActionReference)); diff --git a/src/Tests/WinReform.Domain.Tests/Infrastructure/Model/ModelBaseTests.cs b/src/Tests/WinReform.Domain.Tests/Infrastructure/Model/ModelBaseTests.cs index 01cc2d6..a96123e 100644 --- a/src/Tests/WinReform.Domain.Tests/Infrastructure/Model/ModelBaseTests.cs +++ b/src/Tests/WinReform.Domain.Tests/Infrastructure/Model/ModelBaseTests.cs @@ -57,7 +57,7 @@ public void SetProperty_UnchangedValue_ShouldNotSet() modelFixture.PropertyChanged += (o, e) => { // Act - if (e.PropertyName.Equals(nameof(modelFixture.Number))) + if (e.PropertyName != null && e.PropertyName.Equals(nameof(modelFixture.Number))) { invoked = true; } @@ -81,7 +81,7 @@ public void SetProperty_NewValue_ShouldRaisePropertyChanged() modelFixture.PropertyChanged += (o, e) => { // Act - if (e.PropertyName.Equals(nameof(modelFixture.Number))) + if (e.PropertyName != null && e.PropertyName.Equals(nameof(modelFixture.Number))) { invoked = true; } @@ -103,7 +103,7 @@ public void SetProperty_PropertyDependency_ShouldRaisePropertyChanged() modelFixture.PropertyChanged += (o, e) => { // Act - if (e.PropertyName.Equals(nameof(modelFixture.TextDependency))) + if (e.PropertyName != null && e.PropertyName.Equals(nameof(modelFixture.TextDependency))) { invoked = true; } @@ -129,7 +129,7 @@ public void OnPropertyChanged_Raised_ShouldExtractPropertyName() modelFixture.PropertyChanged += (o, e) => { // Act - if (e.PropertyName.Equals(nameof(modelFixture.Number))) + if (e.PropertyName != null && e.PropertyName.Equals(nameof(modelFixture.Number))) { invoked = true; } diff --git a/src/Tests/WinReform.Domain.Tests/WinReform.Domain.Tests.csproj b/src/Tests/WinReform.Domain.Tests/WinReform.Domain.Tests.csproj index 232aabd..ecebc5b 100644 --- a/src/Tests/WinReform.Domain.Tests/WinReform.Domain.Tests.csproj +++ b/src/Tests/WinReform.Domain.Tests/WinReform.Domain.Tests.csproj @@ -8,11 +8,17 @@ - - - - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/Tests/WinReform.Tests.Fixtures/ModelFixture.cs b/src/Tests/WinReform.Tests.Fixtures/ModelFixture.cs index 3722774..e3f8ff4 100644 --- a/src/Tests/WinReform.Tests.Fixtures/ModelFixture.cs +++ b/src/Tests/WinReform.Tests.Fixtures/ModelFixture.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; +using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using WinReform.Domain.Infrastructure.Attributes; using WinReform.Domain.Infrastructure.Model; @@ -10,7 +8,7 @@ namespace WinReform.Tests.Fixtures /// /// Defines a class that represents a model fixture that provides a fake model properties for testing puprose /// - public class ModelFixture : ModelBase, IEquatable, IComparable + public sealed class ModelFixture : ModelBase, IEquatable, IComparable, IEqualityComparer { /// /// Gets or Sets the identifier of the model @@ -66,16 +64,6 @@ public void InvokePropertyChanged(string propertyName) /// Returns containing all property names that rely on the given property names public List GetPropertyDependencies(string propertyName) => PropertyDependencies[propertyName]; - /// - /// Compares a given to the current - /// - /// to compare - /// Returns if both are equal, otherwise returns - public bool Equals([AllowNull] ModelFixture obj) - => obj?.Id == Id - && obj?.Text == Text - && obj?.Number == Number; - /// /// Compares if a given represents the same as the current instance /// @@ -96,15 +84,133 @@ public int CompareTo([AllowNull] ModelFixture obj) /// to compare /// Returns if the is equal to the current , otherwise returns /// - public override bool Equals(object obj) + public override bool Equals(object? obj) => obj is ModelFixture fixture && Equals(fixture); + /// + /// Compares a given to the current + /// + /// to compare + /// Returns if both are equal, otherwise returns + public bool Equals([AllowNull] ModelFixture obj) + => obj?.Id == Id + && obj.Text == Text + && obj.Number == Number; + + /// + /// Checks if two instances are equal. + /// + /// The left to compare. + /// The right to compare. + /// Returns if both instances are equal; otherwise, . + public static bool operator ==(ModelFixture left, ModelFixture right) + { + // Handle null comparisons + if (ReferenceEquals(left, right)) + return true; + if (left is null || right is null) + return false; + + return left.Equals(right); // Use the instance Equals method + } + + /// + /// Checks if two instances are not equal. + /// + /// The left to compare. + /// The right to compare. + /// Returns if the instances are not equal; otherwise, . + public static bool operator !=(ModelFixture left, ModelFixture right) + { + return !(left == right); // Use the == operator to simplify logic + } + + /// + /// Checks if the left is less than the right . + /// + /// The left to compare. + /// The right to compare. + /// Returns if the left instance is less than the right; otherwise, . + public static bool operator <(ModelFixture left, ModelFixture right) + { + if (left is null && right is null) return false; + if (left is null) return true; + if (right is null) return false; + + return left.CompareTo(right) < 0; + } + + /// + /// Checks if the left is greater than the right . + /// + /// The left to compare. + /// The right to compare. + /// Returns if the left instance is greater than the right; otherwise, . + public static bool operator >(ModelFixture left, ModelFixture right) + { + if (left is null && right is null) return false; + if (right is null) return true; + if (left is null) return false; + + return left.CompareTo(right) > 0; + } + + /// + /// Checks if the left is less than or equal to the right . + /// + /// The left to compare. + /// The right to compare. + /// Returns if the left instance is less than or equal to the right; otherwise, . + public static bool operator <=(ModelFixture left, ModelFixture right) + { + return left == right || left < right; + } + + /// + /// Checks if the left is greater than or equal to the right . + /// + /// The left to compare. + /// The right to compare. + /// Returns if the left instance is greater than or equal to the right; otherwise, . + public static bool operator >=(ModelFixture left, ModelFixture right) + { + return left == right || left > right; + } + /// /// Gets the hashcode of the /// /// Returns containing a unique hashcode that represents the instance of the current public override int GetHashCode() => (Id, Text, Number).GetHashCode(); + + /// + /// Determines whether the specified instances are equal. + /// + /// The first to compare. + /// The second to compare. + /// + /// Returns if the specified instances are equal; otherwise, . + /// + public bool Equals(ModelFixture? x, ModelFixture? y) + { + if (x is null && y is null) return true; + if (x is null || y is null) return false; + return x.Id == y.Id && x.Text == y.Text && x.Number == y.Number; + } + + /// + /// Returns a hash code for the specified . + /// + /// The for which a hash code is to be returned. Cannot be . + /// + /// A hash code for the specified . + /// + /// Thrown if is . + public int GetHashCode([DisallowNull] ModelFixture obj) + { + return (obj.Id, obj.Text, obj.Number).GetHashCode(); + } } } diff --git a/src/Tests/WinReform.Tests.Process.Fixture/Program.cs b/src/Tests/WinReform.Tests.Process.Fixture/Program.cs index bf04a55..7ca79da 100644 --- a/src/Tests/WinReform.Tests.Process.Fixture/Program.cs +++ b/src/Tests/WinReform.Tests.Process.Fixture/Program.cs @@ -1,42 +1,51 @@ -using System; -using System.Timers; +using System.Timers; -namespace WinReform.Tests.Process.Fixture +namespace WinReform.Tests.Process.Fixture; + +/// +/// Defines a class that represents a fixture of a process without a window +/// NOTE: The application automatically closes after x seconds, this to make sure that if the test failed and the dispose isn't triggered the app won't linger in the background forever. +/// +internal static class Program { /// - /// Defines a class that represents a fixture of a process without a window - /// NOTE: The application automaticly closes after x seconds, this to make sure that if the test failed and the dispose isnt't triggered the app wont linger in the background forever + /// that triggers an automatic close of the application + /// + private static System.Timers.Timer? s_autoCloseTimer; + + /// + /// Entry point of the application /// - internal class Program + /// Arguments passed on startup + private static void Main() { - /// - /// that triggers an automatic close of the application - /// - private static System.Timers.Timer s_autoCloseTimer; + s_autoCloseTimer = new System.Timers.Timer(20000); // 20 seconds + s_autoCloseTimer.Elapsed += OnAutoCloseTimer; + s_autoCloseTimer.Start(); - /// - /// Entry point of the application - /// - /// Arguments passed on startup - private static void Main() - { - s_autoCloseTimer = new System.Timers.Timer(20000); // 20 seconds - s_autoCloseTimer.Elapsed += OnAutoCloseTimer; - s_autoCloseTimer.Start(); + Console.ReadKey(); + } - Console.ReadKey(); + /// + /// Raised when the elapsed and automatically closes the application. + /// + /// The source of the event. + /// An that contains the event data. + private static void OnAutoCloseTimer(object? sender, ElapsedEventArgs e) + { + if (sender == null) + { + return; } - /// - /// Raised when the elapsed and automaticly closes the application - /// - /// - /// - private static void OnAutoCloseTimer(object sender, ElapsedEventArgs e) + // Safely dispose of the timer only if it's not null + if (s_autoCloseTimer != null) { s_autoCloseTimer.Close(); s_autoCloseTimer.Dispose(); - Environment.Exit(0); + s_autoCloseTimer = null; } + + Environment.Exit(0); } } diff --git a/src/Tests/WinReform.Tests.WindowProcess.Fixture/App.xaml.cs b/src/Tests/WinReform.Tests.WindowProcess.Fixture/App.xaml.cs index 00b1011..7bd2800 100644 --- a/src/Tests/WinReform.Tests.WindowProcess.Fixture/App.xaml.cs +++ b/src/Tests/WinReform.Tests.WindowProcess.Fixture/App.xaml.cs @@ -6,14 +6,14 @@ namespace WinReform.Tests.WindowProcess.Fixture { /// /// Defines a class that represents a fixture of a process with a window - /// NOTE: The application automaticly closes after x seconds, this to make sure that if the test failed and the dispose isnt't triggered the app wont linger in the background forever + /// NOTE: The application automatically closes after x seconds, this to make sure that if the test failed and the dispose isn't triggered the app won't linger in the background forever. /// public partial class App : Application { /// /// that triggers an automatic close of the application /// - private System.Timers.Timer _autoCloseTimer; + private System.Timers.Timer? _autoCloseTimer; /// /// Sets up the project @@ -32,14 +32,24 @@ protected override void OnStartup(StartupEventArgs e) } /// - /// Raised when the elapsed and automaticly closes the application + /// Raised when the elapsed and automatically closes the application /// - /// - /// - private void OnAutoCloseTimer(object sender, ElapsedEventArgs e) + /// The source of the event. + /// An that contains the event data. + private void OnAutoCloseTimer(object? sender, ElapsedEventArgs e) { - _autoCloseTimer.Close(); - _autoCloseTimer.Dispose(); + if(sender == null) + { + return; + } + + if (_autoCloseTimer != null) + { + _autoCloseTimer.Close(); + _autoCloseTimer.Dispose(); + _autoCloseTimer = null; + } + Environment.Exit(0); } } diff --git a/src/Tests/WinReform.Tests.WindowProcess.Fixture/WinReform.Tests.WindowProcess.Fixture.csproj b/src/Tests/WinReform.Tests.WindowProcess.Fixture/WinReform.Tests.WindowProcess.Fixture.csproj index 5a5f9a8..1c11cd7 100644 --- a/src/Tests/WinReform.Tests.WindowProcess.Fixture/WinReform.Tests.WindowProcess.Fixture.csproj +++ b/src/Tests/WinReform.Tests.WindowProcess.Fixture/WinReform.Tests.WindowProcess.Fixture.csproj @@ -6,6 +6,7 @@ enable WinExe true + $(NoWarn);NETSDK1137 \ No newline at end of file diff --git a/src/Tests/WinReform.Tests/WinReform.Tests.csproj b/src/Tests/WinReform.Tests/WinReform.Tests.csproj index da2a904..e16c72c 100644 --- a/src/Tests/WinReform.Tests/WinReform.Tests.csproj +++ b/src/Tests/WinReform.Tests/WinReform.Tests.csproj @@ -14,11 +14,17 @@ - - - - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/WinReform/WinReform.Domain/Settings/SettingStore.cs b/src/WinReform/WinReform.Domain/Settings/SettingStore.cs index 8794a7d..ec70d29 100644 --- a/src/WinReform/WinReform.Domain/Settings/SettingStore.cs +++ b/src/WinReform/WinReform.Domain/Settings/SettingStore.cs @@ -48,7 +48,7 @@ public SettingStore() WriteIndented = true }; - return JsonSerializer.Deserialize(settingString, serializerOptions); + return JsonSerializer.Deserialize(settingString, serializerOptions) ?? new TSetting(); } /// @@ -56,12 +56,17 @@ public void Save(TSetting settings) { var file = Path.Combine(_filePath, $"{typeof(TSetting).Name}.json"); var fileInfo = new FileInfo(file); - fileInfo.Directory.Create(); + + if (fileInfo.Directory != null && !fileInfo.Directory.Exists) + { + fileInfo.Directory.Create(); + } var serializerOptions = new JsonSerializerOptions { WriteIndented = true }; + var json = JsonSerializer.Serialize(settings, serializerOptions); File.WriteAllText(file, json); } diff --git a/src/WinReform/WinReform.Domain/WinReform.Domain.csproj b/src/WinReform/WinReform.Domain/WinReform.Domain.csproj index 8cc5da9..3acc2da 100644 --- a/src/WinReform/WinReform.Domain/WinReform.Domain.csproj +++ b/src/WinReform/WinReform.Domain/WinReform.Domain.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/WinReform/WinReform.Domain/Windows/WindowService.cs b/src/WinReform/WinReform.Domain/Windows/WindowService.cs index 17bddd4..31feea6 100644 --- a/src/WinReform/WinReform.Domain/Windows/WindowService.cs +++ b/src/WinReform/WinReform.Domain/Windows/WindowService.cs @@ -50,23 +50,33 @@ public IEnumerable GetActiveWindows() } var dimensions = _winApiService.GetWindowRect(process.MainWindowHandle); - if(dimensions.IsEmpty) + if (dimensions.IsEmpty) { continue; // Has a 0 by 0 window, and not meant to display } + Bitmap? iconBitmap = default; + if (process.MainModule?.FileName != null && File.Exists(process.MainModule.FileName)) + { + var icon = Icon.ExtractAssociatedIcon(process.MainModule.FileName); + if (icon != null) + { + iconBitmap = icon.ToBitmap(); + } + } + windows.Add(new Window() { Id = process.Id, WindowHandle = process.MainWindowHandle, Description = process.MainModule?.FileVersionInfo.FileDescription ?? string.Empty, - Icon = Icon.ExtractAssociatedIcon(process.MainModule?.FileName).ToBitmap(), + Icon = iconBitmap, Dimensions = dimensions }); } catch (Win32Exception) { - continue; + // Do nothing } } diff --git a/src/WinReform/WinReform/ActiveWindows/ActiveWindowsViewModel.cs b/src/WinReform/WinReform/ActiveWindows/ActiveWindowsViewModel.cs index f780d3c..9c5404d 100644 --- a/src/WinReform/WinReform/ActiveWindows/ActiveWindowsViewModel.cs +++ b/src/WinReform/WinReform/ActiveWindows/ActiveWindowsViewModel.cs @@ -1,9 +1,6 @@ -using System; -using System.Collections.ObjectModel; +using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; -using System.Linq; -using System.Threading.Tasks; using System.Windows; using System.Windows.Data; using System.Windows.Threading; @@ -135,9 +132,18 @@ public ActiveWindowsViewModel(IEventAggregator eventAggregator, IWindowService w } /// - /// Disposes of all event handlers + /// Disposes of the view model /// public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Disposes of all event handlers + /// + protected virtual void Dispose(bool disposing) { _autoRefreshTimer.Stop(); _autoRefreshTimer.Tick -= OnAutoRefreshEvent; @@ -189,7 +195,7 @@ private void ApplicationSettingsChanged(ISetting settings) /// /// /// - private void SelectedActiveWindowsChanged(object sender, NotifyCollectionChangedEventArgs e) + private void SelectedActiveWindowsChanged(object? sender, NotifyCollectionChangedEventArgs e) { _eventAggregator.GetEvent().Publish(SelectedActiveWindows.ToList()); } diff --git a/src/WinReform/WinReform/Infrastructure/Command/DelegateCommand.cs b/src/WinReform/WinReform/Infrastructure/Command/DelegateCommand.cs index 81f17df..ee5e457 100644 --- a/src/WinReform/WinReform/Infrastructure/Command/DelegateCommand.cs +++ b/src/WinReform/WinReform/Infrastructure/Command/DelegateCommand.cs @@ -59,13 +59,13 @@ public bool CanExecute() } /// - protected override void Execute(object parameter) + protected override void Execute(object? parameter) { Execute(); } /// - protected override bool CanExecute(object parameter) + protected override bool CanExecute(object? parameter) { return CanExecute(); } @@ -106,12 +106,9 @@ public DelegateCommand(Action executeMethod, Func? canExecuteMethod) } var typeInfo = typeof(T).GetTypeInfo(); - if (typeInfo.IsValueType) + if (typeInfo.IsValueType && (!typeInfo.IsGenericType || !typeof(Nullable<>).GetTypeInfo().IsAssignableFrom(typeInfo.GetGenericTypeDefinition().GetTypeInfo()))) { - if (!typeInfo.IsGenericType || !typeof(Nullable<>).GetTypeInfo().IsAssignableFrom(typeInfo.GetGenericTypeDefinition().GetTypeInfo())) - { - throw new InvalidCastException("Parameter type isnt a valid generic type"); - } + throw new InvalidCastException("Parameter type isnt a valid generic type"); } _executeMethod = executeMethod; @@ -138,15 +135,37 @@ public bool CanExecute(T parameter) } /// - protected override void Execute(object parameter) + protected override void Execute(object? parameter) { - Execute((T)parameter); + if (parameter is T typedParameter) + { + Execute(typedParameter); + } + else if (parameter == null && default(T) is null) + { + Execute(default!); + } + else + { + throw new ArgumentException($"Invalid parameter type. Expected {typeof(T)}, got {parameter?.GetType().Name ?? "null"}."); + } } /// - protected override bool CanExecute(object parameter) + protected override bool CanExecute(object? parameter) { - return CanExecute((T)parameter); + if (parameter is T typedParameter) + { + return CanExecute(typedParameter); + } + else if (parameter is null && default(T) is null) + { + return CanExecute(default!); + } + else + { + return false; + } } } } diff --git a/src/WinReform/WinReform/Infrastructure/Command/DelegateCommandBase.cs b/src/WinReform/WinReform/Infrastructure/Command/DelegateCommandBase.cs index 3045a9d..1f0528b 100644 --- a/src/WinReform/WinReform/Infrastructure/Command/DelegateCommandBase.cs +++ b/src/WinReform/WinReform/Infrastructure/Command/DelegateCommandBase.cs @@ -22,7 +22,7 @@ public abstract class DelegateCommandBase : ICommand /// /// A base command that provides base functionallity to a command /// - public DelegateCommandBase() + protected DelegateCommandBase() { _synchronizationContext = SynchronizationContext.Current; } @@ -31,7 +31,7 @@ public DelegateCommandBase() /// Executes the command /// /// Command parameter - void ICommand.Execute(object parameter) + void ICommand.Execute(object? parameter) { Execute(parameter); } @@ -41,7 +41,7 @@ void ICommand.Execute(object parameter) /// /// Data used to determine if the command can be executed /// Returns if the command can execute, otherwise - bool ICommand.CanExecute(object parameter) + bool ICommand.CanExecute(object? parameter) { return CanExecute(parameter); } @@ -59,13 +59,13 @@ public void RaiseCanExecuteChanged() /// /// Data used to determine if the command can be executed /// Returns if the command can execute, otherwise - protected abstract bool CanExecute(object parameter); + protected abstract bool CanExecute(object? parameter); /// /// Executes the command /// /// Command parameter - protected abstract void Execute(object parameter); + protected abstract void Execute(object? parameter); /// /// Raises the allowing every command to requery diff --git a/src/WinReform/WinReform/Infrastructure/Extensions/ObservableCollectionExtensions.cs b/src/WinReform/WinReform/Infrastructure/Extensions/ObservableCollectionExtensions.cs index 940e613..f346320 100644 --- a/src/WinReform/WinReform/Infrastructure/Extensions/ObservableCollectionExtensions.cs +++ b/src/WinReform/WinReform/Infrastructure/Extensions/ObservableCollectionExtensions.cs @@ -31,25 +31,29 @@ public static void UpdateCollection(this ObservableCollection collection, { if (collection.Count > i) { - var itemIndex = collection.IndexOf(collection.Where(i => Comparer.Default.Compare(i, item) == 0).FirstOrDefault()); + var existingItem = collection.FirstOrDefault(existing => Comparer.Default.Compare(existing, item) == 0); - if (itemIndex < 0) + if (existingItem == null! || existingItem.Equals(default(T))) { - // Item doesn't exist + // Item doesn't exist in the collection, so insert it collection.Insert(i, item); } - else if (itemIndex > i || itemIndex < i) - { - // Item exists, but has moved up or down - collection.Move(itemIndex, i); - } else { - if ((!collection[i]?.Equals(item)) ?? false) + // Get the index of the existing item, ensuring it's not null + var itemIndex = collection.IndexOf(existingItem); + + if (itemIndex != i) + { + // Item exists but is in the wrong place, so move it + collection.Move(itemIndex, i); + } + else { - // Item has changed, replace it - if (item != null) + // Check if the item has changed (considering nullability) + if (collection[i] is not null && item is not null && !collection[i]!.Equals(item)) { + // If the item has changed, copy properties foreach (var sourceProperty in item.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) { var targetProperty = collection[i]?.GetType().GetProperty(sourceProperty.Name); @@ -65,14 +69,14 @@ public static void UpdateCollection(this ObservableCollection collection, } else { - // Item doesn't exist + // Item doesn't exist in the collection, so add it collection.Add(item); } i++; } - // Remove all old items + // Remove any items left in the original collection that aren't in the new collection while (collection.Count > newCollection.Count) { collection.RemoveAt(i); diff --git a/src/WinReform/WinReform/WinReform.csproj b/src/WinReform/WinReform/WinReform.csproj index 72485fd..21f7224 100644 --- a/src/WinReform/WinReform/WinReform.csproj +++ b/src/WinReform/WinReform/WinReform.csproj @@ -9,6 +9,7 @@ app.manifest logo.ico WinReform + $(NoWarn);NETSDK1137 @@ -20,10 +21,10 @@ - - - - + + + + From 8df933ebe0571bef927c15f6a4f3c0edd320eac6 Mon Sep 17 00:00:00 2001 From: AKruimink <43521957+AKruimink@users.noreply.github.com> Date: Fri, 6 Sep 2024 00:57:00 +0100 Subject: [PATCH 4/4] Updates the actions to use v3 and target the new .net version --- .github/workflows/build-project.yml | 17 +++++++++-------- .github/workflows/test-project.yml | 15 ++++++++------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build-project.yml b/.github/workflows/build-project.yml index d70cacf..eb75d8a 100644 --- a/.github/workflows/build-project.yml +++ b/.github/workflows/build-project.yml @@ -1,7 +1,7 @@ name: 'build-project' on: - push: #Push always triggers after a merge + push: # Push always triggers after a merge branches: - master - develop @@ -9,27 +9,28 @@ on: # Defines environment variables env: - NETCORE_VERSION: '3.1.200' + NETCORE_VERSION: '8.0.x' jobs: build: name: 'run-project-build' runs-on: windows-latest steps: - - uses: actions/checkout@v2 + # Checkout the repository + - uses: actions/checkout@v3 - #Setup the environment - - name: 'setup .NET Core SDK ${{ env.NETCORE_VERSION }}' - uses: actions/setup-dotnet@v1 + # Setup the .NET 8.0 SDK environment + - name: 'setup .NET SDK ${{ env.NETCORE_VERSION }}' + uses: actions/setup-dotnet@v3 with: dotnet-version: ${{ env.NETCORE_VERSION }} - # Restore all nuget packages to prevent issues during build + # Restore NuGet packages to ensure dependencies are available for the build - name: 'restore nuget packages' working-directory: './src' run: dotnet restore - # Build the project + # Build the project in Release configuration - name: 'build project' working-directory: './src' run: dotnet build --configuration Release --no-restore \ No newline at end of file diff --git a/.github/workflows/test-project.yml b/.github/workflows/test-project.yml index 0083dc2..a511b8c 100644 --- a/.github/workflows/test-project.yml +++ b/.github/workflows/test-project.yml @@ -1,7 +1,7 @@ name: 'test-project' on: - push: #Push always triggers after a merge + push: # Push always triggers after a merge branches: - master - develop @@ -9,22 +9,23 @@ on: # Defines environment variables env: - NETCORE_VERSION: '3.1.200' + NETCORE_VERSION: '8.0.x' jobs: build: name: 'run-unit-tests' runs-on: windows-latest steps: - - uses: actions/checkout@v2 + # Checkout the repository + - uses: actions/checkout@v3 - #Setup the environment - - name: 'setup .NET Core SDK ${{ env.NETCORE_VERSION }}' - uses: actions/setup-dotnet@v1 + # Setup the .NET 8.0 SDK environment + - name: 'setup .NET SDK ${{ env.NETCORE_VERSION }}' + uses: actions/setup-dotnet@v3 with: dotnet-version: ${{ env.NETCORE_VERSION }} - # Restore all nuget packages to prevent issues during build + # Restore all NuGet packages to ensure dependencies are available - name: 'restore nuget packages' working-directory: './src' run: dotnet restore