How to combine the dynamic set of Observables into a new Observable?

I have a concept Roomin my program. Each room has a quantity User, and each user has Observableone that indicates what level of silence he wants in the room. When the user selects a new value, I just push it on the Observable, calling OnNextin the internal instance BehaviorSubjectinside the class User.

The main logic of the program is that you need to be able to say "what level of silence" in the room. For example, if at least one user in a room needs silence, then the whole room needs silence.

This is a simplification of my classes:

First, I use an enumeration to represent possible sound levels. Now there are only two values:

enum SoundLevelRequirement
{
    /// <summary>
    ///     Indicates that the user is ok with any sound level in the room.
    /// </summary>
    None,

    /// <summary>
    ///     Indicates that the user needs absolute silence in the room.
    /// </summary>
    Silence
}

Observable, , .

class User
{
    private readonly BehaviorSubject<SoundLevelRequirement> soundLevel;

    public User(string name)
    {
        Name = name;
        soundLevel = new BehaviorSubject<SoundLevelRequirement>(SoundLevelRequirement.None);
    }

    public string Name { get; }

    public IObservable<SoundLevelRequirement> SoundLevelChanged => soundLevel.DistinctUntilChanged();

    public void SetSoundLevel(SoundLevelRequirement level)
    {
        soundLevel.OnNext(level);
    }
}

, :

class Room
{
    private readonly BehaviorSubject<SoundLevelRequirement> soundLevel;
    private readonly ObservableCollection<User> users;

    public Room(string name)
    {
        Name = name;
        Users = new ObservableCollection<User>();

        // THIS IS WHERE I NEED TO COMBINE ALL CHILD OBSERVABLES INSTEAD 
        // OF USING ANOTHER Subject
        soundLevel = new BehaviorSubject<SoundLevelRequirement>(SoundLevelRequirement.None);
    }

    public ObservableCollection<User> Users { get; set; }

    public string Name { get; }

    public IObservable<SoundLevelRequirement> SoundLevel => soundLevel.DistinctUntilChanged();
}

Observable Rx Observable - . , ( User ), . , , CombineLatest, , :

Users.Select(u => u.SoundLevelChanged).CombineLatest().Select(latest => latest.Max());

, , - , , " ", . , , .

, . , 5 "" - , Silence, reset , , None.

, ObservableCollection , -, , , , , , .

+4
1

, . User.

:

public SoundLevelRequirement SoundLevel => soundLevel.Value;

Room :

class Room
{
    private readonly IObservable<SoundLevelRequirement> soundLevel;

    public Room(string name)
    {
        this.Name = name;
        this.Users = new ObservableCollection<User>();

        soundLevel =
            Observable
                .Create<SoundLevelRequirement>(o =>
                    Observable
                        .FromEventPattern<
                            NotifyCollectionChangedEventHandler,
                            NotifyCollectionChangedEventArgs>(
                            h => this.Users.CollectionChanged += h,
                            h => this.Users.CollectionChanged -= h)
                        .SelectMany(x => this.Users
                            .Select(u => u.SoundLevelChanged
                                .StartWith(u.SoundLevel))
                                .Merge())
                        .Select(ep =>
                            this.Users.Any(u =>
                                u.SoundLevel == SoundLevelRequirement.Silence)
                                    ? SoundLevelRequirement.Silence
                                    : SoundLevelRequirement.None)
                        .DistinctUntilChanged()
                        .Subscribe(o));
    }

    public ObservableCollection<User> Users { get; set; }

    public string Name { get; }

    public IObservable<SoundLevelRequirement> SoundLevel => soundLevel.AsObservable();
}

, Room.SoundLevel 1, .Replay(1) soundLevel, IConnectableObservable<SoundLevelRequirement>. IDisposable Room, . - , . .

+2

All Articles