├── .editorconfig ├── .github └── dependabot.yml ├── .gitignore ├── Gu.Reactive.Analyzers.Tests ├── .editorconfig ├── AssemblyAttributes.cs ├── Cs8602SuppressorTests.cs ├── Cs8620SuppressorTests.cs ├── GUREA01DoNotObserveMutablePropertyTests │ ├── Diagnostics.cs │ └── Valid.cs ├── GUREA02ObservableAndCriteriaMustMatchTests │ ├── Diagnostics.cs │ └── Valid.cs ├── GUREA03PathMustNotifyTests │ ├── Diagnostics.cs │ └── Valid.cs ├── GUREA04PreferSlimTests │ ├── CodeFix.cs │ └── Valid.cs ├── GUREA05FullPathMustHaveMoreThanOneItemTests │ ├── Diagnostics.cs │ └── Valid.cs ├── GUREA06DoNotNewConditionTests │ ├── Diagnostics.cs │ └── Valid.cs ├── GUREA07DontNegateConditionTests │ ├── CodeFix.cs │ └── Valid.cs ├── GUREA08InlineSingleLineTests │ ├── CodeFix.cs │ └── Valid.cs ├── GUREA09ObservableBeforeCriteriaTests │ ├── CodeFix.cs │ └── Valid.cs ├── GUREA10DoNotMergeInObservableTests │ ├── Diagnostics.cs │ └── Valid.cs ├── GUREA11PreferObservableFromEventTests │ ├── CodeFix.ActionOfInt.cs │ ├── CodeFix.EventHandler.cs │ ├── CodeFix.EventHandlerOfInt.cs │ ├── CodeFix.MiscEventhandlers.cs │ ├── CodeFix.cs │ └── Valid.cs ├── GUREA12ObservableFromEventDelegateTypeTests │ ├── CodeFix.cs │ └── Valid.cs ├── GUREA13SyncParametersAndArgsTests │ ├── CodeFix.cs │ └── Valid.cs ├── Gu.Reactive.Analyzers.Tests.csproj ├── ModuleInitializer.cs └── ReproBox.cs ├── Gu.Reactive.Analyzers ├── .editorconfig ├── AnalyzerCategory.cs ├── Analyzers │ ├── AddAssignmentAnalyzer.cs │ ├── ConstructorAnalyzer.cs │ └── InvocationAnalyzer.cs ├── AssemblyAttributes.cs ├── CodeFixes │ ├── EventSubscriptionToObserveFix.cs │ ├── InjectNegatedCodeFix.cs │ ├── InlineSingleLineCodeFix.cs │ ├── ObservableBeforeCriteriaCodeFix.cs │ ├── ObservableFromEventArgsFix.cs │ ├── SortArgsFix.cs │ ├── SortParametersFix.cs │ └── UseSlimFix.cs ├── Descriptors.cs ├── Gu.Reactive.Analyzers.csproj ├── Gu.Reactive.Analyzers.csproj.DotSettings ├── Helpers │ ├── KnownSymbols │ │ ├── IConditionType.cs │ │ ├── KnownSymbol.cs │ │ ├── NotifyPropertyChangedExtType.cs │ │ ├── NullableOfTType.cs │ │ ├── ObservableExtensionsType.cs │ │ ├── ObservableType.cs │ │ └── StringType.cs │ ├── SymbolHelpers │ │ └── PropertySymbolExt.cs │ └── Walkers │ │ ├── IdentifierNameExecutionWalker.cs │ │ └── InvocationExecutionWalker.cs ├── InternalsVisibleTo.cs ├── Suppressors │ ├── Cs8602Suppressor.cs │ └── Cs8620Suppressor.cs └── tools │ ├── install.ps1 │ └── uninstall.ps1 ├── Gu.Reactive.Benchmarks ├── .editorconfig ├── AssemblyAttributes.cs ├── Benchmarks │ ├── AddAssignmentAnalyzerBenchmarks.cs │ ├── AddAssignmentAnalyzerBenchmarks.md │ ├── AllAnalyzersBenchmarks.cs │ ├── AllAnalyzersBenchmarks.md │ ├── Caching.cs │ ├── Caching.md │ ├── CodeGen │ │ ├── Code.cs │ │ └── CodeGen.cs │ ├── ConstructorAnalyzerBenchmarks.cs │ ├── Cs8602SuppressorBenchmarks.cs │ ├── Cs8620SuppressorBenchmarks.cs │ ├── Diff.cs │ ├── Diff.md │ ├── InvocationAnalyzerBenchmarks.cs │ ├── InvocationAnalyzerBenchmarks.md │ ├── MinTrackerProperty.cs │ ├── MinTrackerProperty.md │ ├── MinTrackerSimple.cs │ ├── MinTrackerSimple.md │ ├── NameOf.cs │ ├── NameOf.md │ ├── ObserveItemPropertyChanged.cs │ ├── ObserveItemPropertyChanged.md │ ├── ObservePropertyChanged.cs │ ├── ObservePropertyChanged.md │ ├── ObservePropertyChangedReact.cs │ ├── ObservePropertyChangedReact.md │ ├── ObservePropertyChangedThenSubscribe.cs │ ├── ObservePropertyChangedThenSubscribe.md │ ├── ObservePropertyChangedThenSubscribeThenReact.cs │ ├── ObservePropertyChangedThenSubscribeThenReact.md │ ├── ThrottledView.cs │ └── ThrottledView.md ├── Gu.Reactive.Benchmarks.csproj ├── Gu.Reactive.Benchmarks.csproj.DotSettings ├── Helpers │ ├── Fake.cs │ ├── IFake.cs │ ├── Level.cs │ ├── NotInpc.cs │ └── StructLevel.cs ├── Program.cs ├── app.config └── ~$raceEventProgrammersGuide.docx ├── Gu.Reactive.Demo ├── .editorconfig ├── App.xaml ├── App.xaml.cs ├── AssemblyAttributes.cs ├── AsyncCommandsView.xaml ├── AsyncCommandsView.xaml.cs ├── AsyncCommandsViewModel.cs ├── Collections │ ├── CollectionViewDemo.xaml │ ├── CollectionViewDemo.xaml.cs │ ├── CollectionViewDemoViewModel.cs │ ├── DispatchingCollectionView.xaml │ ├── DispatchingCollectionView.xaml.cs │ ├── DispatchingCollectionViewModel.cs │ ├── DispatchingViewView.xaml │ ├── DispatchingViewView.xaml.cs │ ├── DispatchingViewViewModel.cs │ ├── FilteredDispatchingView.xaml │ ├── FilteredDispatchingView.xaml.cs │ ├── FilteredDispatchingViewModel.cs │ ├── FilteredViewView.xaml │ ├── FilteredViewView.xaml.cs │ ├── FilteredViewViewModel.cs │ ├── MappedVm.cs │ ├── MappingViewView.xaml │ ├── MappingViewView.xaml.cs │ ├── MappingViewViewModel.cs │ ├── ObservableFixedSizeQueueView.xaml │ ├── ObservableFixedSizeQueueView.xaml.cs │ ├── ObservableFixedSizeQueueViewModel.cs │ ├── Person.cs │ ├── ReadOnlyFilteredViewView.xaml │ ├── ReadOnlyFilteredViewView.xaml.cs │ ├── ReadOnlyFilteredViewViewModel.cs │ ├── ReadOnlySerialViewView.xaml │ ├── ReadOnlySerialViewView.xaml.cs │ ├── ReadOnlySerialViewViewModel.cs │ ├── ReadOnlyThrottledViewView.xaml │ ├── ReadOnlyThrottledViewView.xaml.cs │ ├── ReadOnlyThrottledViewViewModel.cs │ ├── ReadonlyFilteredDispatchingView.xaml │ ├── ReadonlyFilteredDispatchingView.xaml.cs │ ├── ReadonlyFilteredDispatchingViewModel.cs │ ├── ThrottledViewView.xaml │ ├── ThrottledViewView.xaml.cs │ └── ThrottledViewViewModel.cs ├── CommandsView.xaml ├── CommandsView.xaml.cs ├── CommandsViewModel.cs ├── Conditions │ ├── CanStart.cs │ ├── ConditionButtonsView.xaml │ ├── ConditionButtonsView.xaml.cs │ ├── ConditionState.cs │ ├── ConditionsView.xaml │ ├── ConditionsView.xaml.cs │ ├── ConditionsViewModel.cs │ ├── EditConditionStateView.xaml │ ├── EditConditionStateView.xaml.cs │ ├── EitherCommandsView.xaml │ ├── EitherCommandsView.xaml.cs │ ├── EitherCommandsVm.cs │ ├── HasFuel.cs │ ├── IsAnyDoorOpen.cs │ ├── IsBackDoorOpen.cs │ ├── IsLeftDoorOpen.cs │ ├── IsMotorRunning.cs │ ├── IsRightDoorOpen.cs │ ├── SyncErrorCondition.cs │ ├── ToolTipsView.xaml │ └── ToolTipsView.xaml.cs ├── Converters │ ├── BooleanToBrushConverter.cs │ └── BooleanToVisibilityConverter.cs ├── DataGridAndEventsView.xaml ├── DataGridAndEventsView.xaml.cs ├── DummyItem.cs ├── EnumValuesView.xaml ├── EnumValuesView.xaml.cs ├── Gu.Reactive.Demo.csproj ├── Gu.Reactive.Demo.csproj.DotSettings ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── MainWindowViewModel.cs ├── NamedFilter.cs ├── NinjaBindingView.xaml ├── NinjaBindingView.xaml.cs ├── NinjaBindingViewModel.cs ├── TypeNameConverter.cs └── UiTestWindows │ ├── AsyncCommandsWindow.xaml │ ├── CommandsWindow.xaml │ ├── ConditionControlViewModel.cs │ ├── ConditionControlWindow.xaml │ ├── ConditionControlWindow.xaml.cs │ ├── DispatchingCollectionWindow.xaml │ ├── DispatchingViewWindow.xaml │ ├── FilteredDispatchingWindow.xaml │ ├── MappingViewWindow.xaml │ ├── ReadOnlyFilteredViewWindow.xaml │ ├── ReadOnlySerialViewWindow.xaml │ ├── ReadOnlyThrottledViewWindow.xaml │ └── ReadonlyFilteredDispatchingWindow.xaml ├── Gu.Reactive.Tests ├── .editorconfig ├── AssemblyAttributes.cs ├── ChunkTests.cs ├── Collections │ ├── CollectionSynchronizerTests.cs │ ├── DiffTests.cs │ ├── FixedSizedQueueTests.cs │ ├── ObservableBatchCollectionTests.cs │ └── ObservableFixedSizeQueueTests.cs ├── Conditions │ ├── AbstractConditionTests.cs │ ├── AndConditionTests.cs │ ├── ConditionExtTests.cs │ ├── ConditionTests.cs │ ├── NegatedConditionTests.cs │ ├── NegatedTests.cs │ ├── NullIsFalseTests.cs │ └── OrConditionTests.cs ├── Gu.Reactive.Tests.csproj ├── Gu.Reactive.Tests.csproj.DotSettings ├── Helpers │ ├── AbstractFake.cs │ ├── AssertEx.cs │ ├── ConcreteFake1.cs │ ├── ConcreteFake2.cs │ ├── DerivedFake.cs │ ├── DumpIfDebug.cs │ ├── EventArgsComparer.cs │ ├── EventPatternAssert.cs │ ├── Fake.cs │ ├── FakeWithCollection.cs │ ├── Fake{T}.cs │ ├── IFake.cs │ ├── IGeneric.cs │ ├── Indexed.cs │ ├── Level.cs │ ├── Level1.cs │ ├── Level2.cs │ ├── Level3.cs │ ├── Level4.cs │ ├── Level{T}.cs │ ├── ListEx.cs │ ├── NotNotifying.cs │ ├── StructLevel.cs │ ├── TestExtensions.cs │ ├── WithAbstractFake.cs │ ├── WithShadowing.cs │ └── With{T}.cs ├── Internals │ ├── PropertyPathTests │ │ └── NotifyingPathTests.cs │ └── TypeExtTests.cs ├── MaybeTests.cs ├── NameOfTests.Method.cs ├── NameOfTests.Property.cs ├── NotifyCollectionChangedEventArgsTests.cs ├── NotifyCollectionChangedExt │ ├── ObserveCollectionChanged.cs │ ├── ObserveCollectionChangedSlim.cs │ ├── ObserveItemPropertyChanged.cs │ ├── ObserveItemPropertyChangedSlim.cs │ ├── ObservePropertyChangedWithValueChainedItemPropertyChanged.cs │ └── ObserveValueChainedItemPropertyChanged.cs ├── NotifyPropertyChangedExt │ ├── ObserveFullPropertyPathSlim.cs │ ├── ObservePropertyChangedNoFilter.cs │ ├── ObservePropertyChangedSlimLambda.cs │ ├── ObservePropertyChangedSlimString.cs │ ├── ObservePropertyChangedWithValueNestedLambda.cs │ ├── ObservePropertyChangedWithValueSimpleLambda.cs │ ├── ObserveValue.cs │ ├── OnPropertyChangedNestedLambda.cs │ └── OnPropertyChangedSimpleLambda.cs ├── ObservableExtTests.AsReadOnlyView.cs ├── ObservableExtTests.Chunks.cs ├── ObservableExtTests.Throttle.cs ├── ObservableExtTests.WithPrevious.cs ├── ReadOnlyViews │ ├── CrudSource │ │ ├── CrudSourceTests.cs │ │ ├── ReadOnlyFilteredView.cs │ │ ├── ReadOnlyFilteredViewMappedView.cs │ │ ├── ReadOnlyFilteredViewNoScheduler.cs │ │ ├── ReadOnlyThrottledView.cs │ │ └── ReadOnlyThrottledViewNoScheduler.cs │ ├── ExtensionsTests.cs │ ├── Filter │ │ ├── ReadOnlyFilteredViewTests.cs │ │ └── ThrowingEnumerable.cs │ ├── MappingViewTests.Creating.cs │ ├── MappingViewTests.CreatingUpdating.cs │ ├── MappingViewTests.CreatingUpdatingRemoving.cs │ ├── MappingViewTests.FromObservable.cs │ ├── MappingViewTests.Nested.cs │ ├── MappingViewTests.ReferenceType.cs │ ├── MappingViewTests.ReferenceTypeCreatingCachingRemoving.cs │ ├── MappingViewTests.ValueTypeCreatingRemoving.cs │ ├── MappingViewTests.cs │ ├── ReadOnlyFilteredViewTests.cs │ └── ReadOnlySerialViewTests.cs ├── Reflection │ ├── GetterTests.cs │ └── PropertyPathParserTests.cs ├── Sandbox │ └── ItemsObservableBox.cs ├── SerialDisposableTests.cs └── Trackers │ ├── DoubleAverageTrackerTests.cs │ ├── MaxTrackerTests.Nested.cs │ ├── MaxTrackerTests.Simple.cs │ ├── MinMaxTrackerTests.Nested.cs │ ├── MinMaxTrackerTests.Simple.cs │ ├── MinTrackerTests.Nested.cs │ └── MinTrackerTests.Simple.cs ├── Gu.Reactive.sln ├── Gu.Reactive.sln.DotSettings ├── Gu.Reactive.snk ├── Gu.Reactive ├── .editorconfig ├── AssemblyAttributes.cs ├── Chunk{T}.cs ├── Collections │ ├── CollectionSynchronizer{T}.cs │ ├── FixedSizedQueue{T}.cs │ ├── Internals │ │ ├── CollectionDebugView.cs │ │ ├── Diff.cs │ │ └── ThrowHelper.cs │ ├── ObservableBatchCollection{T}.cs │ ├── ObservableFixedSizeQueue{T}.cs │ └── ObservableSet{T}.cs ├── Conditions │ ├── AbstractCondition.cs │ ├── AndCondition.cs │ ├── CollectionCondition.cs │ ├── Condition.cs │ ├── ConditionCollection.cs │ ├── ConditionExt.cs │ ├── ConditionHistoryPoint.cs │ ├── Internals │ │ ├── AndConditionCollection.cs │ │ ├── CollectionConditionDebugView.cs │ │ └── OrConditionCollection.cs │ ├── Negated.cs │ ├── NegatedCondition.cs │ ├── NullIsFalse.cs │ ├── ObservableAndCriteria.cs │ └── OrCondition.cs ├── Contracts │ ├── ICondition.cs │ ├── IFilteredView{T}.cs │ ├── IMaybe.cs │ ├── IObservableCollection{T}.cs │ ├── IObservableSet.cs │ ├── IReadOnlyFilteredView{T}.cs │ ├── IReadOnlyObservableCollection{T}.cs │ ├── IReadOnlyThrottledView{T}.cs │ ├── IReadOnlyView.cs │ ├── IReadonlySet{T}.cs │ ├── IRefreshAble.cs │ ├── ISatisfied.cs │ ├── ISchedulers.cs │ ├── IThrottledView{T}.cs │ └── IWpfSchedulers.cs ├── EventArgs │ ├── CachedEventArgs.cs │ ├── ItemPropertyChangedEventArgs{TItem,TValue}.cs │ └── NotifyCollectionChangedEventArgsExt.cs ├── ForegroundScheduler.cs ├── Gu.Reactive.csproj ├── Gu.Reactive.csproj.DotSettings ├── Internals │ ├── Chunk.cs │ ├── ConcurrentQueueExt.cs │ ├── Exceptions.cs │ ├── Extensions │ │ ├── EnumerableExt.cs │ │ ├── ExpressionExt.cs │ │ ├── IListExt.cs │ │ ├── LazyExt.cs │ │ └── SetExt.cs │ ├── IdentityMap.cs │ ├── IdentityMap{TKey,TValue}.cs │ ├── IdentitySet.cs │ ├── IdentitySet{T}.cs │ ├── ItemsTracker │ │ ├── ItemsTracker.cs │ │ ├── ItemsTrackerSlim.cs │ │ ├── ItemsTracker{TCollection,TItem,TProperty}.cs │ │ ├── NestedItemsTrackerSlim.cs │ │ ├── NestedItemsTracker{TCollection,TItem,TProperty}.cs │ │ ├── SimpleItemsTrackerSlim.cs │ │ ├── SimpleItemsTracker{TCollection,TItem,TProperty}.cs │ │ └── TrackedItemPropertyChangedEventHandler.cs │ ├── ObjectIdentityComparer{T}.cs │ ├── PropertyPath │ │ ├── INotifyingGetter.cs │ │ ├── IPropertyPath.cs │ │ ├── NotifyingGetter.cs │ │ ├── NotifyingPath.cs │ │ ├── NotifyingPath{TNotifier,TProperty}.cs │ │ ├── PropertyPathParser.cs │ │ └── PropertyPath{TSource,TValue}.cs │ ├── PropertyTracker │ │ ├── IPropertyPathTracker.cs │ │ ├── IPropertyTracker.cs │ │ ├── IPropertyTracker{TValue}.cs │ │ ├── PropertyPathTracker.cs │ │ ├── PropertyTracker.cs │ │ └── TrackedPropertyChangedEventHandler.cs │ ├── RwLock.cs │ └── SetPool.cs ├── Maybe.cs ├── Maybe{T}.cs ├── NameOf.cs ├── NotifyCollectionChangedEventArgs{T}.cs ├── NotifyCollectionChangedExt.cs ├── NotifyCollectionChangedExt.generated.cs ├── NotifyCollectionChangedExt.tt ├── NotifyPropertyChangedExt.cs ├── ObservableExt.cs ├── Obsolete │ ├── IConditionsService.cs │ ├── NameOf.Obsolete.cs │ ├── NotifyCollectionChangedExt.Obsolete.cs │ ├── NotifyPropertyChangedExt.Obsolete.cs │ ├── PropertyChangedAndValueEventArgs{TProperty}.cs │ └── TaskExt.cs ├── PublicAPI.Shipped.txt ├── PublicAPI.Unshipped.txt ├── ReadOnlyViews │ ├── Filtered.cs │ ├── Mapping │ │ ├── CreatingCachingRemoving{TSource,TResult}.cs │ │ ├── CreatingCaching{TSource,TResult}.cs │ │ ├── CreatingRemoving{TSource,TResult}.cs │ │ ├── Creating{TSource,TResult}.cs │ │ ├── IMapper{TSource,TResult}.cs │ │ ├── InstanceMap.cs │ │ ├── Mapper.cs │ │ ├── RefCounter{T}.cs │ │ ├── UpdatingRemoving{TSource,TResult}.cs │ │ └── Updating{TSource,TResult}.cs │ ├── MappingView.Create.cs │ ├── MappingView.generated.cs │ ├── MappingView.tt │ ├── MappingView{TSource,TResult}.cs │ ├── MappingView{TSource,TResult}.generated.cs │ ├── MappingView{TSource,TResult}.tt │ ├── ReadOnlyFilteredView.Create.cs │ ├── ReadOnlyFilteredView.FromObservable.cs │ ├── ReadOnlyFilteredView.generated.cs │ ├── ReadOnlyFilteredView.tt │ ├── ReadOnlyFilteredView{T}.cs │ ├── ReadOnlyFilteredView{T}.generated.cs │ ├── ReadOnlyFilteredView{T}.tt │ ├── ReadOnlyIListView{T}.cs │ ├── ReadOnlySerialViewBase.cs │ ├── ReadOnlySerialView{T}.cs │ ├── ReadOnlyThrottledView.generated.cs │ ├── ReadOnlyThrottledView.tt │ ├── ReadOnlyThrottledView{T}.cs │ ├── ReadonlyIListView.cs │ └── ReadonlyViewBase{TSource,TMapped}.cs ├── Reflection │ ├── Comparers │ │ ├── MemberExpressionComparer.cs │ │ └── PropertyPathComparer.cs │ └── Getter │ │ ├── ClassGetter{TSource,TValue}.cs │ │ ├── Getter.cs │ │ ├── Getter{TSource,TValue}.cs │ │ ├── IGetter.cs │ │ ├── IGetter{TSource,TValue}.cs │ │ ├── IGetter{TValue}.cs │ │ ├── IdentityGetter.cs │ │ └── StructGetter{TSource,TValue}.cs ├── Schedulers.cs ├── SerialDisposable{T}.cs ├── SourceAndValue.cs ├── SourceAndValue{TSource,TValue}.cs ├── Trackers │ ├── DoubleAverageTracker.cs │ ├── Internals │ │ ├── IChanges.cs │ │ ├── ITracker{TValue}.cs │ │ ├── NestedChanges{TCollection,TItem,TValue}.cs │ │ └── SimpleChanges{TCollection,TValue}.cs │ ├── Mapper{TSource,TResult}.cs │ ├── MaxTracker.generated.cs │ ├── MaxTracker.tt │ ├── MaxTracker{TValue}.cs │ ├── MinMaxTracker.generated.cs │ ├── MinMaxTracker.tt │ ├── MinMaxTracker{TValue}.cs │ ├── MinTracker.generated.cs │ ├── MinTracker.tt │ ├── MinTracker{TValue}.cs │ └── Tracker{TValue}.cs ├── TypeExt.cs ├── WithMaybePrevious{T}.cs └── WithPrevious{T}.cs ├── Gu.Wpf.Reactive.Tests ├── .editorconfig ├── AssemblyAttributes.cs ├── AssertCompletion.cs ├── Collections │ ├── DispatchingCollection │ │ ├── DispatchingCollectionTests.cs │ │ └── WhenBound.cs │ ├── ObservableCollectionExtensionsTests.cs │ └── ReadOnlyDispatchingViewTests.cs ├── Commands │ ├── AsyncCommandHelpers │ │ └── NotifyTaskCompletionTests.cs │ ├── AsyncCommandTests.cs │ ├── AsyncParameterCommandTests.cs │ ├── ConditionParameterRelayCommandTests.cs │ ├── ConditionRelayCommandTests.cs │ ├── ManualParameterRelayCommandTests.cs │ ├── ManualRelayCommandTests.cs │ └── ObservingRelayCommandTests.cs ├── FakesAndHelpers │ ├── App.cs │ ├── CommandListener.cs │ ├── DumpIfDebug.cs │ ├── TestDispatcherScheduler.cs │ └── TestExtensions.cs ├── Gu.Wpf.Reactive.Tests.csproj ├── Gu.Wpf.Reactive.Tests.csproj.DotSettings ├── NamespacesTests.cs └── Views │ ├── CrudSource │ ├── FilteredViewNoScheduler.cs │ ├── FilteredViewThrottledWithTestScheduler.cs │ ├── ThrottledViewNoScheduler.cs │ └── ThrottledViewWithScheduler.cs │ ├── CrudView │ ├── CrudViewTests.cs │ ├── DispatchingView.cs │ ├── FilteredViewNoThrottling.cs │ ├── FilteredViewThrottledWithTestScheduler.cs │ └── ThrottledViewWithScheduler.cs │ ├── DispatchingViewTests.cs │ ├── ExtensionsTests.cs │ ├── FilterTests │ ├── AbstractFilterTests.cs │ ├── FilterTestsWithDispatcher.cs │ ├── FilterTestsWithTestScheduler.cs │ ├── Repros.cs │ ├── Triggers.cs │ └── WithDispatcher.cs │ └── ThrottledViewTests.cs ├── Gu.Wpf.Reactive.UiTests ├── .editorconfig ├── AssemblyAttributes.cs ├── AsyncCommandsWindowTests.cs ├── CommandsWindowTests.cs ├── ConditionControlWindowTests.cs ├── DispatchingCollectionWindowTests.cs ├── DispatchingViewWindowTests.cs ├── FilteredDispatchingWindowTests.cs ├── Gu.Wpf.Reactive.UiTests.csproj ├── Gu.Wpf.Reactive.UiTests.csproj.DotSettings ├── Helpers │ ├── AutomationElementExt.cs │ ├── Changes.cs │ ├── GridExt.cs │ └── Info.cs ├── MainWindowTests.cs ├── MappingViewWindowTests.cs ├── ReadOnlyFilteredViewWindowTests.cs ├── ReadOnlySerialViewWindowTests.cs ├── ReadOnlyThrottledViewWindowTests.cs └── ReadonlyFilteredDispatchingWindowTests.cs ├── Gu.Wpf.Reactive ├── .editorconfig ├── AssemblyAttributes.cs ├── Commands │ ├── AsyncCommand.cs │ ├── AsyncCommandHelpers │ │ ├── ConditionAndDisposable.cs │ │ ├── INotifyTaskCompletion.cs │ │ ├── ITaskRunner.cs │ │ ├── ITaskRunner{TParameter}.cs │ │ ├── NotifyTaskCompletion.cs │ │ ├── NotifyTaskCompletionBase.cs │ │ ├── NotifyTaskCompletion{TResult}.cs │ │ ├── TaskRunner.cs │ │ ├── TaskRunnerBase.cs │ │ ├── TaskRunnerCancelable.cs │ │ ├── TaskRunnerCancelable{TParameter}.cs │ │ ├── TaskRunner{TParameter}.cs │ │ └── VoidTypeStruct.cs │ ├── AsyncCommand{TParameter}.cs │ ├── CanExecuteChangedEventManager.cs │ ├── CommandBase{T}.cs │ ├── ConditionRelayCommand.cs │ ├── ConditionRelayCommand{T}.cs │ ├── IAsyncCommand.cs │ ├── IConditionRelayCommand.cs │ ├── ManualRelayCommand.cs │ ├── ManualRelayCommand{T}.cs │ ├── ObservingRelayCommand.cs │ ├── ObservingRelayCommand{T}.cs │ ├── RelayCommand.cs │ └── RelayCommand{T}.cs ├── ConditionControl.Keys.cs ├── ConditionControl.cs ├── ConditionToolTip.cs ├── ConditionTypeTemplateSelector.cs ├── Converters │ └── ConditionHistoryToStringConverter.cs ├── Gu.Wpf.Reactive.csproj ├── Gu.Wpf.Reactive.csproj.DotSettings ├── Internals │ ├── BindingHelper.cs │ └── BoolBoxes.cs ├── MarkupExtensions │ ├── EnumValuesForExtension.cs │ ├── NinjaBinding.cs │ └── RootObjectExtension.cs ├── Obsolete │ ├── DispatchingCollection{T}.cs │ ├── DispatchingView.generated.cs │ ├── DispatchingView.tt │ ├── DispatchingView{T}.cs │ ├── NotifyCollectionChangedEventHandlerExt.cs │ ├── ObservableCollectionExtensions.cs │ ├── ReadOnlyDispatchingView.generated.cs │ ├── ReadOnlyDispatchingView.tt │ ├── ReadOnlyDispatchingView{T}.cs │ └── Schedulers.cs ├── PublicAPI.Shipped.txt ├── PublicAPI.Unshipped.txt ├── Themes │ ├── Assets.xaml │ ├── ConditionControl.xaml │ ├── ConditionToolTip.xaml │ └── Generic.xaml ├── Views │ ├── EditableListView.cs │ ├── EditableListView{T}.cs │ ├── FilteredView.generated.cs │ ├── FilteredView.tt │ ├── FilteredView{T}.cs │ ├── SynchronizedEditableView{T}.cs │ ├── ThrottledView.generated.cs │ ├── ThrottledView.tt │ └── ThrottledView{T}.cs └── WpfSchedulers.cs ├── LICENSE.md ├── README.md ├── RELEASE_NOTES.md ├── Settings.XamlStyler ├── appveyor.yml ├── azure-pipelines.yml └── stylecop.json /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: nuget 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | #ignore thumbnails created by windows 3 | Thumbs.db 4 | #Ignore files build by Visual Studio 5 | *.obj 6 | *.exe 7 | *.pdb 8 | *.user 9 | *.aps 10 | *.pch 11 | *.vspscc 12 | *_i.c 13 | *_p.c 14 | *.ncb 15 | *.suo 16 | *.tlb 17 | *.tlh 18 | *.bak 19 | *.cache 20 | *.ilk 21 | *.log 22 | [Bb]in 23 | [Dd]ebug*/ 24 | *.lib 25 | *.sbr 26 | obj/ 27 | [Rr]elease*/ 28 | _ReSharper*/ 29 | [Tt]est[Rr]esult* 30 | packages/* 31 | !packages/*ToolTips* 32 | publish/* 33 | packages/* 34 | .vs/* 35 | /paket-files/* 36 | /Gu.Reactive.Benchmarks/BenchmarkDotNet.Artifacts/* 37 | *.orig 38 | /msbuild.binlog 39 | -------------------------------------------------------------------------------- /Gu.Reactive.Analyzers.Tests/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # Default severity for analyzer diagnostics with category 'StyleCop.CSharp.DocumentationRules' 4 | dotnet_analyzer_diagnostic.category-StyleCop.CSharp.DocumentationRules.severity = none 5 | # SA0001: XML comment analysis is disabled due to project configuration 6 | dotnet_diagnostic.SA0001.severity = none 7 | # SA1203: Constants should appear before fields 8 | dotnet_diagnostic.SA1203.severity = none 9 | 10 | # CA1034: Nested types should not be visible 11 | dotnet_diagnostic.CA1034.severity = none 12 | # CA1711: Identifiers should not have incorrect suffix 13 | dotnet_diagnostic.CA1711.severity = none 14 | # CA1724: The type name Diagnostics conflicts in whole or in part with the namespace name 'System.Diagnostics' defined in the .NET Framework. Rename the type to eliminate the conflict. 15 | dotnet_diagnostic.CA1724.severity = none 16 | -------------------------------------------------------------------------------- /Gu.Reactive.Analyzers.Tests/AssemblyAttributes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | [assembly: CLSCompliant(false)] 4 | -------------------------------------------------------------------------------- /Gu.Reactive.Analyzers.Tests/GUREA11PreferObservableFromEventTests/CodeFix.MiscEventhandlers.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Analyzers.Tests.GUREA11PreferObservableFromEventTests 2 | { 3 | using Gu.Roslyn.Asserts; 4 | using NUnit.Framework; 5 | 6 | public static partial class CodeFix 7 | { 8 | public static class MiscEventHandlers 9 | { 10 | [Test] 11 | public static void WhenNotUsingSenderNorArgLambda() 12 | { 13 | var before = @" 14 | namespace N 15 | { 16 | using System; 17 | using System.IO; 18 | 19 | internal class C 20 | { 21 | public C() 22 | { 23 | var watcher = new FileSystemWatcher(); 24 | ↓watcher.Created += (sender, args) => { }; 25 | } 26 | } 27 | }"; 28 | 29 | var after = @" 30 | namespace N 31 | { 32 | using System; 33 | using System.IO; 34 | using System.Reactive.Linq; 35 | 36 | internal class C 37 | { 38 | public C() 39 | { 40 | var watcher = new FileSystemWatcher(); 41 | Observable.FromEvent( 42 | h => (_, e) => h(e), 43 | h => watcher.Created += h, 44 | h => watcher.Created -= h) 45 | .Subscribe(_ => { }); 46 | } 47 | } 48 | }"; 49 | RoslynAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, before, after); 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Gu.Reactive.Analyzers.Tests/GUREA11PreferObservableFromEventTests/CodeFix.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Analyzers.Tests.GUREA11PreferObservableFromEventTests 2 | { 3 | using Gu.Roslyn.Asserts; 4 | 5 | public static partial class CodeFix 6 | { 7 | private static readonly AddAssignmentAnalyzer Analyzer = new(); 8 | private static readonly EventSubscriptionToObserveFix Fix = new(); 9 | private static readonly ExpectedDiagnostic ExpectedDiagnostic = ExpectedDiagnostic.Create(Descriptors.GUREA11PreferObservableFromEvent); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Gu.Reactive.Analyzers.Tests/GUREA13SyncParametersAndArgsTests/Valid.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Analyzers.Tests.GUREA13SyncParametersAndArgsTests 2 | { 3 | using Gu.Roslyn.Asserts; 4 | using NUnit.Framework; 5 | 6 | public static class Valid 7 | { 8 | private static readonly ConstructorAnalyzer Analyzer = new(); 9 | 10 | private const string Condition1 = @" 11 | namespace N 12 | { 13 | using System.Reactive.Linq; 14 | using Gu.Reactive; 15 | 16 | public class Condition1 : Condition 17 | { 18 | public Condition1() 19 | : base(Observable.Never(), () => true) 20 | { 21 | } 22 | } 23 | }"; 24 | 25 | private const string Condition2 = @" 26 | namespace N 27 | { 28 | using System.Reactive.Linq; 29 | using Gu.Reactive; 30 | 31 | public class Condition2 : Condition 32 | { 33 | public Condition2() 34 | : base(Observable.Never(), () => true) 35 | { 36 | } 37 | } 38 | }"; 39 | 40 | [Test] 41 | public static void AndConditionSortArgs() 42 | { 43 | var code = @" 44 | namespace N 45 | { 46 | using Gu.Reactive; 47 | 48 | public class FooCondition : AndCondition 49 | { 50 | public FooCondition(Condition1 condition1, Condition2 condition2) 51 | : base(condition1, condition2) 52 | { 53 | } 54 | } 55 | }"; 56 | RoslynAssert.Valid(Analyzer, Condition1, Condition2, code); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Gu.Reactive.Analyzers.Tests/ModuleInitializer.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Analyzers.Tests 2 | { 3 | using System.Runtime.CompilerServices; 4 | using Gu.Roslyn.Asserts; 5 | 6 | internal static class ModuleInitializer 7 | { 8 | [ModuleInitializer] 9 | internal static void Initialize() 10 | { 11 | Settings.Default = Settings.Default 12 | .WithCompilationOptions(x => x.WithSuppressedDiagnostics("CS1701")) 13 | .WithMetadataReferences(MetadataReferences.Transitive(typeof(Gu.Wpf.Reactive.AsyncCommand))); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Gu.Reactive.Analyzers.Tests/ReproBox.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Analyzers.Tests 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.Linq; 7 | using Gu.Roslyn.Asserts; 8 | using Microsoft.CodeAnalysis; 9 | using Microsoft.CodeAnalysis.Diagnostics; 10 | using NUnit.Framework; 11 | 12 | [Explicit] 13 | public class ReproBox 14 | { 15 | // ReSharper disable once UnusedMember.Local 16 | private static readonly IReadOnlyList AllAnalyzers = 17 | typeof(KnownSymbol).Assembly.GetTypes() 18 | .Where(typeof(DiagnosticAnalyzer).IsAssignableFrom) 19 | .Select(t => (DiagnosticAnalyzer)Activator.CreateInstance(t)!) 20 | .ToArray(); 21 | 22 | private static readonly Solution Solution = CodeFactory.CreateSolution( 23 | new FileInfo("C:\\Git\\Gu.State\\Gu.State.sln")); 24 | 25 | [TestCaseSource(nameof(AllAnalyzers))] 26 | public void SolutionRepro(DiagnosticAnalyzer analyzer) 27 | { 28 | RoslynAssert.Valid(analyzer, Solution); 29 | } 30 | 31 | [TestCaseSource(nameof(AllAnalyzers))] 32 | public void Repro(DiagnosticAnalyzer analyzer) 33 | { 34 | var code = @" 35 | namespace N 36 | { 37 | public sealed class C 38 | { 39 | } 40 | }"; 41 | 42 | RoslynAssert.Valid(analyzer, code); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Gu.Reactive.Analyzers/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # Default severity for analyzer diagnostics with category 'StyleCop.CSharp.DocumentationRules' 4 | dotnet_analyzer_diagnostic.category-StyleCop.CSharp.DocumentationRules.severity = none 5 | # SA0001: XML comment analysis is disabled due to project configuration 6 | dotnet_diagnostic.SA0001.severity = none 7 | # SA1401: Fields should be private 8 | dotnet_diagnostic.SA1401.severity = none 9 | 10 | # CA1051: Do not declare visible instance fields 11 | dotnet_diagnostic.CA1051.severity = none 12 | # CA1710: Identifiers should have correct suffix 13 | dotnet_diagnostic.CA1710.severity = none 14 | # CA1716: Identifiers should not match keywords 15 | dotnet_diagnostic.CA1716.severity = none 16 | 17 | # RS2008: Enable analyzer release tracking 18 | dotnet_diagnostic.RS2008.severity = none 19 | -------------------------------------------------------------------------------- /Gu.Reactive.Analyzers/AnalyzerCategory.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Analyzers 2 | { 3 | internal class AnalyzerCategory 4 | { 5 | internal const string Correctness = "Gu.Reactive.Analyzers.Correctness"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Gu.Reactive.Analyzers/Analyzers/AddAssignmentAnalyzer.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Analyzers 2 | { 3 | using System.Collections.Immutable; 4 | using Gu.Roslyn.AnalyzerExtensions; 5 | using Microsoft.CodeAnalysis; 6 | using Microsoft.CodeAnalysis.CSharp; 7 | using Microsoft.CodeAnalysis.CSharp.Syntax; 8 | using Microsoft.CodeAnalysis.Diagnostics; 9 | 10 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 11 | internal class AddAssignmentAnalyzer : DiagnosticAnalyzer 12 | { 13 | public override ImmutableArray SupportedDiagnostics { get; } = 14 | ImmutableArray.Create(Descriptors.GUREA11PreferObservableFromEvent); 15 | 16 | public override void Initialize(AnalysisContext context) 17 | { 18 | context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); 19 | context.EnableConcurrentExecution(); 20 | context.RegisterSyntaxNodeAction(HandleInvocation, SyntaxKind.AddAssignmentExpression); 21 | } 22 | 23 | private static void HandleInvocation(SyntaxNodeAnalysisContext context) 24 | { 25 | if (!context.IsExcludedFromAnalysis() && 26 | context.Node is AssignmentExpressionSyntax { Left: { } left } assignment && 27 | assignment.FirstAncestor() is null && 28 | context.SemanticModel.GetSymbolSafe(left, context.CancellationToken) is IEventSymbol _) 29 | { 30 | context.ReportDiagnostic(Diagnostic.Create(Descriptors.GUREA11PreferObservableFromEvent, assignment.GetLocation())); 31 | } 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Gu.Reactive.Analyzers/AssemblyAttributes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | [assembly: CLSCompliant(false)] 4 | -------------------------------------------------------------------------------- /Gu.Reactive.Analyzers/Helpers/KnownSymbols/IConditionType.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Analyzers 2 | { 3 | using Gu.Roslyn.AnalyzerExtensions; 4 | 5 | internal class IConditionType : QualifiedType 6 | { 7 | internal readonly QualifiedMethod Negate; 8 | 9 | internal IConditionType() 10 | : base("Gu.Reactive.ICondition") 11 | { 12 | this.Negate = new QualifiedMethod(this, nameof(this.Negate)); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Gu.Reactive.Analyzers/Helpers/KnownSymbols/NotifyPropertyChangedExtType.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Analyzers 2 | { 3 | using Gu.Roslyn.AnalyzerExtensions; 4 | 5 | internal class NotifyPropertyChangedExtType : QualifiedType 6 | { 7 | internal readonly QualifiedMethod ObservePropertyChanged; 8 | internal readonly QualifiedMethod ObservePropertyChangedSlim; 9 | internal readonly QualifiedMethod ObserveFullPropertyPathSlim; 10 | 11 | internal NotifyPropertyChangedExtType() 12 | : base("Gu.Reactive.NotifyPropertyChangedExt") 13 | { 14 | this.ObservePropertyChanged = new QualifiedMethod(this, nameof(this.ObservePropertyChanged)); 15 | this.ObservePropertyChangedSlim = new QualifiedMethod(this, nameof(this.ObservePropertyChangedSlim)); 16 | this.ObserveFullPropertyPathSlim = new QualifiedMethod(this, nameof(this.ObserveFullPropertyPathSlim)); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Gu.Reactive.Analyzers/Helpers/KnownSymbols/NullableOfTType.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Analyzers 2 | { 3 | using Gu.Roslyn.AnalyzerExtensions; 4 | 5 | internal class NullableOfTType : QualifiedType 6 | { 7 | internal readonly QualifiedProperty Value; 8 | internal readonly QualifiedProperty HasValue; 9 | 10 | internal NullableOfTType() 11 | : base("System.Nullable`1") 12 | { 13 | this.Value = new QualifiedProperty(this, nameof(this.Value)); 14 | this.HasValue = new QualifiedProperty(this, nameof(this.HasValue)); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Gu.Reactive.Analyzers/Helpers/KnownSymbols/ObservableExtensionsType.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Analyzers 2 | { 3 | using Gu.Roslyn.AnalyzerExtensions; 4 | 5 | internal class ObservableExtensionsType : QualifiedType 6 | { 7 | internal readonly QualifiedMethod Subscribe; 8 | 9 | internal ObservableExtensionsType() 10 | : base("System.ObservableExtensions") 11 | { 12 | this.Subscribe = new QualifiedMethod(this, nameof(this.Subscribe)); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Gu.Reactive.Analyzers/Helpers/KnownSymbols/ObservableType.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Analyzers 2 | { 3 | using Gu.Roslyn.AnalyzerExtensions; 4 | 5 | internal class ObservableType : QualifiedType 6 | { 7 | internal readonly QualifiedMethod Merge; 8 | internal readonly QualifiedMethod FromEvent; 9 | internal readonly QualifiedMethod Interval; 10 | 11 | internal ObservableType() 12 | : base("System.Reactive.Linq.Observable") 13 | { 14 | this.Merge = new QualifiedMethod(this, nameof(this.Merge)); 15 | this.FromEvent = new QualifiedMethod(this, nameof(this.FromEvent)); 16 | this.Interval = new QualifiedMethod(this, nameof(this.Interval)); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Gu.Reactive.Analyzers/Helpers/KnownSymbols/StringType.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Analyzers 2 | { 3 | using Gu.Roslyn.AnalyzerExtensions; 4 | 5 | internal class StringType : QualifiedType 6 | { 7 | internal readonly QualifiedMethod Format; 8 | 9 | internal StringType() 10 | : base("System.String", "string") 11 | { 12 | this.Format = new QualifiedMethod(this, nameof(this.Format)); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Gu.Reactive.Analyzers/InternalsVisibleTo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo("Gu.Reactive.Analyzers.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100AB5BC1D032E9E344649AF43E93555B9F69733DCB59951999FEF8A5ADAB5985D5D27DFC91615F062B1AE47FACC549F07E182E0D1F247D587DB83ED87524E18E806336EAEAEB87271C60C790693A3BD6A199D896DD8ED367FD3B3E350B1B0DD78F8BD212872805939C337D96F104DAF36B79ABCEB6D3C7F0F951CC9880A66846AB")] 4 | [assembly: InternalsVisibleTo("Gu.Reactive.Benchmarks, PublicKey=0024000004800000940000000602000000240000525341310004000001000100AB5BC1D032E9E344649AF43E93555B9F69733DCB59951999FEF8A5ADAB5985D5D27DFC91615F062B1AE47FACC549F07E182E0D1F247D587DB83ED87524E18E806336EAEAEB87271C60C790693A3BD6A199D896DD8ED367FD3B3E350B1B0DD78F8BD212872805939C337D96F104DAF36B79ABCEB6D3C7F0F951CC9880A66846AB")] 5 | -------------------------------------------------------------------------------- /Gu.Reactive.Analyzers/Suppressors/Cs8620Suppressor.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Analyzers 2 | { 3 | using System.Collections.Immutable; 4 | using System.Globalization; 5 | using System.Text.RegularExpressions; 6 | using Microsoft.CodeAnalysis; 7 | using Microsoft.CodeAnalysis.Diagnostics; 8 | 9 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 10 | internal class Cs8620Suppressor : DiagnosticSuppressor 11 | { 12 | private static readonly SuppressionDescriptor Descriptor = new SuppressionDescriptor( 13 | nameof(Cs8620Suppressor), 14 | "CS8620", 15 | "No way to declare out T in structs and classes."); 16 | 17 | public override ImmutableArray SupportedSuppressions { get; } = ImmutableArray.Create( 18 | Descriptor); 19 | 20 | public override void ReportSuppressions(SuppressionAnalysisContext context) 21 | { 22 | foreach (var diagnostic in context.ReportedDiagnostics) 23 | { 24 | if (diagnostic.GetMessage(CultureInfo.InvariantCulture) is { } message && 25 | IsOut(message)) 26 | { 27 | context.ReportSuppression(Suppression.Create(Descriptor, diagnostic)); 28 | } 29 | 30 | static bool IsOut(string message) 31 | { 32 | return Regex.IsMatch(message, "Argument of type '.*Maybe<.+>>*' cannot be used for parameter '[^']+' of type '.*Maybe<.+\\?>>*'") || 33 | Regex.IsMatch(message, "Argument of type '.*PropertyChangedAndValueEventArgs<.+>>*' cannot be used for parameter '[^']+' of type '.*PropertyChangedAndValueEventArgs<.+\\?>>*'"); 34 | } 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Gu.Reactive.Analyzers/tools/install.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | $analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers" ) * -Resolve 4 | 5 | foreach($analyzersPath in $analyzersPaths) 6 | { 7 | # Install the language agnostic analyzers. 8 | if (Test-Path $analyzersPath) 9 | { 10 | foreach ($analyzerFilePath in Get-ChildItem $analyzersPath -Filter *.dll) 11 | { 12 | if($project.Object.AnalyzerReferences) 13 | { 14 | $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) 15 | } 16 | } 17 | } 18 | } 19 | 20 | $project.Type # gives the language name like (C# or VB.NET) 21 | $languageFolder = "" 22 | if($project.Type -eq "C#") 23 | { 24 | $languageFolder = "cs" 25 | } 26 | if($project.Type -eq "VB.NET") 27 | { 28 | $languageFolder = "vb" 29 | } 30 | if($languageFolder -eq "") 31 | { 32 | return 33 | } 34 | 35 | foreach($analyzersPath in $analyzersPaths) 36 | { 37 | # Install language specific analyzers. 38 | $languageAnalyzersPath = join-path $analyzersPath $languageFolder 39 | if (Test-Path $languageAnalyzersPath) 40 | { 41 | foreach ($analyzerFilePath in Get-ChildItem $languageAnalyzersPath -Filter *.dll) 42 | { 43 | if($project.Object.AnalyzerReferences) 44 | { 45 | $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) 46 | } 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /Gu.Reactive.Analyzers/tools/uninstall.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | $analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers" ) * -Resolve 4 | 5 | foreach($analyzersPath in $analyzersPaths) 6 | { 7 | # Uninstall the language agnostic analyzers. 8 | if (Test-Path $analyzersPath) 9 | { 10 | foreach ($analyzerFilePath in Get-ChildItem $analyzersPath -Filter *.dll) 11 | { 12 | if($project.Object.AnalyzerReferences) 13 | { 14 | $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) 15 | } 16 | } 17 | } 18 | } 19 | 20 | $project.Type # gives the language name like (C# or VB.NET) 21 | $languageFolder = "" 22 | if($project.Type -eq "C#") 23 | { 24 | $languageFolder = "cs" 25 | } 26 | if($project.Type -eq "VB.NET") 27 | { 28 | $languageFolder = "vb" 29 | } 30 | if($languageFolder -eq "") 31 | { 32 | return 33 | } 34 | 35 | foreach($analyzersPath in $analyzersPaths) 36 | { 37 | # Uninstall language specific analyzers. 38 | $languageAnalyzersPath = join-path $analyzersPath $languageFolder 39 | if (Test-Path $languageAnalyzersPath) 40 | { 41 | foreach ($analyzerFilePath in Get-ChildItem $languageAnalyzersPath -Filter *.dll) 42 | { 43 | if($project.Object.AnalyzerReferences) 44 | { 45 | try 46 | { 47 | $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) 48 | } 49 | catch 50 | { 51 | 52 | } 53 | } 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # Default severity for analyzer diagnostics with category 'StyleCop.CSharp.DocumentationRules' 4 | dotnet_analyzer_diagnostic.category-StyleCop.CSharp.DocumentationRules.severity = none 5 | # SA0001: XML comment analysis is disabled due to project configuration 6 | dotnet_diagnostic.SA0001.severity = none 7 | 8 | # CA1044: Properties should not be write only 9 | dotnet_diagnostic.CA1044.severity = none 10 | # CA1062: Validate arguments of public methods 11 | dotnet_diagnostic.CA1062.severity = none 12 | # CA1724: The type name Caching conflicts in whole or in part with the namespace name 'System.Web.Caching' defined in the .NET Framework. Rename the type to eliminate the conflict. 13 | dotnet_diagnostic.CA1724.severity = none 14 | # CA1716: Identifiers should not match keywords 15 | dotnet_diagnostic.CA1716.severity = none 16 | # CA1822: Mark members as static 17 | dotnet_diagnostic.CA1822.severity = none 18 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/AssemblyAttributes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | [assembly: CLSCompliant(false)] 4 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Benchmarks/AddAssignmentAnalyzerBenchmarks.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantNameQualifier 2 | namespace Gu.Reactive.Benchmarks 3 | { 4 | [BenchmarkDotNet.Attributes.MemoryDiagnoser] 5 | public class AddAssignmentAnalyzerBenchmarks 6 | { 7 | private static readonly Gu.Roslyn.Asserts.Benchmark Benchmark = Gu.Roslyn.Asserts.Benchmark.Create(Code.AnalyzersProject, new Gu.Reactive.Analyzers.AddAssignmentAnalyzer()); 8 | 9 | [BenchmarkDotNet.Attributes.Benchmark] 10 | public void RunOnAnalyzerProject() 11 | { 12 | Benchmark.Run(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Benchmarks/AddAssignmentAnalyzerBenchmarks.md: -------------------------------------------------------------------------------- 1 | ``` ini 2 | 3 | BenchmarkDotNet=v0.10.10, OS=Windows 7 SP1 (6.1.7601.0) 4 | Processor=Intel Xeon CPU E5-2637 v4 3.50GHzIntel Xeon CPU E5-2637 v4 3.50GHz, ProcessorCount=16 5 | Frequency=3410117 Hz, Resolution=293.2451 ns, Timer=TSC 6 | [Host] : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2116.0 7 | DefaultJob : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2116.0 8 | 9 | 10 | ``` 11 | | Method | Mean | Error | StdDev | Gen 0 | Gen 1 | Allocated | 12 | |-------------------------- |---------:|---------:|---------:|-------:|-------:|----------:| 13 | | RunOnIDisposableAnalyzers | 35.73 us | 1.064 us | 3.035 us | 0.3052 | 0.0684 | 2.07 KB | 14 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Benchmarks/CodeGen/Code.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Benchmarks 2 | { 3 | using Gu.Roslyn.Asserts; 4 | using Microsoft.CodeAnalysis; 5 | 6 | public static class Code 7 | { 8 | public static Solution AnalyzersProject { get; } = CodeFactory.CreateSolution( 9 | ProjectFile.Find("Gu.Reactive.Benchmarks.csproj")); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Benchmarks/ConstructorAnalyzerBenchmarks.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantNameQualifier 2 | namespace Gu.Reactive.Benchmarks 3 | { 4 | [BenchmarkDotNet.Attributes.MemoryDiagnoser] 5 | public class ConstructorAnalyzerBenchmarks 6 | { 7 | private static readonly Gu.Roslyn.Asserts.Benchmark Benchmark = Gu.Roslyn.Asserts.Benchmark.Create(Code.AnalyzersProject, new Gu.Reactive.Analyzers.ConstructorAnalyzer()); 8 | 9 | [BenchmarkDotNet.Attributes.Benchmark] 10 | public void RunOnAnalyzerProject() 11 | { 12 | Benchmark.Run(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Benchmarks/Cs8602SuppressorBenchmarks.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantNameQualifier 2 | namespace Gu.Reactive.Benchmarks 3 | { 4 | [BenchmarkDotNet.Attributes.MemoryDiagnoser] 5 | public class Cs8602SuppressorBenchmarks 6 | { 7 | private static readonly Gu.Roslyn.Asserts.Benchmark Benchmark = Gu.Roslyn.Asserts.Benchmark.Create(Code.AnalyzersProject, new Gu.Reactive.Analyzers.Cs8602Suppressor()); 8 | 9 | [BenchmarkDotNet.Attributes.Benchmark] 10 | public void RunOnAnalyzerProject() 11 | { 12 | Benchmark.Run(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Benchmarks/Cs8620SuppressorBenchmarks.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantNameQualifier 2 | namespace Gu.Reactive.Benchmarks 3 | { 4 | [BenchmarkDotNet.Attributes.MemoryDiagnoser] 5 | public class Cs8620SuppressorBenchmarks 6 | { 7 | private static readonly Gu.Roslyn.Asserts.Benchmark Benchmark = Gu.Roslyn.Asserts.Benchmark.Create(Code.AnalyzersProject, new Gu.Reactive.Analyzers.Cs8620Suppressor()); 8 | 9 | [BenchmarkDotNet.Attributes.Benchmark] 10 | public void RunOnAnalyzerProject() 11 | { 12 | Benchmark.Run(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Benchmarks/Diff.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Benchmarks 2 | { 3 | using System.Collections.Generic; 4 | using System.Collections.Specialized; 5 | using System.Linq; 6 | using BenchmarkDotNet.Attributes; 7 | 8 | public class Diff 9 | { 10 | private List x = null!; 11 | private List y = null!; 12 | 13 | [Params(10, 100, 1000)] 14 | public int N 15 | { 16 | set 17 | { 18 | this.x = CreateFakes(value); 19 | this.y = CreateFakes(value); 20 | } 21 | } 22 | 23 | [Benchmark] 24 | public NotifyCollectionChangedEventArgs? CollectionChange() 25 | { 26 | return Reactive.Diff.CollectionChange(this.x, this.y); 27 | } 28 | 29 | private static List CreateFakes(int n) 30 | { 31 | return Enumerable.Range(0, n) 32 | .Select(i => new Fake { Value = i }) 33 | .ToList(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Benchmarks/Diff.md: -------------------------------------------------------------------------------- 1 | ```ini 2 | 3 | BenchmarkDotNet=v0.9.7.0 4 | OS=Microsoft Windows NT 6.1.7601 Service Pack 1 5 | Processor=Intel(R) Xeon(R) CPU X5687 3.60GHz, ProcessorCount=8 6 | Frequency=3515830 ticks, Resolution=284.4279 ns, Timer=ACPI 7 | HostCLR=MS.NET 4.0.30319.42000, Arch=32-bit RELEASE 8 | JitModules=clrjit-v4.6.1087.0 9 | 10 | Type=Diff Mode=Throughput 11 | 12 | ``` 13 | Method | N | Median | StdDev | Gen 0 | Gen 1 | Gen 2 | Bytes Allocated/Op | 14 | ----------------- |----- |------------ |---------- |------ |------ |------ |------------------- | 15 | **CollectionChange** | **10** | **131.4031 ns** | **2.2953 ns** | **-** | **-** | **-** | **0,01** | 16 | **CollectionChange** | **100** | **123.9039 ns** | **3.4183 ns** | **-** | **-** | **-** | **0,01** | 17 | **CollectionChange** | **1000** | **129.4650 ns** | **2.2220 ns** | **-** | **-** | **-** | **0,01** | 18 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Benchmarks/InvocationAnalyzerBenchmarks.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable RedundantNameQualifier 2 | namespace Gu.Reactive.Benchmarks 3 | { 4 | [BenchmarkDotNet.Attributes.MemoryDiagnoser] 5 | public class InvocationAnalyzerBenchmarks 6 | { 7 | private static readonly Gu.Roslyn.Asserts.Benchmark Benchmark = Gu.Roslyn.Asserts.Benchmark.Create(Code.AnalyzersProject, new Gu.Reactive.Analyzers.InvocationAnalyzer()); 8 | 9 | [BenchmarkDotNet.Attributes.Benchmark] 10 | public void RunOnAnalyzerProject() 11 | { 12 | Benchmark.Run(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Benchmarks/InvocationAnalyzerBenchmarks.md: -------------------------------------------------------------------------------- 1 | ``` ini 2 | 3 | BenchmarkDotNet=v0.10.10, OS=Windows 7 SP1 (6.1.7601.0) 4 | Processor=Intel Xeon CPU E5-2637 v4 3.50GHzIntel Xeon CPU E5-2637 v4 3.50GHz, ProcessorCount=16 5 | Frequency=3410117 Hz, Resolution=293.2451 ns, Timer=TSC 6 | [Host] : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2116.0 7 | DefaultJob : .NET Framework 4.7 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.7.2116.0 8 | 9 | 10 | ``` 11 | | Method | Mean | Error | StdDev | Gen 0 | Allocated | 12 | |-------------------------- |---------:|----------:|----------:|-------:|----------:| 13 | | RunOnIDisposableAnalyzers | 1.331 ms | 0.0370 ms | 0.1067 ms | 9.7656 | 71.22 KB | 14 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Benchmarks/MinTrackerProperty.md: -------------------------------------------------------------------------------- 1 | ```ini 2 | 3 | BenchmarkDotNet=v0.9.7.0 4 | OS=Microsoft Windows NT 6.1.7601 Service Pack 1 5 | Processor=Intel(R) Xeon(R) CPU X5687 3.60GHz, ProcessorCount=8 6 | Frequency=3515830 ticks, Resolution=284.4279 ns, Timer=ACPI 7 | HostCLR=MS.NET 4.0.30319.42000, Arch=32-bit RELEASE 8 | JitModules=clrjit-v4.6.1087.0 9 | 10 | Type=MinTrackerProperty Mode=Throughput 11 | 12 | ``` 13 | Method | Median | StdDev | Scaled | Gen 0 | Gen 1 | Gen 2 | Bytes Allocated/Op | 14 | --------------- |------------ |---------- |------- |------ |------- |------ |------------------- | 15 | Linq | 237.8302 us | 7.6770 us | 1.00 | 36,00 | 120,00 | 35,00 | 14 184,72 | 16 | Tracker | 211.1851 us | 4.4753 us | 0.89 | 35,36 | 105,11 | 31,53 | 12 770,02 | 17 | TrackerChanges | 218.5361 us | 4.5327 us | 0.92 | 34,00 | 113,00 | 33,00 | 13 349,20 | 18 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Benchmarks/MinTrackerSimple.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Benchmarks 2 | { 3 | using System; 4 | using System.Collections.ObjectModel; 5 | using System.Linq; 6 | 7 | using BenchmarkDotNet.Attributes; 8 | 9 | [BenchmarkDotNet.Attributes.MemoryDiagnoser] 10 | public class MinTrackerSimple 11 | { 12 | private readonly ObservableCollection ints1 = new ObservableBatchCollection(); 13 | private readonly ObservableCollection ints2 = new ObservableBatchCollection(); 14 | 15 | [GlobalSetup] 16 | public void SetupData() 17 | { 18 | foreach (var ints in new[] { this.ints1, this.ints2 }) 19 | { 20 | ints.Clear(); 21 | for (var i = 0; i < 1000; i++) 22 | { 23 | ints.Add(i); 24 | } 25 | } 26 | } 27 | 28 | [Benchmark(Baseline = true)] 29 | public int? Linq() 30 | { 31 | var min = this.ints1.Min(x => x); 32 | Update(this.ints1); 33 | return Math.Min(min, this.ints1.Min(x => x)); 34 | } 35 | 36 | [Benchmark] 37 | public int? Tracker() 38 | { 39 | using var tracker = this.ints2.TrackMin(); 40 | Update(this.ints2); 41 | return tracker.Value; 42 | } 43 | 44 | private static void Update(ObservableCollection ints) 45 | { 46 | if (ints.Count > 1000) 47 | { 48 | ints.RemoveAt(ints.Count - 1); 49 | } 50 | else 51 | { 52 | ints.Add(5); 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Benchmarks/MinTrackerSimple.md: -------------------------------------------------------------------------------- 1 | ```ini 2 | 3 | BenchmarkDotNet=v0.9.7.0 4 | OS=Microsoft Windows NT 6.1.7601 Service Pack 1 5 | Processor=Intel(R) Xeon(R) CPU X5687 3.60GHz, ProcessorCount=8 6 | Frequency=3515830 ticks, Resolution=284.4279 ns, Timer=ACPI 7 | HostCLR=MS.NET 4.0.30319.42000, Arch=32-bit RELEASE 8 | JitModules=clrjit-v4.6.1087.0 9 | 10 | Type=MinTrackerSimple Mode=Throughput 11 | 12 | ``` 13 | Method | Median | StdDev | Scaled | Gen 0 | Gen 1 | Gen 2 | Bytes Allocated/Op | 14 | -------- |--------------- |-------------- |------- |------ |------ |------ |------------------- | 15 | Linq | 68,860.5767 ns | 1,153.1306 ns | 1.00 | - | - | - | 72,07 | 16 | Tracker | 153.6925 ns | 1.1579 ns | 0.00 | 2,47 | - | 0,21 | 46,74 | 17 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Benchmarks/NameOf.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS8602, CS8603 2 | namespace Gu.Reactive.Benchmarks 3 | { 4 | using BenchmarkDotNet.Attributes; 5 | 6 | [BenchmarkDotNet.Attributes.MemoryDiagnoser] 7 | public class NameOf 8 | { 9 | [Benchmark(Baseline = true)] 10 | public string UsingCsharp6Nameof() => nameof(Fake.Name); 11 | 12 | [Benchmark] 13 | public string Property() => Reactive.NameOf.Property(x => x.Name); 14 | 15 | [Benchmark] 16 | public string PropertyNested() => Reactive.NameOf.Property(x => x.Next.Next.Name); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Benchmarks/NameOf.md: -------------------------------------------------------------------------------- 1 | ```ini 2 | 3 | BenchmarkDotNet=v0.9.7.0 4 | OS=Microsoft Windows NT 6.1.7601 Service Pack 1 5 | Processor=Intel(R) Xeon(R) CPU X5687 3.60GHz, ProcessorCount=8 6 | Frequency=3515830 ticks, Resolution=284.4279 ns, Timer=ACPI 7 | HostCLR=MS.NET 4.0.30319.42000, Arch=32-bit RELEASE 8 | JitModules=clrjit-v4.6.1087.0 9 | 10 | Type=NameOf Mode=Throughput 11 | 12 | ``` 13 | Method | Median | StdDev | Scaled | Gen 0 | Gen 1 | Gen 2 | Bytes Allocated/Op | 14 | ------------------- |-------------- |----------- |-------------- |------- |------ |------ |------------------- | 15 | UsingCsharp6Nameof | 0.0002 ns | 0.0440 ns | 1.00 | - | - | - | 0,00 | 16 | Property | 3,502.2155 ns | 98.7658 ns | 14,592,926.82 | 100,00 | - | - | 200,39 | 17 | PropertyNested | 5,622.5324 ns | 38.5531 ns | 23,427,799.91 | 173,95 | - | - | 348,55 | 18 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Benchmarks/ObserveItemPropertyChanged.md: -------------------------------------------------------------------------------- 1 | ``` ini 2 | 3 | BenchmarkDotNet=v0.10.3.0, OS=Microsoft Windows NT 6.1.7601 Service Pack 1 4 | Processor=Intel(R) Xeon(R) CPU X5687 3.60GHz, ProcessorCount=8 5 | Frequency=3515820 Hz, Resolution=284.4287 ns, Timer=TSC 6 | [Host] : Clr 4.0.30319.42000, 32bit LegacyJIT-v4.6.1590.0 7 | DefaultJob : Clr 4.0.30319.42000, 32bit LegacyJIT-v4.6.1590.0 8 | 9 | 10 | ``` 11 | | Method | Mean | StdDev | Allocated | 12 | |--------------------------------------------------------------- |----------- |---------- |---------- | 13 | | ObserveItemPropertyChangedSlimSimpleLambdaAddOne | 8.3044 us | 0.2165 us | 1.58 kB | 14 | | ObserveItemPropertyChangedSlimThreeLevelLambdaAddOne | 12.7648 us | 0.1094 us | 2.28 kB | 15 | | ObserveItemPropertyChangedSlimThreeLevelLambdaAddOneThenUpdate | 13.5444 us | 0.1356 us | 2.36 kB | 16 | | ObserveItemPropertyChangedSimpleLambdaAddOne | 8.2538 us | 0.1722 us | 1.63 kB | 17 | | ObserveItemPropertyChangedThreeLevelLambdaAddOne | 12.6882 us | 0.3096 us | 2.33 kB | 18 | | ObserveItemPropertyChangedThreeLevelLambdaAddOneThenUpdate | 14.2532 us | 0.4211 us | 2.45 kB | 19 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Benchmarks/ObservePropertyChangedReact.md: -------------------------------------------------------------------------------- 1 | ```ini 2 | 3 | BenchmarkDotNet=v0.9.7.0 4 | OS=Microsoft Windows NT 6.1.7601 Service Pack 1 5 | Processor=Intel(R) Xeon(R) CPU X5687 3.60GHz, ProcessorCount=8 6 | Frequency=3515830 ticks, Resolution=284.4279 ns, Timer=ACPI 7 | HostCLR=MS.NET 4.0.30319.42000, Arch=32-bit RELEASE 8 | JitModules=clrjit-v4.6.1087.0 9 | 10 | Type=ObservePropertyChangedReact Mode=Throughput 11 | 12 | ``` 13 | Method | Median | StdDev | Scaled | Gen 0 | Gen 1 | Gen 2 | Bytes Allocated/Op | 14 | ---------------------------- |------------ |---------- |------- |------- |------ |------ |------------------- | 15 | SubscribeToEventStandard | 15.5067 ns | 0.9781 ns | 1.00 | 60,26 | - | - | 5,37 | 16 | SimpleLambda | 51.7613 ns | 2.4138 ns | 3.34 | 124,45 | - | - | 11,23 | 17 | Slim | 36.7900 ns | 1.2539 ns | 2.37 | 54,29 | - | - | 4,87 | 18 | Nested | 159.6342 ns | 0.9389 ns | 10.29 | 206,62 | - | - | 18,91 | 19 | Rx | 49.5527 ns | 3.9692 ns | 3.20 | 120,15 | - | - | 10,85 | 20 | PropertyChangedEventManager | 320.5120 ns | 4.6841 ns | 20.67 | 175,00 | - | - | 17,04 | 21 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Benchmarks/ThrottledView.md: -------------------------------------------------------------------------------- 1 | ```ini 2 | 3 | BenchmarkDotNet=v0.9.7.0 4 | OS=Microsoft Windows NT 6.1.7601 Service Pack 1 5 | Processor=Intel(R) Xeon(R) CPU X5687 3.60GHz, ProcessorCount=8 6 | Frequency=3515830 ticks, Resolution=284.4279 ns, Timer=ACPI 7 | HostCLR=MS.NET 4.0.30319.42000, Arch=32-bit RELEASE 8 | JitModules=clrjit-v4.6.1087.0 9 | 10 | Type=ThrottledView Mode=Throughput 11 | 12 | ``` 13 | Method | N | Median | StdDev | Scaled | Gen 0 | Gen 1 | Gen 2 | Bytes Allocated/Op | 14 | --------------- |----- |-------------- |----------- |------- |------- |------- |------ |------------------- | 15 | AddToReference | 1000 | 60.1432 us | 1.7285 us | 1.00 | 110,10 | - | - | 41 174,60 | 16 | AddToSource | 1000 | 1,457.7678 us | 28.7588 us | 24.24 | 56,87 | 235,37 | 45,50 | 142 862,64 | 17 | AddToView | 1000 | 1,388.9346 us | 52.8479 us | 23.09 | 60,00 | 215,00 | 56,00 | 137 162,16 | 18 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Gu.Reactive.Benchmarks.csproj.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | True -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Helpers/IFake.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Benchmarks 2 | { 3 | using System.ComponentModel; 4 | 5 | public interface IFake : INotifyPropertyChanged 6 | { 7 | int WriteOnly { set; } 8 | 9 | bool IsTrue { get; set; } 10 | 11 | string? Name { get; set; } 12 | 13 | Level? Next { get; set; } 14 | 15 | StructLevel StructLevel { get; set; } 16 | 17 | NotInpc? NotInpc { get; } 18 | 19 | int Value { get; set; } 20 | 21 | Level? Method(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Helpers/NotInpc.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Benchmarks 2 | { 3 | // ReSharper disable once ClassNeverInstantiated.Global 4 | #pragma warning disable INPC001 // Implement INotifyPropertyChanged. 5 | public class NotInpc 6 | { 7 | public bool IsTrue { get; set; } 8 | 9 | public bool? IsTrueOrNull { get; set; } 10 | 11 | public string? Name { get; set; } 12 | 13 | public int Value { get; set; } 14 | } 15 | #pragma warning restore INPC001 // Implement INotifyPropertyChanged. 16 | } 17 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/Helpers/StructLevel.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Benchmarks 2 | { 3 | using System.ComponentModel; 4 | 5 | #pragma warning disable INPC008 // Struct must not implement INotifyPropertyChanged 6 | #pragma warning disable CA1815 // Override equals and operator equals on value types 7 | public struct StructLevel : INotifyPropertyChanged 8 | #pragma warning restore CA1815 // Override equals and operator equals on value types 9 | #pragma warning restore INPC008 // Struct must not implement INotifyPropertyChanged 10 | { 11 | public event PropertyChangedEventHandler PropertyChanged 12 | { 13 | add { } 14 | remove { } 15 | } 16 | 17 | public string Name { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Gu.Reactive.Benchmarks/~$raceEventProgrammersGuide.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GuOrg/Gu.Reactive/3b18a966d1420871dc2af8b57d231690d6d4ae07/Gu.Reactive.Benchmarks/~$raceEventProgrammersGuide.docx -------------------------------------------------------------------------------- /Gu.Reactive.Demo/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # Default severity for analyzer diagnostics with category 'StyleCop.CSharp.DocumentationRules' 4 | dotnet_analyzer_diagnostic.category-StyleCop.CSharp.DocumentationRules.severity = none 5 | # SA0001: XML comment analysis is disabled due to project configuration 6 | dotnet_diagnostic.SA0001.severity = none 7 | 8 | # CA5394: Do not use insecure randomness 9 | dotnet_diagnostic.CA5394.severity = none 10 | # CA1034: Nested types should not be visible 11 | dotnet_diagnostic.CA1034.severity = none 12 | # CA2000: Dispose objects before losing scope 13 | dotnet_diagnostic.CA2000.severity = none 14 | # CA2201: Do not raise reserved exception types 15 | dotnet_diagnostic.CA2201.severity = none 16 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/App.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System; 4 | using System.Windows; 5 | 6 | public partial class App : Application 7 | { 8 | protected override void OnStartup(StartupEventArgs e) 9 | { 10 | if (e is { Args: { Length: 1 } args }) 11 | { 12 | var window = args[0]; 13 | this.StartupUri = new Uri($"UiTestWindows/{window}.xaml", UriKind.Relative); 14 | } 15 | 16 | base.OnStartup(e); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/AssemblyAttributes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows; 3 | 4 | [assembly: CLSCompliant(false)] 5 | [assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] 6 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/AsyncCommandsView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.Windows.Controls; 4 | 5 | public partial class AsyncCommandsView : UserControl 6 | { 7 | public AsyncCommandsView() 8 | { 9 | this.InitializeComponent(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Collections/DispatchingCollectionView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.Windows.Controls; 4 | 5 | public partial class DispatchingCollectionView : UserControl 6 | { 7 | public DispatchingCollectionView() 8 | { 9 | this.InitializeComponent(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Collections/DispatchingViewView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for DispatchingViewView.xaml. 7 | /// 8 | public partial class DispatchingViewView : UserControl 9 | { 10 | public DispatchingViewView() 11 | { 12 | this.InitializeComponent(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Collections/FilteredDispatchingView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.Windows.Controls; 4 | 5 | public partial class FilteredDispatchingView : UserControl 6 | { 7 | public FilteredDispatchingView() 8 | { 9 | this.InitializeComponent(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Collections/FilteredViewView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System; 4 | using System.Linq; 5 | using System.Windows.Controls; 6 | 7 | /// 8 | /// Interaction logic for FilteredViewView.xaml. 9 | /// 10 | public sealed partial class FilteredViewView : UserControl, IDisposable 11 | { 12 | private readonly FilteredViewViewModel vm; 13 | private bool disposed; 14 | 15 | public FilteredViewView() 16 | { 17 | this.InitializeComponent(); 18 | this.DataContext = this.vm = new FilteredViewViewModel(); 19 | } 20 | 21 | public void Dispose() 22 | { 23 | if (this.disposed) 24 | { 25 | return; 26 | } 27 | 28 | this.disposed = true; 29 | this.vm.Dispose(); 30 | } 31 | 32 | private void OnTagsSelectionChanged(object sender, SelectionChangedEventArgs e) 33 | { 34 | this.vm.SelectedTags = this.TagBox.SelectedItems.Cast(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Collections/MappedVm.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.ComponentModel; 4 | using System.Diagnostics; 5 | using System.Runtime.CompilerServices; 6 | 7 | [DebuggerDisplay("{GetType().Name} Value: {Value} Index: {Index}")] 8 | public class MappedVm : INotifyPropertyChanged 9 | { 10 | private int value; 11 | 12 | private int? index; 13 | 14 | public event PropertyChangedEventHandler? PropertyChanged; 15 | 16 | public int Value 17 | { 18 | get => this.value; 19 | 20 | set 21 | { 22 | if (value == this.value) 23 | { 24 | return; 25 | } 26 | 27 | this.value = value; 28 | this.OnPropertyChanged(); 29 | } 30 | } 31 | 32 | public int? Index 33 | { 34 | get => this.index; 35 | 36 | set 37 | { 38 | if (value == this.index) 39 | { 40 | return; 41 | } 42 | 43 | this.index = value; 44 | this.OnPropertyChanged(); 45 | } 46 | } 47 | 48 | public MappedVm UpdateIndex(int i) 49 | { 50 | this.Index = i; 51 | return this; 52 | } 53 | 54 | protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) => this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Collections/MappingViewView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for MappingViewView.xaml. 7 | /// 8 | public partial class MappingViewView : UserControl 9 | { 10 | public MappingViewView() 11 | { 12 | this.InitializeComponent(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Collections/ObservableFixedSizeQueueView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for ObservableFixedSizeQueueView.xaml. 7 | /// 8 | public partial class ObservableFixedSizeQueueView : UserControl 9 | { 10 | public ObservableFixedSizeQueueView() 11 | { 12 | this.InitializeComponent(); 13 | this.DataContext = new ObservableFixedSizeQueueViewModel(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Collections/ObservableFixedSizeQueueViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.Threading.Tasks; 4 | using System.Windows.Input; 5 | 6 | using Gu.Wpf.Reactive; 7 | 8 | public class ObservableFixedSizeQueueViewModel 9 | { 10 | private int count; 11 | 12 | public ObservableFixedSizeQueueViewModel() 13 | { 14 | this.EnqueueCommand = new RelayCommand(() => this.Queue.Enqueue(++this.count), () => true); 15 | this.EnqueueOnThreadCommand = new RelayCommand(() => Task.Run(() => this.Queue.Enqueue(++this.count)), () => true); 16 | } 17 | 18 | public ObservableFixedSizeQueue Queue { get; } = new ObservableFixedSizeQueue(5); 19 | 20 | public ICommand EnqueueCommand { get; } 21 | 22 | public ICommand EnqueueOnThreadCommand { get; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Collections/ReadOnlyFilteredViewView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for ReadOnlyFilteredViewView.xaml. 7 | /// 8 | public partial class ReadOnlyFilteredViewView : UserControl 9 | { 10 | public ReadOnlyFilteredViewView() 11 | { 12 | this.InitializeComponent(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Collections/ReadOnlySerialViewView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.Windows.Controls; 4 | 5 | public partial class ReadOnlySerialViewView : UserControl 6 | { 7 | public ReadOnlySerialViewView() 8 | { 9 | this.InitializeComponent(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Collections/ReadOnlyThrottledViewView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for ReadOnlyThrottledViewView.xaml. 7 | /// 8 | public partial class ReadOnlyThrottledViewView : UserControl 9 | { 10 | public ReadOnlyThrottledViewView() 11 | { 12 | this.InitializeComponent(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Collections/ReadonlyFilteredDispatchingView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.Windows.Controls; 4 | 5 | public partial class ReadonlyFilteredDispatchingView : UserControl 6 | { 7 | public ReadonlyFilteredDispatchingView() 8 | { 9 | this.InitializeComponent(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Collections/ThrottledViewView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.Windows.Controls; 4 | 5 | /// 6 | /// Interaction logic for ThrottledViewView.xaml. 7 | /// 8 | public partial class ThrottledViewView : UserControl 9 | { 10 | public ThrottledViewView() 11 | { 12 | this.InitializeComponent(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/CommandsView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.Windows.Controls; 4 | 5 | public partial class CommandsView : UserControl 6 | { 7 | public CommandsView() 8 | { 9 | this.InitializeComponent(); 10 | this.DataContext = new CommandsViewModel(); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Conditions/CanStart.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | public class CanStart : AndCondition 4 | { 5 | public CanStart() 6 | #pragma warning disable IDISP004 // Don't ignore created IDisposable. 7 | : base(new IsAnyDoorOpen().Negate(), new HasFuel(), new IsMotorRunning().Negate()) 8 | #pragma warning restore IDISP004 // Don't ignore created IDisposable. 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Conditions/ConditionButtonsView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.Windows.Controls; 4 | 5 | public partial class ConditionButtonsView : UserControl 6 | { 7 | public ConditionButtonsView() 8 | { 9 | this.InitializeComponent(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Conditions/ConditionsView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.Windows.Controls; 4 | 5 | public partial class ConditionsView : UserControl 6 | { 7 | public ConditionsView() 8 | { 9 | this.InitializeComponent(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Conditions/EditConditionStateView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.Windows.Controls; 4 | 5 | public partial class EditConditionStateView : UserControl 6 | { 7 | public EditConditionStateView() 8 | { 9 | this.InitializeComponent(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Conditions/EitherCommandsView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.Windows.Controls; 4 | 5 | public partial class EitherCommandsView : UserControl 6 | { 7 | public EitherCommandsView() 8 | { 9 | this.InitializeComponent(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Conditions/HasFuel.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | public class HasFuel : Condition 4 | { 5 | public HasFuel() 6 | : base( 7 | ConditionState.Instance.ObservePropertyChangedSlim(x => x.FuelLevel), 8 | () => ConditionState.Instance.FuelLevel > 0) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Conditions/IsAnyDoorOpen.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | public class IsAnyDoorOpen : OrCondition 4 | { 5 | public IsAnyDoorOpen() 6 | : base(new IsLeftDoorOpen(), new IsRightDoorOpen(), new IsBackDoorOpen()) 7 | { 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Conditions/IsBackDoorOpen.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | public class IsBackDoorOpen : Condition 4 | { 5 | public IsBackDoorOpen() 6 | : base( 7 | ConditionState.Instance.ObservePropertyChangedSlim(x => x.IsBackDoorOpen), 8 | () => ConditionState.Instance.IsBackDoorOpen) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Conditions/IsLeftDoorOpen.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | public class IsLeftDoorOpen : Condition 4 | { 5 | public IsLeftDoorOpen() 6 | : base( 7 | ConditionState.Instance.ObservePropertyChangedSlim(x => x.IsLeftDoorOpen), 8 | () => ConditionState.Instance.IsLeftDoorOpen) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Conditions/IsMotorRunning.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | public class IsMotorRunning : Condition 4 | { 5 | public IsMotorRunning() 6 | : base( 7 | ConditionState.Instance.ObservePropertyChangedSlim(x => x.IsMotorRunning), 8 | () => ConditionState.Instance.IsMotorRunning) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Conditions/IsRightDoorOpen.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | public class IsRightDoorOpen : Condition 4 | { 5 | public IsRightDoorOpen() 6 | : base( 7 | ConditionState.Instance.ObservePropertyChangedSlim(x => x.IsRightDoorOpen), 8 | () => ConditionState.Instance.IsRightDoorOpen) 9 | { 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Conditions/SyncErrorCondition.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | public class SyncErrorCondition : Condition 4 | { 5 | public SyncErrorCondition() 6 | #pragma warning disable GUREA02 // Observable and criteria must match. 7 | : base( 8 | ConditionState.Instance.ObservePropertyChangedSlim(x => x.IsMotorRunning), 9 | () => ConditionState.Instance.IsRightDoorOpen) // notifying for the wrong property 10 | #pragma warning restore GUREA02 // Observable and criteria must match. 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Conditions/ToolTipsView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.Windows.Controls; 4 | 5 | public partial class ToolTipsView : UserControl 6 | { 7 | public ToolTipsView() 8 | { 9 | this.InitializeComponent(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Converters/BooleanToBrushConverter.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo.Converters 2 | { 3 | using System; 4 | using System.Globalization; 5 | using System.Windows.Data; 6 | using System.Windows.Markup; 7 | using System.Windows.Media; 8 | 9 | [MarkupExtensionReturnType(typeof(BooleanToBrushConverter))] 10 | [ValueConversion(typeof(bool), typeof(Brush))] 11 | public class BooleanToBrushConverter : MarkupExtension, IValueConverter 12 | { 13 | public Brush? WhenTrue { get; set; } 14 | 15 | public Brush? WhenFalse { get; set; } 16 | 17 | public Brush? WhenNull { get; set; } 18 | 19 | public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) 20 | { 21 | return value switch 22 | { 23 | true => this.WhenTrue, 24 | false => this.WhenFalse, 25 | null => this.WhenNull, 26 | _ => throw new ArgumentException("Expected bool?", nameof(value)), 27 | }; 28 | } 29 | 30 | object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 31 | { 32 | throw new NotSupportedException(); 33 | } 34 | 35 | public override object ProvideValue(IServiceProvider serviceProvider) => this; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Converters/BooleanToVisibilityConverter.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo.Converters 2 | { 3 | using System; 4 | using System.Globalization; 5 | using System.Windows; 6 | using System.Windows.Data; 7 | using System.Windows.Markup; 8 | 9 | [MarkupExtensionReturnType(typeof(BooleanToVisibilityConverter))] 10 | [ValueConversion(typeof(bool?), typeof(Visibility))] 11 | public class BooleanToVisibilityConverter : MarkupExtension, IValueConverter 12 | { 13 | public Visibility WhenTrue { get; set; } = Visibility.Visible; 14 | 15 | public Visibility WhenFalse { get; set; } = Visibility.Hidden; 16 | 17 | public Visibility WhenNull { get; set; } = Visibility.Hidden; 18 | 19 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 20 | { 21 | return value switch 22 | { 23 | true => this.WhenTrue, 24 | false => this.WhenTrue, 25 | null => this.WhenNull, 26 | _ => throw new ArgumentException("Expected bool?"), 27 | }; 28 | } 29 | 30 | object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 31 | { 32 | throw new NotSupportedException(); 33 | } 34 | 35 | public override object ProvideValue(IServiceProvider serviceProvider) => this; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/DataGridAndEventsView.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/DummyItem.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.ComponentModel; 4 | using System.Globalization; 5 | using System.Runtime.CompilerServices; 6 | 7 | public class DummyItem : INotifyPropertyChanged 8 | { 9 | private int value; 10 | 11 | public DummyItem() 12 | { 13 | } 14 | 15 | public DummyItem(int value) 16 | { 17 | this.value = value; 18 | } 19 | 20 | public event PropertyChangedEventHandler? PropertyChanged; 21 | 22 | public int Value 23 | { 24 | get => this.value; 25 | 26 | set 27 | { 28 | if (value == this.value) 29 | { 30 | return; 31 | } 32 | 33 | this.value = value; 34 | this.OnPropertyChanged(); 35 | } 36 | } 37 | 38 | public override string ToString() 39 | { 40 | return this.Value.ToString(CultureInfo.InvariantCulture); 41 | } 42 | 43 | protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) => this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/EnumValuesView.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/EnumValuesView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.Windows.Controls; 4 | 5 | public partial class EnumValuesView : UserControl 6 | { 7 | public EnumValuesView() 8 | { 9 | this.InitializeComponent(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Gu.Reactive.Demo.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net6.0-windows 4 | WinExe 5 | true 6 | latest 7 | enable 8 | 9 | 10 | 11 | True 12 | AllEnabledByDefault 13 | latest 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/Gu.Reactive.Demo.csproj.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | True -------------------------------------------------------------------------------- /Gu.Reactive.Demo/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.Windows; 4 | 5 | public partial class MainWindow : Window 6 | { 7 | public MainWindow() 8 | { 9 | this.InitializeComponent(); 10 | this.DataContext = new MainWindowViewModel(); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/MainWindowViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.ComponentModel; 4 | using System.Runtime.CompilerServices; 5 | 6 | public class MainWindowViewModel : INotifyPropertyChanged 7 | { 8 | public event PropertyChangedEventHandler? PropertyChanged; 9 | 10 | protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) 11 | { 12 | this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/NamedFilter.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System; 4 | 5 | public class NamedFilter 6 | { 7 | public NamedFilter(string name, Predicate filter) 8 | { 9 | this.Name = name; 10 | this.Filter = filter; 11 | } 12 | 13 | public string Name { get; } 14 | 15 | public Predicate Filter { get; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/NinjaBindingView.xaml.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.Windows.Controls; 4 | 5 | public partial class NinjaBindingView : UserControl 6 | { 7 | public NinjaBindingView() 8 | { 9 | this.InitializeComponent(); 10 | this.DataContext = new NinjaBindingViewModel(); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/NinjaBindingViewModel.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System.ComponentModel; 4 | using System.Runtime.CompilerServices; 5 | using System.Windows; 6 | 7 | public class NinjaBindingViewModel : INotifyPropertyChanged 8 | { 9 | private bool visible = true; 10 | 11 | private Visibility visibility; 12 | 13 | public event PropertyChangedEventHandler? PropertyChanged; 14 | 15 | public bool Visible 16 | { 17 | get => this.visible; 18 | 19 | set 20 | { 21 | if (value.Equals(this.visible)) 22 | { 23 | return; 24 | } 25 | 26 | this.visible = value; 27 | this.OnPropertyChanged(); 28 | this.Visibility = this.visible ? Visibility.Visible : Visibility.Collapsed; 29 | } 30 | } 31 | 32 | public Visibility Visibility 33 | { 34 | get => this.visibility; 35 | 36 | set 37 | { 38 | if (value == this.visibility) 39 | { 40 | return; 41 | } 42 | 43 | this.visibility = value; 44 | this.OnPropertyChanged(); 45 | } 46 | } 47 | 48 | protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) => this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/TypeNameConverter.cs: -------------------------------------------------------------------------------- 1 | namespace Gu.Reactive.Demo 2 | { 3 | using System; 4 | using System.Globalization; 5 | using System.Windows.Data; 6 | 7 | [ValueConversion(typeof(object), typeof(string))] 8 | public sealed class TypeNameConverter : IValueConverter 9 | { 10 | public static readonly TypeNameConverter Default = new TypeNameConverter(); 11 | 12 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 13 | { 14 | return value?.GetType().Name ?? "null"; 15 | } 16 | 17 | object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 18 | { 19 | throw new NotSupportedException(); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/UiTestWindows/AsyncCommandsWindow.xaml: -------------------------------------------------------------------------------- 1 |  11 | 12 | 13 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/UiTestWindows/CommandsWindow.xaml: -------------------------------------------------------------------------------- 1 |  11 | 12 | 13 | -------------------------------------------------------------------------------- /Gu.Reactive.Demo/UiTestWindows/ConditionControlWindow.xaml: -------------------------------------------------------------------------------- 1 |  12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |