{"id":21129477,"url":"https://github.com/guorg/gu.reactive","last_synced_at":"2025-12-16T23:56:16.190Z","repository":{"id":21418170,"uuid":"24736246","full_name":"GuOrg/Gu.Reactive","owner":"GuOrg","description":"Helpers for using System.Reactive with INotifyPropertyChanged and INotifyCollectionChanged","archived":false,"fork":false,"pushed_at":"2024-03-04T16:49:15.000Z","size":5395,"stargazers_count":22,"open_issues_count":15,"forks_count":6,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-11-19T05:05:03.143Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GuOrg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-10-02T20:54:41.000Z","updated_at":"2023-03-04T07:14:53.000Z","dependencies_parsed_at":"2023-02-10T16:45:38.584Z","dependency_job_id":"bb9048c2-80cc-4504-8c9f-4f8261f86ee5","html_url":"https://github.com/GuOrg/Gu.Reactive","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GuOrg%2FGu.Reactive","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GuOrg%2FGu.Reactive/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GuOrg%2FGu.Reactive/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GuOrg%2FGu.Reactive/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GuOrg","download_url":"https://codeload.github.com/GuOrg/Gu.Reactive/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225473050,"owners_count":17479721,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-20T05:23:04.794Z","updated_at":"2025-12-16T23:56:16.146Z","avatar_url":"https://github.com/GuOrg.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"Gu.Reactive\n===========\n\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.md)\n[![Nuget](https://img.shields.io/nuget/v/Gu.Reactive.svg?label=Gu.Reactive)](https://www.nuget.org/packages/Gu.Reactive/)\n[![Nuget](https://img.shields.io/nuget/v/Gu.Wpf.Reactive.svg?label=Gu.Wpf.Reactive)](https://www.nuget.org/packages/Gu.Wpf.Reactive/)\n[![Build status](https://ci.appveyor.com/api/projects/status/klrt8kctqbvt2j95/branch/master?svg=true)](https://ci.appveyor.com/project/JohanLarsson/gu-reactive/branch/master)\n[![Build Status](https://dev.azure.com/guorg/Gu.Reactive/_apis/build/status/GuOrg.Gu.Reactive?branchName=master)](https://dev.azure.com/guorg/Gu.Reactive/_build/latest?definitionId=14\u0026branchName=master)\n[![Gitter](https://badges.gitter.im/JoinChat.svg)](https://gitter.im/JohanLarsson/Gu.Reactive?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n\nHelpers for using System.Reactive with `INotifyPropertyChanged`.\n\n# Table of contents\n\n- [Factory methods for creating observables.](#factory-methods-for-creating-observables)\n  - [ObservePropertyChangedSlim:](#observepropertychangedslim)\n    - [SignalInitial](#signalinitial)\n  - [ObserveValue](#observevalue)\n  - [ObservePropertyChangedWithValue](#observepropertychangedwithvalue)\n  - [ObservePropertyChanged:](#observepropertychanged)\n    - [SignalInitial](#signalinitial)\n  - [ObserveCollectionChanged:](#observecollectionchanged)\n    - [SignalInitial](#signalinitial)\n  - [ObservePropertyChangedSlim:](#observepropertychangedslim)\n    - [SignalInitial](#signalinitial)\n  - [ObserveItemPropertyChanged](#observeitempropertychanged)\n  - [ObserveItemPropertyChangedSlim](#observeitempropertychanged)\n- [Conditions:](#conditions)\n  - [Condition](#condition)\n    - [IsSatisfied](#issatisfied)\n    - [Name](#name)\n    - [History](#history)\n    - [Negate()](#negate)\n  - [OrCondition](#orcondition)\n    - [IsSatisfied](#issatisfied)\n  - [AndCondition](#andcondition)\n    - [IsSatisfied](#issatisfied)\n- [Collections](#collections)\n  - [ReadOnlyFilteredView](#readonlyfilteredview)\n  - [MappingView](#mappingviewtsource-tresult)\n  - [ReadOnlyThrottledView](#readonlythrottledview)\n  - [ReadOnlyDispatchingView](#readonlydispatchingview)\n  - [ReadOnlySerialView](#readonlyserialview)\n  - [Commands](#commands)\n    - [AsyncCommand](#asynccommand)\n    - [ConditionRelayCommand](#conditionrelaycommand)\n    - [ManualRelayCommand](#manualrelaycommand)\n    - [ObservingRelayCommand](#observingrelaycommand)\n    - [RelayCommand](#relaycommand)\n  - [MarkupExtensions](#markupextensions)\n    - [EnumValuesForExtension](#enumvaluesforextension)\n    - [NinjaBinding](#ninjabinding)\n\n# Assembly redirects.\nWhen used from .Net 4.6 assembly redirects are needed.\nhttps://github.com/Reactive-Extensions/Rx.NET/issues/299\n\n```xml\n\u003cdependentAssembly\u003e\n  \u003cassemblyIdentity name=\"System.Reactive.Core\" publicKeyToken=\"94bc3704cddfc263\" culture=\"neutral\" /\u003e\n  \u003cbindingRedirect oldVersion=\"0.0.0.0-3.0.3000.0\" newVersion=\"3.0.3000.0\" /\u003e\n\u003c/dependentAssembly\u003e\n\u003cdependentAssembly\u003e\n  \u003cassemblyIdentity name=\"System.Reactive.PlatformServices\" publicKeyToken=\"94bc3704cddfc263\" culture=\"neutral\" /\u003e\n  \u003cbindingRedirect oldVersion=\"0.0.0.0-3.0.3000.0\" newVersion=\"3.0.3000.0\" /\u003e\n\u003c/dependentAssembly\u003e\n\u003cdependentAssembly\u003e\n  \u003cassemblyIdentity name=\"System.Reactive.Linq\" publicKeyToken=\"94bc3704cddfc263\" culture=\"neutral\" /\u003e\n  \u003cbindingRedirect oldVersion=\"0.0.0.0-3.0.3000.0\" newVersion=\"3.0.3000.0\" /\u003e\n\u003c/dependentAssembly\u003e\n```\nNuget can generate redirects using PM\u003e `Get-Project –All | Add-BindingRedirect`\n\n# Factory methods for creating observables.\n\n## ObservePropertyChangedSlim:\n\n```c#\nvar subscription = foo.ObservePropertyChangedSlim(x =\u003e x.Bar.Baz)\n                       .Subscribe(...);\n```\n\n1) Return an `IObservable\u003cPropertyChangedEventArgs\u003e` so more lightweight than `ObservePropertyChanged`\n2) Filters change args mathing property name or `string.IsNullOrEmpty`\n\n### SignalInitial\nDefault true meaning that the observable will call OnNext on Subscribe\n\n## ObserveValue\nObserve the value of a property, calls on next when the value changes. \nReturns an `Observable\u003cMaybe\u003cT\u003e\u003e`, this is due to if you observe `foo.ObserveValue(x =\u003e x.Bar.Baz)` and Bar is null.\nIf so it return `Maybe.None`\n\n```c#\nvar ints = new List\u003cint\u003e();\nfoo.ObserveValue(x =\u003e x.Bar.Baz)\n    .Subscribe(ints.Add);\n```\n\n## ObservePropertyChanged:\n\n```c#\nvar subscription = fake.ObservePropertyChanged(x =\u003e x.Level1.Level2.Value)\n                       .Subscribe(...);\n```\n\n1) Create an observable from the `PropertytChangedEvent` for fake.\n2) Listens to nested changes. All steps in the property path must be INotifyPropertyChanged. Throws if not.\n3) When PropertyChanged is raised with string.Empty or null the observable notifies.\n4) Updates subscriptions for items in path and uses weak events.\n\n### SignalInitial\nDefault true meaning that the observable will call OnNext on Subscribe.\nThe sender will be tha last node in the path that has a value, in the example above it would be the value of the property `Level2` if it is not null, then `Level1` if not null if the entire path is null the root item `fake` is used as sender for the first notifixcation.\nThe eventags for the signal initial event is `string.Empty`\n\n## ObservePropertyChangedWithValue\n```c#\nfake.ObservePropertyChangedWithValue(x =\u003e x.Collection)\n    .ItemPropertyChanged(x =\u003e x.Name)\n    .Subscribe(_changes.Add);\n```\n\n\n## ObserveCollectionChanged:\n\n```c#\nvar subscription = collection.ObserveCollectionChanged()\n                       .Subscribe(...);\n```\n\n1) Create an observable from the `CollectionChangedEvent` for collection.\n\n### SignalInitial\nDefault true meaning that the observable will call OnNext on Subscribe\n\n## ObservePropertyChangedSlim:\n\n```c#\nvar subscription = collection.ObserveCollectionChangedSlim()\n                       .Subscribe(...);\n```\n\n1) Return an `IObservable\u003cNotifyCollectionChangedEventArgs\u003e` so more lightweight than `ObserveCollectionChanged`\n\n### SignalInitial\nDefault true meaning that the observable will call OnNExt on Subscribe\n\n## ObserveItemPropertyChanged\n```c#\nvar subscription = collection.ObserveItemPropertyChanged(x =\u003e x.Name)\n                             .Subscribe(...);\n```\nAn observable that signals when the collection is modified or the property that the lambda points to signals for any item in the collection.\nIf the collection changes the collection is sender.\nWhen an element is removed null is passed as item.\nWhen an element is replaced the observable notifies twice, once for the remove of the old element and once for the add of the new element.\n\n### SignalInitial\nDefault true meaning that the observable will call OnNExt on Subscribe\n\n## ObserveItemPropertyChanged\n```c#\nvar subscription = collection.ObserveItemPropertyChangedSlim(x =\u003e x.Name)\n                             .Subscribe(...);\n```\nAn observable that signals when the collection is modified or the property that the lambda points to signals for any item in the collection.\n### SignalInitial\nDefault true meaning that the observable will call OnNExt on Subscribe\n\n# Conditions:\n## Condition\n\nA type that calculates `IsSatisfied` when any of the `IObservable\u003cobject\u003e` triggers signals.\nCreate it in code like this:\n\n```c#\nthis.isTrueCondition = new Condition(\n    this.ObservePropertyChanged(x =\u003e x.IsTrue),\n    () =\u003e this.IsTrue);\n```\n\nThe conditions work really well when used with an IoC.\nThen subclasses are created and the IoC is used to build trees of nested conditions.\n\n```c#\npublic class HasFuel : Condition\n{\n    public HasFuel(Car car)\n        : base(\n            car.ObservePropertyChanged(x =\u003e x.FuelLevel),\n            () =\u003e car.FuelLevel \u003e 0)\n    {\n    }\n}\n```\n\n### IsSatisfied\n\nEvaluates the criteria passed to the ctor. Recalculates when any of the observables signals and the value changes.\n\n### Name\n\nDefault is `GetType.Name` but the property is mutable so other names can be specified.\n\n### History\n\nThe last 100 times of change and values for `IsSatisfied`\n\n### Negate()\n\nReturns a condition wrapping the instance and negating the value of `IsSatisfied`.\nNegating a negated condition returns the original condition.\n\n## OrCondition\n\nCalculates `IsSatisfied` based on if any of the prerequisites are true. Listens to changes in `IsSatisfied` for prerequisites and notifies when value changes.\n\n```c#\npublic class IsAnyDoorOpen : OrCondition\n{\n    public IsAnyDoorOpen(\n        IsLeftDoorOpen isLeftDoorOpen,\n        IsRightDoorOpen isRightDoorOpen)\n        : base(isLeftDoorOpen, isRightDoorOpen)\n    {\n    }\n}\n```\n### IsSatisfied\n\nTrue if `IsSatisfied` for any prerequisites is true.\nFalse if `IsSatisfied` for all prerequisites are false.\nNull if `IsSatisfied` for no prerequisite is true and any prerequisite is null.\n\n## AndCondition\n\nCalculates `IsSatisfied` based on if all of the prerequisites have IsSatisfied == true. Listens to changes in `IsSatisfied` for prerequisites and notifies when value changes.\n\n```c#\npublic class IsAnyDoorOpen : AndCondition\n{\n    public IsAnyDoorOpen(\n        IsLeftDoorOpen isLeftDoorOpen,\n        IsRightDoorOpen isRightDoorOpen)\n        : base(isLeftDoorOpen.Negate(), isRightDoorOpen.Negate())\n    {\n    }\n}\n```\n### IsSatisfied\n\nTrue if `IsSatisfied` for all prerequisites are true.\nFalse if `IsSatisfied` for any prerequisite is false.\nNull if `IsSatisfied` for no prerequisite is false and any prerequisite is null.\n\nSe demo for more code samples.\n\n# Collections\n\n## ReadOnlyFilteredView\u003cT\u003e\n\nA typed filtered view of a collection. Sample usage:\n\n```c#\npublic sealed class ViewModel : INotifyPropertyChanged, IDisposable\n{\n    private string filterText;\n    private bool disposed;\n\n    public ViewModel(ObservableCollection\u003cPerson\u003e people, IWpfSchedulers schedulers)\n    {\n        this.FilteredPeople = people.AsReadOnlyFilteredView(\n            this.IsMatch,\n            TimeSpan.FromMilliseconds(10),\n            schedulers.Dispatcher,\n            this.ObservePropertyChangedSlim(nameof(this.FilterText)));\n    }\n\n    public event PropertyChangedEventHandler PropertyChanged;\n\n    public IReadOnlyObservableCollection\u003cPerson\u003e FilteredPeople { get; }\n\n    public string FilterText\n    {\n        get\n        {\n            return this.filterText;\n        }\n\n        set\n        {\n            if (value == this.filterText)\n            {\n                return;\n            }\n\n            this.filterText = value;\n            this.OnPropertyChanged();\n        }\n    }\n\n    public void Dispose()\n    {\n        if (this.disposed)\n        {\n            return;\n        }\n\n        this.disposed = true;\n        this.FilteredPeople.Dispose();\n    }\n\n    private void OnPropertyChanged([CallerMemberName] string propertyName = null)\n    {\n        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));\n    }\n\n    private bool IsMatch(Person person)\n    {\n        if (string.IsNullOrEmpty(this.filterText))\n        {\n            return true;\n        }\n\n        var indexOf = CultureInfo.InvariantCulture.CompareInfo.IndexOf(person.FirstName, this.filterText, CompareOptions.OrdinalIgnoreCase);\n        if (this.filterText.Length == 1)\n        {\n            return indexOf == 0;\n        }\n\n        return indexOf \u003e= 0;\n    }\n}\n```\n\n## MappingView\u003cTSource, TResult\u003e\n\nA view that maps from one type to another. If the source type is a reference type the same instance produces the same mapped instance if the item appears more than once in the collection.\n\n### Simple\n\n```c#\npublic sealed class ViewModel : IDisposable\n{\n    private bool disposed;\n\n    public ViewModel(ObservableCollection\u003cPerson\u003e people)\n    {\n        this.PersonViewModels = people.AsMappingView(x =\u003e new PersonViewModel(x));\n    }\n\n    public MappingView\u003cPerson, PersonViewModel\u003e PersonViewModels { get; }\n\n    public void Dispose()\n    {\n        if (this.disposed)\n        {\n            return;\n        }\n\n        this.disposed = true;\n        this.PersonViewModels.Dispose();\n    }\n}\n```\n\n### When creating `IDisposable`\n\nPass in an action that is invoked when the last instance is removed from the mapped collection.\n\n```c#\npublic sealed class ViewModel : IDisposable\n{\n    private bool disposed;\n\n    public ViewModel(ObservableCollection\u003cPerson\u003e people)\n    {\n        this.PersonViewModels = people.AsMappingView(\n            x =\u003e new PersonViewModel(x),\n            x =\u003e x.Dispose());\n    }\n\n    public IReadOnlyObservableCollection\u003cPersonViewModel\u003e PersonViewModels { get; }\n\n    public void Dispose()\n    {\n        if (this.disposed)\n        {\n            return;\n        }\n\n        this.disposed = true;\n        (this.PersonViewModels as IDisposable)?.Dispose();\n    }\n}\n```\n\n## ReadOnlyThrottledView\u003cT\u003e\n\nA view that buffers changes. If there are many changes within the buffer time one reset event is raised instead of on event per change.\n\n```c#\npublic sealed class ViewModel : IDisposable\n{\n    private bool disposed;\n\n    public ViewModel(ObservableCollection\u003cPerson\u003e people)\n    {\n        this.PersonViewModels = people.AsReadOnlyThrottledView(TimeSpan.FromMilliseconds(100));\n    }\n\n    public IReadOnlyObservableCollection\u003cPerson\u003e PersonViewModels { get; }\n\n    public void Dispose()\n    {\n        if (this.disposed)\n        {\n            return;\n        }\n\n        this.disposed = true;\n        this.PersonViewModels.Dispose();\n    }\n}\n```\n\n## ReadOnlyDispatchingView\u003cT\u003e\n\nA view that notifies on the dispatcher. Useful if the collection is updated on another thread.\n\n```c#\npublic sealed class ViewModel : IDisposable\n{\n    private bool disposed;\n\n    public ViewModel(ObservableCollection\u003cPerson\u003e people)\n    {\n        this.PersonViewModels = people.AsReadOnlyDispatchingView();\n    }\n\n    public IReadOnlyObservableCollection\u003cPerson\u003e PersonViewModels { get; }\n\n    public void Dispose()\n    {\n        if (this.disposed)\n        {\n            return;\n        }\n\n        this.disposed = true;\n        this.PersonViewModels.Dispose();\n    }\n}\n```\n\n## ReadOnlySerialView\u003cT\u003e\n\nA view that can have source set to different collections. \nUseful when composing with for example MappedView\n\n```c#\npublic sealed class ViewModel : IDisposable\n{\n    private bool disposed;\n\n    public ViewModel(ObservableCollection\u003cPerson\u003e people)\n    {\n        this.Update(people);\n    }\n\n    public ReadOnlySerialView\u003cPerson\u003e People { get; } = new ReadOnlySerialView\u003cPerson\u003e();\n\n    public void Update(ObservableCollection\u003cPerson\u003e people)\n    {\n        this.People.SetSource(people);\n    }\n\n    public void Dispose()\n    {\n        if (this.disposed)\n        {\n            return;\n        }\n\n        this.disposed = true;\n        this.People.Dispose();\n    }\n}\n```\n\n## Sample\n\nThe following sample filters a list and then maps it to another type. This happens on the task pool.\nThen changhes are notified to the view on the dispatcher.\n\n```c#\npublic sealed class ViewModel : INotifyPropertyChanged, IDisposable\n{\n    private string filterText;\n    private bool disposed;\n\n    public ViewModel(ObservableCollection\u003cPerson\u003e people, IWpfSchedulers schedulers)\n    {\n        this.FilteredPeople = people.AsReadOnlyFilteredView(\n                                        this.IsMatch,\n                                        TimeSpan.FromMilliseconds(10),\n                                        schedulers.TaskPool,\n                                        this.ObservePropertyChangedSlim(nameof(this.FilterText)))\n                                    .AsMappingView(\n                                        x =\u003e new PersonViewModel(x),\n                                        x =\u003e x.Dispose())\n                                    .AsReadOnlyDispatchingView();\n    }\n\n    public event PropertyChangedEventHandler PropertyChanged;\n\n    public IReadOnlyObservableCollection\u003cPersonViewModel\u003e FilteredPeople { get; }\n\n    public string FilterText\n    {\n        get\n        {\n            return this.filterText;\n        }\n\n        set\n        {\n            if (value == this.filterText)\n            {\n                return;\n            }\n\n            this.filterText = value;\n            this.OnPropertyChanged();\n        }\n    }\n\n    public void Dispose()\n    {\n        if (this.disposed)\n        {\n            return;\n        }\n\n        this.disposed = true;\n        (this.FilteredPeople as IDisposable)?.Dispose();\n    }\n\n    private void OnPropertyChanged([CallerMemberName] string propertyName = null)\n    {\n        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));\n    }\n\n    private bool IsMatch(Person person)\n    {\n        if (string.IsNullOrEmpty(this.filterText))\n        {\n            return true;\n        }\n\n        var indexOf = CultureInfo.InvariantCulture.CompareInfo.IndexOf(person.FirstName, this.filterText, CompareOptions.OrdinalIgnoreCase);\n        if (this.filterText.Length == 1)\n        {\n            return indexOf == 0;\n        }\n\n        return indexOf \u003e= 0;\n    }\n}\n```\nGu.Wpf.Reactive\n===========\n\nHelpers for using System.Reactive with `INotifyPropertyChanged` in  WPF applications.\n\n## Commands\nA set of relay commands. The generic versions take a command parameter of the generic type.\nThe non-generic version does not use the command parameter.\n\n### AsyncCommand\nFor executing tasks. If the overload that takes a `CancellationToken` is used the `CancelCommand` cancels the execution.\nBy default the command is disabled while running.\nIf no condition is passed in IsEnabled is true when not running.\n\n```C#\npublic ViewModel()\n{\n    var canExecute = new Condition(\n        this.ObservePropertyChanged(x =\u003e x.CanExecute), \n        () =\u003e this.CanExecute);\n\n    this.SimpleTaskCommand = new AsyncCommand(this.SimpleTask, canExecute);\n    this.CancelableTaskCommand = new AsyncCommand(this.CancelableTask, canExecute);\n    this.ParameterTaskCommand = new AsyncCommand\u003cstring\u003e(this.ParameterTask, canExecute);\n    this.CancelableParameterTaskCommand = new AsyncCommand\u003cstring\u003e(this.CancelableParameterTask, canExecute);\n}\n\npublic AsyncCommand SimpleTaskCommand { get; }\n\npublic AsyncCommand CancelableTaskCommand { get; }\n\npublic AsyncCommand ParameterTaskCommand { get; }\n\npublic AsyncCommand CancelableParameterTaskCommand { get; }\n\nprivate async Task SimpleTask()\n{\n    await Task.Delay(500).ConfigureAwait(false);\n}\n\nprivate async Task CancelableTask(CancellationToken token)\n{\n    this.Count = 0;\n    for (int i = 0; i \u003c 5; i++)\n    {\n        token.ThrowIfCancellationRequested();\n        this.Count++;\n        await Task.Delay(this.Delay, token).ConfigureAwait(false);\n    }\n}\n\nprivate Task ParameterTask(string arg)\n{\n    return this.SimpleTask();\n}\n\nprivate Task CancelableParameterTask(string arg, CancellationToken token)\n{\n    return this.CancelableTask(token);\n}\n```\n\n### ConditionRelayCommand\n\nA relay command where `CanExecute` is controlled by a `ICondition`\n\n```C#\npublic ViewModel()\n{\n    var canExecute = new Condition(\n        this.ObservePropertyChanged(x =\u003e x.CanExecute), \n        () =\u003e this.CanExecute);\n\n    this.ConditionRelayCommand = new ConditionRelayCommand(() =\u003e ..., canExecute);\n    this.ConditionRelayCommandWithParameter = new ConditionRelayCommand\u003cstring\u003e(parameter =\u003e ..., canExecute);\n}\n\npublic ConditionRelayCommand ConditionRelayCommand { get; }\n\npublic ConditionRelayCommand ConditionRelayCommandWithParameter { get; }\n```\n\n### ManualRelayCommand\n\nA command where you need to manually call `RaiseCanExecuteChanged`.\n\n```C#\npublic ViewModel()\n{\n    this.ManualRelayCommand = new ManualRelayCommand(() =\u003e ..., () =\u003e this.CanExecute);\n    this.ManualRelayCommandWithParameter = new ManualRelayCommand\u003cstring\u003e(parameter =\u003e ..., () =\u003e this.CanExecute);\n}\n\npublic ManualRelayCommand ManualRelayCommand { get; }\n\npublic ManualRelayCommand ManualRelayCommandWithParameter { get; }\n```\n\n### ObservingRelayCommand\n\nA command where an observable is passed in for raising `CanExecuteChanged`.\n\n```C#\npublic ViewModel()\n{\n    var onCanExecute = this.ObservePropertyChanged(x =\u003e x.CanExecute)\n    this.ObservingRelayCommand = new ObservingRelayCommand(() =\u003e ..., onCanExecute, () =\u003e this.CanExecute);\n    this.ObservingRelayCommandWithParameter = new ObservingRelayCommand\u003cstring\u003e(parameter =\u003e ..., onCanExecute, () =\u003e this.CanExecute);\n}\n\npublic ObservingRelayCommand ObservingRelayCommand { get; }\n\npublic ObservingRelayCommand ObservingRelayCommandWithParameter { get; }\n```\n\n\n### RelayCommand\n\nA command that uses the `CommandManager.RequerySuggested` event.\nIt exposes a RaiseCanExecuteChanged method for forcing notification.\n\n```C#\npublic ViewModel()\n{\n    this.RelayCommand = new RelayCommand(() =\u003e ..., () =\u003e this.CanExecute);\n    this.RelayCommandWithParameter = new RelayCommand\u003cstring\u003e(parameter =\u003e ..., () =\u003e this.CanExecute);\n}\n\npublic RelayCommand ManualRelayCommand { get; }\n\npublic RelayCommand ManualRelayCommandWithParameter { get; }\n```\n\n## MarkupExtensions\n\n### EnumValuesForExtension\n\nMarkupextension for getting enum values for a type.\n\nSample code:\n\n```xaml\nxmlns:reactive=\"http://Gu.com/Reactive\"\n...\n\u003cComboBox ItemsSource=\"{reactive:EnumValuesFor {x:Type Visibility}}\" /\u003e\n```\n\n### NinjaBinding\n\nMarkupextension for binding when not in the visual tree.\n\nSample code:\n\n```xaml\nxmlns:reactive=\"http://Gu.com/Reactive\"\n...\n\u003cCheckBox x:Name=\"CheckBox\" IsChecked=\"{Binding Visible}\" /\u003e\n...\n\u003cDataGrid AutoGenerateColumns=\"False\"\u003e\n    \u003cDataGrid.Columns\u003e\n        \u003c!--Here the viewmodel has a Visibility property--\u003e\n        \u003cDataGridTextColumn Header=\"Binding\" \n                            Visibility=\"{reactive:NinjaBinding {Binding Visibility}}\" /\u003e\n\n        \u003cDataGridTextColumn Header=\"ElementName\" \n                            Visibility=\"{reactive:NinjaBinding Binding={Binding IsChecked, \n                                                                                ElementName=CheckBox, \n                                                                                Converter={StaticResource BooleanToVisibilityConverter}}}\" /\u003e\n    \u003c/DataGrid.Columns\u003e\n\u003c/DataGrid\u003e\n```\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguorg%2Fgu.reactive","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fguorg%2Fgu.reactive","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fguorg%2Fgu.reactive/lists"}