Having two properties, one of type public IObservable<bool> IsEnabled { get; set; }
and the second public bool IsActive { get;set; }
and I want to combine the two properties in one using System.Reactive
like that public bool IsActiveAndEnabled {get;set;}
public class BindableProperty<T>
{
T Value { get; }
}
public class Manager
{
public IObservable<bool> IsEnabled { get; set; }
public BindableProperty<bool> IsActiveAndEnabled { get; set; }
private bool isActive;
public bool IsActive
{
get { return isActive; }
set
{
isActive = value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged(() => IsActive);
}
}
private void OnPropertyChanged(Func<bool> property)
{
throw new NotImplementedException();
}
public Manager()
{
IsEnabled
.And(/* accept only observable, but I want to join with IsActive*/)
.Then((isEnabled,isActive) => IsActiveAndEnabled = isEnabled && isActive);
}
}
The code you've posted is not a good example of how use the Reactive-programming paradigm.
ObservableCollection
to the .NET Framework ages ago, but their (mis)use of the term "Observable" in the context of ObservableCollection
is completely unrelated to the meaning of Observable
in Reactive programming.When doing Reactive programming, an Observable is a source (or emitter) of a stream of data objects (note that a stream can be empty (never emitting anything) or only ever emit a single object before it closes itself, or emits thousands of objects every second).
IObservable
is better thought of as an "IEnumerable<T>
-that-pushes" (compared to the normal IEnumerable<T>
which has "pull" semantics).I strongly recommend following a guide or tutorial on the concepts of Reactive programming before continuing further. Most of the guides and tutorials cover RxJS (Reactive Extensions for JavaScript, populised after Angular decided to use Observable<Response>
instead of Promise<Response>
for their built-in HTTP client librar. While many of the guides cover RxJS they are fully applicable to Reactive Programming for other platforms, such as .NET (while IObservable<T>
is part of the .NET Framework, you will need the separate Reactive Extensions library to do reactive programming properly and without reinventing the wheel).
Important note: Reactive Extensions, RxJS and Reactive programming have absolutely nothing to do with "React"/"ReactJS" and the React-pattern (there is a tangental relation, but they are completely separate things).
Resources:
As for your case, this is my recommendation:
class Manager
must be mutable:public IObservable<bool> IsEnabled { get; set; }
class ManagerState
.class Manager : IObservable<ManagerState>
class Manager
changes, fire-off a new ManagerState
(populated with a snapshot copy of Manager
) to the subscribers.class Manager
can be made immutable:public IObservable<bool> IsEnabled { get; set; }
ManagerSource
which implements IObservable<Manager>
Manager
is updated somehow, fire-off a new Manager
object (populated with a snapshot copy of Manager
) to the subscribers.class Manager
is mutable):class Manager : IObservable<ManagerState>
{
private Boolean isEnabled; // backing field
public Boolean IsEnabled
{
get { return this.isEnabled; }
set
{
this.isEnabled = value;
this.NotifySubscribers();
}
}
private Boolean isActive; // backing field
public Boolean IsActive
{
get { return this.isActive; }
set
{
this.isActive = value;
this.NotifySubscribers();
}
}
#region Observers (Subscribers) handling:
private readonly ConcurrentBag<IObserver<ManagerState>> subscribers = new ConcurrentBag<IObserver<ManagerState>>();
private void NotifySubscribers()
{
ManagerState snapshot = new ManagerState(
this.IsEnabled,
this.IsActive,
// etc
);
foreach( IObserver<ManagerState> observer in this.subscribers )
{
observer.OnNext( snapshot );
}
}
#endregion
}
// Represents a snapshot of the state of a `Manager`
class ManagerState
{
public ManagerState( Boolean isEnabled, Boolean isActive )
{
this.IsEnabled = isEnabled;
this.IsActive = isActive;
}
public Boolean IsEnabled { get; }
public Boolean IsActive { get; }
// any other members, etc
}
Note that this can be combined with support for INotifyPropertyChanged
like so (though I think this is a bad idea because supporting multiple ways to accomplish the same thing will end-up confusing your users/consumers/coworkers) - kinda like how System.Net.Sockets.Socket
has Accept
, AcceptAsync
, BeginAccept
/EndAccept
because it supports synchronous, and the APM and EAP asynchronous paradigms (but not TPL for some reason).
class Manager : IObservable<ManagerState>, INotifyPropertyChanged
{
private Boolean isEnabled; // backing field
public Boolean IsEnabled
{
get { return this.isEnabled; }
set
{
this.isEnabled = value;
this.OnPropertyChanged( nameof(this.IsEnabled) );
}
}
private Boolean isActive; // backing field
public Boolean IsActive
{
get { return this.isActive; }
set
{
this.isActive = value;
this.OnPropertyChanged( nameof(this.IsActive) );
}
}
#region INotifyPropetyChanged and Observers (Subscribers) handling:
private readonly ConcurrentBag<IObserver<ManagerState>> subscribers = new ConcurrentBag<IObserver<ManagerState>>();
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged( String name )
{
// First, notify users of INotifyPropetyChanged:
this.PropertyChanged?.Invoke( this, new PropertyChangedEventArgs( name ) );
// Then notify users of IObservable:
ManagerState snapshot = new ManagerState(
this.IsEnabled,
this.IsActive,
// etc
);
foreach( IObserver<ManagerState> observer in this.subscribers )
{
observer.OnNext( snapshot );
}
}
#endregion
}