<NME> Collections.md
<BEF> # Collections

ReactiveProperty provides some collection classes.

- ReactiveCollection&lt;T&gt;
- ReadOnlyReactiveCollection&lt;T&gt;
- IFilteredReadOnlyObservableCollection&lt;T&gt;

## ReactiveCollection

`ReactiveCollection` inherits `ObservableCollection`.
This class is created from `IObservable`.
It adds an item when a value is provided from the source `IObservable`.
`ReactiveCollection` executes this process using `IScheduler`. The default `IScheduler` dispatches to the UI thread.

```csharp
public class ViewModel
{
    public ReactiveCollection<DateTime> Records { get; }

    public ReactiveCommand StartRecordCommand { get; }

    public ViewModel()
    {
        StartRecordCommand = new ReactiveCommand();
        // Create a ReactiveCollection instance from IObservable
        Records = StartRecordCommand
            .ToUnit()
            .Take(1)
            .Concat(Observable.Defer(() => Observable.Interval(TimeSpan.FromSeconds(1)).ToUnit()))
            .Select(_ => DateTime.Now)
            .ToReactiveCollection();
    }
}
```

> `ToUnit` extension method is defined in the Reactive.Bindings.Extensions namespace.
> This extension method is same as `.Select(_ => Unide.Default)`.

Example of UWP platform.

MainPage.xaml.cs
```csharp
public sealed partial class MainPage : Page
{
    public ViewModel ViewModel { get; } = new ViewModel();
    public MainPage()
    {
        this.InitializeComponent();
    }
}
```

MainPage.xaml
```xml
<Page x:Class="App1.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:App1"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal">
            <Button Content="Start"
                    Command="{x:Bind ViewModel.StartRecordCommand}"
                    Margin="5" />
        </StackPanel>
        <ListView ItemsSource="{x:Bind ViewModel.Records}"
                  Grid.Row="1" />
    </Grid>
</Page>
```

![Basic usage](./images/collections-reactivecollection-basic-usage.gif)

## Collection operations

`ReactiveCollection` class has `XxxxOnScheduler` methods. For example, `AddOnScheduler`, `RemoveOnScheduler`, `ClearOnScheduler`, `GetOnScheduler`, etc...
Those methods run on the `IScheduler` and can be called from outside of the UI thread.

```csharp
public class ViewModel
{
    public ReactiveCollection<DateTime> Records { get; }

    public ReactiveCommand StartRecordCommand { get; }

    public ReactiveCommand ClearCommand { get; }

    public ViewModel()
    {
        StartRecordCommand = new ReactiveCommand();
        // Create a ReactiveCollection instance from IObservable
        Records = StartRecordCommand
            .ToUnit()
            .Take(1)
            .Concat(Observable.Defer(() => Observable.Interval(TimeSpan.FromSeconds(1)).ToUnit()))
            .Select(_ => DateTime.Now)
            .ToReactiveCollection();

        ClearCommand = new ReactiveCommand();
        ClearCommand.ObserveOn(TaskPoolScheduler.Default) // run on the another thread
            .Subscribe(_ => Records.ClearOnScheduler());
    }
}
```

```xml
<Page x:Class="App1.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:App1"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal">
            <Button Content="Start"
                    Command="{x:Bind ViewModel.StartRecordCommand}"
                    Margin="5" />
            <Button Content="Clear"
                    Command="{x:Bind ViewModel.ClearCommand}"
                    Margin="5" />
        </StackPanel>
        <ListView ItemsSource="{x:Bind ViewModel.Records}"
                  Grid.Row="1" />
    </Grid>
</Page>
```

![Collection operations](./images/collections-reactivecollection-collection-operations.gif)

When `ReactiveCollection` class is `Dispose`d, it unsubscribes from the source IObservable instance.

## ReadOnlyReactiveCollection

`ReadOnlyReactiveCollection` class provides one-way synchronization from `ObservableCollection`. Can set converting logic, and dispatch `CollectionChanged` event raise on the `IScheduler`. The default `IScheduler` dispatches to the UI thread.

At first, create a POCO classes.

```csharp
public class BindableBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged([CallerMemberName]string propertyName = null) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    protected void SetProperty<T>(ref T field, T value, [CallerMemberName]string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value))
        {
            return;
        }

        field = value;
        RaisePropertyChanged(propertyName);
    }
}

public class TimerObject : BindableBase, IDisposable
{
    private IDisposable Disposable { get; }

    private long _count;
    public long Count
    {
        get { return _count; }
        private set { SetProperty(ref _count, value); }
    }

    public TimerObject()
    {
        Disposable = Observable.Interval(TimeSpan.FromSeconds(1))
            .Subscribe(_ => Count++);
    }

    public void Dispose()
    {
        Disposable.Dispose();
    }
}
```

This is a simple class that counts up the `Count` property per second.

Wrap the class to ViewModel layer using ReactiveProperty.

```csharp
public class TimerObjectViewModel : IDisposable
{
    public TimerObject Model { get; }

    public ReadOnlyReactiveProperty<string> CountMessage { get; }

    public TimerObjectViewModel(TimerObject timerObject)
    {
        Model = timerObject;
        CountMessage = Model.ObserveProperty(x => x.Count)
            .Select(x => $"Count value is {x}.")
            .ToReadOnlyReactiveProperty();
    }

    public void Dispose()
    {
        Model.Dispose();
    }
}
```

Manage `TimerObject` instances using the `ObservableCollection`.
We should provide `TimerObjectViewModel` instances to View layer, can use `ReadOnlyReactiveCollection` class.
`ReadOnlyReactiveCollection` instance is created using `ToReadOnlyReactiveCollection` extension method. 

```csharp
public class ViewModel
{
    // TimerObject collection
    private ReactiveCollection<TimerObject> ModelCollection { get; }
    // TimerObjectViewModel collection
    public ReadOnlyReactiveCollection<TimerObjectViewModel> ViewModelCollection { get; }

    public ReactiveCommand AddCommand { get; }

    public ReactiveCommand<TimerObjectViewModel> RemoveCommand { get; }

    public ViewModel()
    {
        AddCommand = new ReactiveCommand();
        ModelCollection = AddCommand
            .Select(_ => new TimerObject())
            .ToReactiveCollection();
        // Create a ReadOnlyReactiveCollection instance using the converting logic.
        ViewModelCollection = ModelCollection
            .ToReadOnlyReactiveCollection(x => new TimerObjectViewModel(x));

        RemoveCommand = new ReactiveCommand<TimerObjectViewModel>()
            .WithSubscribe(x => ModelCollection.Remove(x.Model));
    }
}
```

Test view is below.

```xml
<Page x:Class="App1.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:App1"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      xmlns:viewModels="using:ViewModels"
      mc:Ignorable="d"
      x:Name="root">
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Button Content="Add"
                Command="{x:Bind ViewModel.AddCommand}"
                Margin="5" />
        <ListView ItemsSource="{x:Bind ViewModel.ViewModelCollection}"
                  Grid.Row="1">
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="viewModels:TimerObjectViewModel">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>
                        <Button Content="Remove"
                                Command="{Binding ViewModel.RemoveCommand, ElementName=root}"
                                CommandParameter="{x:Bind}"
                                Margin="5" />
                        <TextBlock Text="{x:Bind CountMessage.Value, Mode=OneWay}"
                                   VerticalAlignment="Center"
                                   Style="{ThemeResource BodyTextBlockStyle}"
                                   Grid.Column="1" />
                    </Grid>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</Page>
```

![ReadOnlyReactiveCollection](./images/collections-reactivecollection-readonly-collection.gif)


When the instance was removed in the `ReadOnlyReactiveCollection`, then the `Dispose` method is called. If you don't need this behavior, then set the `disposeElement` argument to `false` in `ToReadOnlyReactiveCollection()`.

```csharp
ViewModelCollection = ModelCollection
    .ToReadOnlyReactiveCollection(x => new TimerObjectViewModel(x), disposeElement: false);
```

### Create from IObservable

`ReadOnlyReactiveCollection` can be created from `IObservable`, it is the same as the `ReactiveCollection`. But, `ReadOnlyReactiveCollection` doesn't have collection operation methods.
`ToReadOnlyReactiveCollection` extension method has an `onReset` argument which is `IObservable<Unit>`.
When this argument raises a value, then the collection is cleared.

```csharp
public class ViewModel
{
    public ReadOnlyReactiveCollection<string> Messages { get; }

    public ReactiveCommand ResetCommand { get; }

    public ViewModel()
    {
        ResetCommand = new ReactiveCommand();
        Messages = Observable.Interval(TimeSpan.FromSeconds(1))
            .Select(_ => DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"))
            .ToReadOnlyReactiveCollection(ResetCommand.ToUnit());
    }
}
```

```xml
<Page x:Class="App1.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:App1"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Button Content="Reset"
                Command="{x:Bind ViewModel.ResetCommand}"
                Margin="5" />
        <ListView ItemsSource="{x:Bind ViewModel.Messages}"
                  Grid.Row="1" />
    </Grid>
</Page>
```

When the `ResetCommand` is executed, clear the Messages.

![Reset](./images/collections-reactivecollection-readonly-collection-reset.gif)

## IFilteredReadOnlyObservableCollection

A collection which filters in realtime from `ObservableCollection`.
`IFilteredReadOnlyObservableCollection` watches the `PropertyChanged` event of the source collection item and the `CollectionChanged` event.

```csharp
public class ValueHolder : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public int Id { get; set; }

    private int _value;
    public int Value
    {
        get => _value;
        set
        {
            _value = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value)));
        }
    }

    public ValueHolder()
    {
        var r = new Random();
        Observable.Interval(TimeSpan.FromSeconds(1))
            .ObserveOnUIDispatcher()
            .Subscribe(_ => Value = r.Next(10));
    }
}

public class ViewModel
{
    public ReactiveCollection<ValueHolder> ValuesSource { get; }

    public IFilteredReadOnlyObservableCollection<ValueHolder> Values { get; }

    public ReactiveCommand AddCommand { get; }

    public ViewModel()
    {
        AddCommand = new ReactiveCommand();
        ValuesSource = AddCommand
            .Select(_ => new ValueHolder { Id = ValuesSource.Count })
            .ToReactiveCollection();
        Values = ValuesSource.ToFilteredReadOnlyObservableCollection(
            x => x.Value > 7);
    }
}
```

> `ObserveOnUIDispatcher` extension method switches to the UI thread from the current thread.


```xml
<Page x:Class="App1.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:App1"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      xmlns:viewModels="using:ViewModels"
      mc:Ignorable="d"
      x:Name="root">
    <Page.Resources>
        <DataTemplate x:Key="valueHolderDataTemplate"
                      x:DataType="viewModels:ValueHolder">
            <TextBlock>
                <Run Text="Id: " />
                <Run Text="{x:Bind Id}" />
                <Run Text=", Value: " />
                <Run Text="{x:Bind Value, Mode=OneWay}" />
            </TextBlock>
        </DataTemplate>
    </Page.Resources>
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Button Content="Add"
                Command="{x:Bind ViewModel.AddCommand}"
                Margin="5" />
        <TextBlock Text="Values"
                   Style="{ThemeResource TitleTextBlockStyle}"
                   Grid.Row="1" />
        <ListView ItemsSource="{x:Bind ViewModel.ValuesSource}"
                  ItemTemplate="{StaticResource valueHolderDataTemplate}"
                  Grid.Row="2" />
        <TextBlock Text="Filtered Values"
                   Style="{ThemeResource TitleTextBlockStyle}"
                   Grid.Row="1"
                   Grid.Column="1" />
        <ListView ItemsSource="{x:Bind ViewModel.Values}"
                  ItemTemplate="{StaticResource valueHolderDataTemplate}"
                  Grid.Row="2"
                  Grid.Column="1" />
    </Grid>
</Page>
```

![IFilteredReadOnlyObservableCollection](./images/collections-filtered-collection.gif)

When the Value property is greater than 7, then display the value in the Filtered Values ListView (right side).

If you want to change update elements trigger from CollectionChanged event to other, then you can customize it using another overload method that has `IObservable<T> sourceElementStatusChanged` argument.

For example, you want to filter nested property of elements on a collection.

```csharp
// An object that has nested object property
public class NestedPropertyObject
{
    public string Id { get; } => Guid.NewGuid().ToString();
    public ReactivePropertySlim<bool> NestedObject { get; } = new ReactivePropertySlim<bool>(true);
}


// Trigger
var sourceCollection = new ObservableCollection<NestedPropertyObject>
{
    new NestedPropertyObject(),
    new NestedPropertyObject(),
    new NestedPropertyObject(),
};

var filteredCollection = sourceCollection.ToFilteredReadOnlyObservableCollection(
    x => x.NestedObject.Value,
    source.ObserveElementProperty(x => x.NestedObject.Value).Select(x => x.Instance)
);

Console.WriteLine(filteredCollection.Count); // 3
sourceCollection[1].NestedObject.Value = false;
Console.WriteLine(filteredCollection.Count); // 2
```

> `collection.ToFilteredReadOnlyObservableCollection(x => x.SomeProperty)` is just a shortcut `collection.ToFilteredReadOnlyObservableCollection(x => x.SomeProperty, collection..ObserveElementPropertyChanged().Select(x => x.Sender))`.

<MSG> Merge pull request #300 from runceel/main

Release v8.0.0-pre
<DFF> @@ -464,19 +464,23 @@ public class ViewModel
 
 When the Value property is greater than 7, then display the value in the Filtered Values ListView (right side).
 
+### Customize how to observe collection elements
+
 If you want to change update elements trigger from CollectionChanged event to other, then you can customize it using another overload method that has `IObservable<T> sourceElementStatusChanged` argument.
 
 For example, you want to filter nested property of elements on a collection.
 
 ```csharp
 // An object that has nested object property
-public class NestedPropertyObject
+public class NestedPropertyObject : INotifyPropertyChanged
 {
+    // omit INPC impl
+
     public string Id { get; } => Guid.NewGuid().ToString();
     public ReactivePropertySlim<bool> NestedObject { get; } = new ReactivePropertySlim<bool>(true);
 }
 
-
+// --------------------
 // Trigger
 var sourceCollection = new ObservableCollection<NestedPropertyObject>
 {
@@ -486,13 +490,22 @@ var sourceCollection = new ObservableCollection<NestedPropertyObject>
 };
 
 var filteredCollection = sourceCollection.ToFilteredReadOnlyObservableCollection(
+    // a lambda expression for filter condition
     x => x.NestedObject.Value,
-    source.ObserveElementProperty(x => x.NestedObject.Value).Select(x => x.Instance)
+    // create a IObservable instance for update trigger of collection elements
+    x => x.ObserveProperty(y => NestedObject.Value)
 );
 
 Console.WriteLine(filteredCollection.Count); // 3
+// filteredCollection is observing NextedObject.Value property path.
+// Then the following line triggers re-eval for filter condition
 sourceCollection[1].NestedObject.Value = false;
 Console.WriteLine(filteredCollection.Count); // 2
 ```
 
-> `collection.ToFilteredReadOnlyObservableCollection(x => x.SomeProperty)` is just a shortcut `collection.ToFilteredReadOnlyObservableCollection(x => x.SomeProperty, collection..ObserveElementPropertyChanged().Select(x => x.Sender))`.
+The following two lines are same:
+
+```csharp
+collection.ToFilteredReadOnlyObservableCollection(x => x.SomeProperty);
+collection.ToFilteredReadOnlyObservableCollection(x => x.SomeProperty, x => x.PropertyChangedAsObservable());
+```

{'commit': 'diff --git a/Source/ReactiveProperty.NETStandard/Helpers/CollectionUtilities.cs b/Source/ReactiveProperty.NETStandard/Helpers/CollectionUtilities.cs\nindex 36d5f59..cd42386 100644\n--- a/Source/ReactiveProperty.NETStandard/Helpers/CollectionUtilities.cs\n+++ b/Source/ReactiveProperty.NETStandard/Helpers/CollectionUtilities.cs\n@@ -148,7 +148,7 @@ namespace Reactive.Bindings.Helpers\n         /// <param name="source">source collection</param>\n         /// <param name="subscribeAction">element subscribe logic.</param>\n         /// <returns></returns>\n-        private static IObservable<TResult> ObserveElementCore<TCollection, TElement, TResult>(TCollection source, Func<TElement, IObserver<TResult>, IDisposable> subscribeAction)\n+        internal static IObservable<TResult> ObserveElementCore<TCollection, TElement, TResult>(TCollection source, Func<TElement, IObserver<TResult>, IDisposable> subscribeAction)\n             where TCollection : INotifyCollectionChanged, IEnumerable<TElement>\n             where TElement : class\n         {\ndiff --git a/Source/ReactiveProperty.NETStandard/Helpers/FilteredReadOnlyObservableCollection.cs b/Source/ReactiveProperty.NETStandard/Helpers/FilteredReadOnlyObservableCollection.cs\nindex 0e3ed2f..ef5ccfe 100644\n--- a/Source/ReactiveProperty.NETStandard/Helpers/FilteredReadOnlyObservableCollection.cs\n+++ b/Source/ReactiveProperty.NETStandard/Helpers/FilteredReadOnlyObservableCollection.cs\n@@ -5,6 +5,7 @@ using System.Collections.ObjectModel;\n using System.Collections.Specialized;\n using System.ComponentModel;\n using System.Linq;\n+using System.Reactive;\n using System.Reactive.Concurrency;\n using System.Reactive.Disposables;\n using System.Reactive.Linq;\n@@ -43,7 +44,8 @@ namespace Reactive.Bindings.Helpers\n     /// </summary>\n     /// <typeparam name="TCollection">type of source collection</typeparam>\n     /// <typeparam name="TElement">type of collection item</typeparam>\n-    public sealed class FilteredReadOnlyObservableCollection<TCollection, TElement> : IFilteredReadOnlyObservableCollection<TElement>, IList // IList UWP GridView support.\n+    /// <typeparam name="TTrigger">type for IObservable to notify source status changed</typeparam>\n+    public sealed class FilteredReadOnlyObservableCollection<TCollection, TElement, TTrigger> : IFilteredReadOnlyObservableCollection<TElement>, IList // IList UWP GridView support.\n         where TCollection : INotifyCollectionChanged, IList<TElement>\n         where TElement : class, INotifyPropertyChanged\n     {\n@@ -68,14 +70,14 @@ namespace Reactive.Bindings.Helpers\n         /// </summary>\n         /// <param name="source">source collection</param>\n         /// <param name="filter">filter function</param>\n-        /// <param name="sourceElementStatusChanged">IObservable to notify source status changed</param>\n-        public FilteredReadOnlyObservableCollection(TCollection source, Func<TElement, bool> filter, IObservable<TElement> sourceElementStatusChanged)\n+        /// <param name="elementChangedFactory">IObservable to notify source status changed</param>\n+        public FilteredReadOnlyObservableCollection(TCollection source, Func<TElement, bool> filter, Func<TElement, IObservable<TTrigger>> elementChangedFactory)\n         {\n             Source = source ?? throw new ArgumentNullException(nameof(source));\n             Filter = filter ?? throw new ArgumentNullException(nameof(filter));\n-            if (sourceElementStatusChanged == null)\n+            if (elementChangedFactory == null)\n             {\n-                throw new ArgumentNullException(nameof(sourceElementStatusChanged));\n+                throw new ArgumentNullException(nameof(elementChangedFactory));\n             }\n \n             lock (_syncRoot)\n@@ -84,7 +86,9 @@ namespace Reactive.Bindings.Helpers\n             }\n \n             // propertychanged\n-            sourceElementStatusChanged.Subscribe(SourceElementChanged)\n+            CollectionUtilities.ObserveElementCore<TCollection, TElement, TElement>(source, (x, observer) =>\n+                elementChangedFactory(x).Subscribe(_ => observer.OnNext(x)))\n+                .Subscribe(SourceElementChanged)\n                 .AddTo(Subscription);\n \n             // collection changed(support single changed only)\n@@ -405,10 +409,10 @@ namespace Reactive.Bindings.Helpers\n         /// <returns></returns>\n         public static IFilteredReadOnlyObservableCollection<T> ToFilteredReadOnlyObservableCollection<T>(this ObservableCollection<T> self, Func<T, bool> filter)\n             where T : class, INotifyPropertyChanged =>\n-            new FilteredReadOnlyObservableCollection<ObservableCollection<T>, T>(\n+            new FilteredReadOnlyObservableCollection<ObservableCollection<T>, T, PropertyChangedEventArgs>(\n                 self, \n                 filter, \n-                self.ObserveElementPropertyChanged().Select(x => x.Sender));\n+                x => x.PropertyChangedAsObservable());\n \n         /// <summary>\n         /// create IFilteredReadOnlyObservableCollection from ReadOnlyObservableCollection\n@@ -419,34 +423,36 @@ namespace Reactive.Bindings.Helpers\n         /// <returns></returns>\n         public static IFilteredReadOnlyObservableCollection<T> ToFilteredReadOnlyObservableCollection<T>(this ReadOnlyObservableCollection<T> self, Func<T, bool> filter)\n             where T : class, INotifyPropertyChanged =>\n-            new FilteredReadOnlyObservableCollection<ReadOnlyObservableCollection<T>, T>(\n+            new FilteredReadOnlyObservableCollection<ReadOnlyObservableCollection<T>, T, PropertyChangedEventArgs>(\n                 self,\n                 filter,\n-                self.ObserveElementPropertyChanged().Select(x => x.Sender));\n+                x => x.PropertyChangedAsObservable());\n \n         /// <summary>\n         /// create IFilteredReadOnlyObservableCollection from ReadOnlyObservableCollection\n         /// </summary>\n         /// <typeparam name="T">Type of collection item.</typeparam>\n+        /// <typeparam name="U">Type of return type for elementStatusChangedFactory</typeparam>\n         /// <param name="self">Source collection.</param>\n         /// <param name="filter">Filter function.</param>\n-        /// <param name="sourceElementStatusChanged">IObservable to notify source status changed</param>\n+        /// <param name="elementStatusChangedFactory">IObservable to notify source status changed</param>\n         /// <returns></returns>\n-        public static IFilteredReadOnlyObservableCollection<T> ToFilteredReadOnlyObservableCollection<T>(this ReadOnlyObservableCollection<T> self, Func<T, bool> filter, IObservable<T> sourceElementStatusChanged)\n+        public static IFilteredReadOnlyObservableCollection<T> ToFilteredReadOnlyObservableCollection<T, U>(this ReadOnlyObservableCollection<T> self, Func<T, bool> filter, Func<T, IObservable<U>> elementStatusChangedFactory)\n             where T : class, INotifyPropertyChanged =>\n-            new FilteredReadOnlyObservableCollection<ReadOnlyObservableCollection<T>, T>(self, filter, sourceElementStatusChanged);\n+            new FilteredReadOnlyObservableCollection<ReadOnlyObservableCollection<T>, T, U>(self, filter, elementStatusChangedFactory);\n \n         /// <summary>\n         /// create IFilteredReadOnlyObservableCollection from ObservableCollection\n         /// </summary>\n         /// <typeparam name="T">Type of collection item.</typeparam>\n+        /// <typeparam name="U">Type of return type for elementStatusChangedFactory</typeparam>\n         /// <param name="self">Source collection.</param>\n         /// <param name="filter">Filter function.</param>\n-        /// <param name="sourceElementStatusChanged">IObservable to notify source status changed</param>\n+        /// <param name="elementStatusChangedFactory">IObservable to notify source status changed</param>\n         /// <returns></returns>\n-        public static IFilteredReadOnlyObservableCollection<T> ToFilteredReadOnlyObservableCollection<T>(this ObservableCollection<T> self, Func<T, bool> filter, IObservable<T> sourceElementStatusChanged)\n+        public static IFilteredReadOnlyObservableCollection<T> ToFilteredReadOnlyObservableCollection<T, U>(this ObservableCollection<T> self, Func<T, bool> filter, Func<T, IObservable<U>> elementStatusChangedFactory)\n             where T : class, INotifyPropertyChanged =>\n-            new FilteredReadOnlyObservableCollection<ObservableCollection<T>, T>(self, filter, sourceElementStatusChanged);\n+            new FilteredReadOnlyObservableCollection<ObservableCollection<T>, T, U>(self, filter, elementStatusChangedFactory);\n \n         /// <summary>\n         /// create ReadOnlyReactiveCollection from IFilteredReadOnlyObservableCollection\ndiff --git a/Test/ReactiveProperty.NETStandard.Tests/Helpers/FilteredReadOnlyObservableCollectionTest.cs b/Test/ReactiveProperty.NETStandard.Tests/Helpers/FilteredReadOnlyObservableCollectionTest.cs\nindex ace9490..25c7803 100644\n--- a/Test/ReactiveProperty.NETStandard.Tests/Helpers/FilteredReadOnlyObservableCollectionTest.cs\n+++ b/Test/ReactiveProperty.NETStandard.Tests/Helpers/FilteredReadOnlyObservableCollectionTest.cs\n@@ -400,8 +400,8 @@ namespace ReactiveProperty.Tests.Helpers\n             });\n \n             var filtered = source.ToFilteredReadOnlyObservableCollection(\n-                x => x.NestedObject.Value, \n-                source.ObserveElementProperty(x => x.NestedObject.Value).Select(x => x.Instance));\n+                x => x.NestedObject.Value,\n+                x => x.ObserveProperty(y => y.NestedObject.Value));\n             filtered.Select(x => x.Name).Is("tanaka1", "tanaka2", "tanaka3", "tanaka4", "tanaka5");\n             source[0].NestedObject.Value = false;\n             filtered.Select(x => x.Name).Is("tanaka2", "tanaka3", "tanaka4", "tanaka5");\ndiff --git a/docs/docs/features/Collections.md b/docs/docs/features/Collections.md\nindex aacfd9b..e344abe 100644\n--- a/docs/docs/features/Collections.md\n+++ b/docs/docs/features/Collections.md\n@@ -464,19 +464,23 @@ public class ViewModel\n \n When the Value property is greater than 7, then display the value in the Filtered Values ListView (right side).\n \n+### Customize how to observe collection elements\n+\n If you want to change update elements trigger from CollectionChanged event to other, then you can customize it using another overload method that has `IObservable<T> sourceElementStatusChanged` argument.\n \n For example, you want to filter nested property of elements on a collection.\n \n ```csharp\n // An object that has nested object property\n-public class NestedPropertyObject\n+public class NestedPropertyObject : INotifyPropertyChanged\n {\n+    // omit INPC impl\n+\n     public string Id { get; } => Guid.NewGuid().ToString();\n     public ReactivePropertySlim<bool> NestedObject { get; } = new ReactivePropertySlim<bool>(true);\n }\n \n-\n+// --------------------\n // Trigger\n var sourceCollection = new ObservableCollection<NestedPropertyObject>\n {\n@@ -486,13 +490,22 @@ var sourceCollection = new ObservableCollection<NestedPropertyObject>\n };\n \n var filteredCollection = sourceCollection.ToFilteredReadOnlyObservableCollection(\n+    // a lambda expression for filter condition\n     x => x.NestedObject.Value,\n-    source.ObserveElementProperty(x => x.NestedObject.Value).Select(x => x.Instance)\n+    // create a IObservable instance for update trigger of collection elements\n+    x => x.ObserveProperty(y => NestedObject.Value)\n );\n \n Console.WriteLine(filteredCollection.Count); // 3\n+// filteredCollection is observing NextedObject.Value property path.\n+// Then the following line triggers re-eval for filter condition\n sourceCollection[1].NestedObject.Value = false;\n Console.WriteLine(filteredCollection.Count); // 2\n ```\n \n-> `collection.ToFilteredReadOnlyObservableCollection(x => x.SomeProperty)` is just a shortcut `collection.ToFilteredReadOnlyObservableCollection(x => x.SomeProperty, collection..ObserveElementPropertyChanged().Select(x => x.Sender))`.\n+The following two lines are same:\n+\n+```csharp\n+collection.ToFilteredReadOnlyObservableCollection(x => x.SomeProperty);\n+collection.ToFilteredReadOnlyObservableCollection(x => x.SomeProperty, x => x.PropertyChangedAsObservable());\n+```\n', 'commit_subject': 'Merge pull request #300 from runceel/main', 'repo_name': 'runceel/ReactiveProperty', 'committer': {'name': 'GitHub', 'email': '1505422b2465e9a84f6fdfaa161078890c593f06@github.com', 'time_sec': '1633615028', 'tz_offset': '540', 'date': {'seconds': '1633615028'}}, 'commit_tree': '9686026c20471c77cee41588e17d70fa9924f6c4', 'commit_message': 'Merge pull request #300 from runceel/main\n\nRelease v8.0.0-pre', 'language_name': 'HTML', 'license': 'mit', 'hunks': '@@ -464,19 +464,23 @@ public class ViewModel\n \n When the Value property is greater than 7, then display the value in the Filtered Values ListView (right side).\n \n+### Customize how to observe collection elements\n+\n If you want to change update elements trigger from CollectionChanged event to other, then you can customize it using another overload method that has `IObservable<T> sourceElementStatusChanged` argument.\n \n For example, you want to filter nested property of elements on a collection.\n \n ```csharp\n // An object that has nested object property\n-public class NestedPropertyObject\n+public class NestedPropertyObject : INotifyPropertyChanged\n {\n+    // omit INPC impl\n+\n     public string Id { get; } => Guid.NewGuid().ToString();\n     public ReactivePropertySlim<bool> NestedObject { get; } = new ReactivePropertySlim<bool>(true);\n }\n \n-\n+// --------------------\n // Trigger\n var sourceCollection = new ObservableCollection<NestedPropertyObject>\n {\n@@ -486,13 +490,22 @@ var sourceCollection = new ObservableCollection<NestedPropertyObject>\n };\n \n var filteredCollection = sourceCollection.ToFilteredReadOnlyObservableCollection(\n+    // a lambda expression for filter condition\n     x => x.NestedObject.Value,\n-    source.ObserveElementProperty(x => x.NestedObject.Value).Select(x => x.Instance)\n+    // create a IObservable instance for update trigger of collection elements\n+    x => x.ObserveProperty(y => NestedObject.Value)\n );\n \n Console.WriteLine(filteredCollection.Count); // 3\n+// filteredCollection is observing NextedObject.Value property path.\n+// Then the following line triggers re-eval for filter condition\n sourceCollection[1].NestedObject.Value = false;\n Console.WriteLine(filteredCollection.Count); // 2\n ```\n \n-> `collection.ToFilteredReadOnlyObservableCollection(x => x.SomeProperty)` is just a shortcut `collection.ToFilteredReadOnlyObservableCollection(x => x.SomeProperty, collection..ObserveElementPropertyChanged().Select(x => x.Sender))`.\n+The following two lines are same:\n+\n+```csharp\n+collection.ToFilteredReadOnlyObservableCollection(x => x.SomeProperty);\n+collection.ToFilteredReadOnlyObservableCollection(x => x.SomeProperty, x => x.PropertyChangedAsObservable());\n+```\n', 'addition_count': 17, 'deletion_count': 4, 'src_file': 'a/docs/docs/features/Collections.md', 'tgt_file': 'b/docs/docs/features/Collections.md', 'file_extension': '.md', 'before_file': '# Collections\n\nReactiveProperty provides some collection classes.\n\n- ReactiveCollection&lt;T&gt;\n- ReadOnlyReactiveCollection&lt;T&gt;\n- IFilteredReadOnlyObservableCollection&lt;T&gt;\n\n## ReactiveCollection\n\n`ReactiveCollection` inherits `ObservableCollection`.\nThis class is created from `IObservable`.\nIt adds an item when a value is provided from the source `IObservable`.\n`ReactiveCollection` executes this process using `IScheduler`. The default `IScheduler` dispatches to the UI thread.\n\n```csharp\npublic class ViewModel\n{\n    public ReactiveCollection<DateTime> Records { get; }\n\n    public ReactiveCommand StartRecordCommand { get; }\n\n    public ViewModel()\n    {\n        StartRecordCommand = new ReactiveCommand();\n        // Create a ReactiveCollection instance from IObservable\n        Records = StartRecordCommand\n            .ToUnit()\n            .Take(1)\n            .Concat(Observable.Defer(() => Observable.Interval(TimeSpan.FromSeconds(1)).ToUnit()))\n            .Select(_ => DateTime.Now)\n            .ToReactiveCollection();\n    }\n}\n```\n\n> `ToUnit` extension method is defined in the Reactive.Bindings.Extensions namespace.\n> This extension method is same as `.Select(_ => Unide.Default)`.\n\nExample of UWP platform.\n\nMainPage.xaml.cs\n```csharp\npublic sealed partial class MainPage : Page\n{\n    public ViewModel ViewModel { get; } = new ViewModel();\n    public MainPage()\n    {\n        this.InitializeComponent();\n    }\n}\n```\n\nMainPage.xaml\n```xml\n<Page x:Class="App1.MainPage"\n      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"\n      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"\n      xmlns:local="using:App1"\n      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"\n      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"\n      mc:Ignorable="d">\n    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">\n        <Grid.RowDefinitions>\n            <RowDefinition Height="Auto" />\n            <RowDefinition />\n        </Grid.RowDefinitions>\n        <StackPanel Orientation="Horizontal">\n            <Button Content="Start"\n                    Command="{x:Bind ViewModel.StartRecordCommand}"\n                    Margin="5" />\n        </StackPanel>\n        <ListView ItemsSource="{x:Bind ViewModel.Records}"\n                  Grid.Row="1" />\n    </Grid>\n</Page>\n```\n\n![Basic usage](./images/collections-reactivecollection-basic-usage.gif)\n\n## Collection operations\n\n`ReactiveCollection` class has `XxxxOnScheduler` methods. For example, `AddOnScheduler`, `RemoveOnScheduler`, `ClearOnScheduler`, `GetOnScheduler`, etc...\nThose methods run on the `IScheduler` and can be called from outside of the UI thread.\n\n```csharp\npublic class ViewModel\n{\n    public ReactiveCollection<DateTime> Records { get; }\n\n    public ReactiveCommand StartRecordCommand { get; }\n\n    public ReactiveCommand ClearCommand { get; }\n\n    public ViewModel()\n    {\n        StartRecordCommand = new ReactiveCommand();\n        // Create a ReactiveCollection instance from IObservable\n        Records = StartRecordCommand\n            .ToUnit()\n            .Take(1)\n            .Concat(Observable.Defer(() => Observable.Interval(TimeSpan.FromSeconds(1)).ToUnit()))\n            .Select(_ => DateTime.Now)\n            .ToReactiveCollection();\n\n        ClearCommand = new ReactiveCommand();\n        ClearCommand.ObserveOn(TaskPoolScheduler.Default) // run on the another thread\n            .Subscribe(_ => Records.ClearOnScheduler());\n    }\n}\n```\n\n```xml\n<Page x:Class="App1.MainPage"\n      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"\n      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"\n      xmlns:local="using:App1"\n      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"\n      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"\n      mc:Ignorable="d">\n    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">\n        <Grid.RowDefinitions>\n            <RowDefinition Height="Auto" />\n            <RowDefinition />\n        </Grid.RowDefinitions>\n        <StackPanel Orientation="Horizontal">\n            <Button Content="Start"\n                    Command="{x:Bind ViewModel.StartRecordCommand}"\n                    Margin="5" />\n            <Button Content="Clear"\n                    Command="{x:Bind ViewModel.ClearCommand}"\n                    Margin="5" />\n        </StackPanel>\n        <ListView ItemsSource="{x:Bind ViewModel.Records}"\n                  Grid.Row="1" />\n    </Grid>\n</Page>\n```\n\n![Collection operations](./images/collections-reactivecollection-collection-operations.gif)\n\nWhen `ReactiveCollection` class is `Dispose`d, it unsubscribes from the source IObservable instance.\n\n## ReadOnlyReactiveCollection\n\n`ReadOnlyReactiveCollection` class provides one-way synchronization from `ObservableCollection`. Can set converting logic, and dispatch `CollectionChanged` event raise on the `IScheduler`. The default `IScheduler` dispatches to the UI thread.\n\nAt first, create a POCO classes.\n\n```csharp\npublic class BindableBase : INotifyPropertyChanged\n{\n    public event PropertyChangedEventHandler PropertyChanged;\n\n    protected void RaisePropertyChanged([CallerMemberName]string propertyName = null) =>\n        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));\n\n    protected void SetProperty<T>(ref T field, T value, [CallerMemberName]string propertyName = null)\n    {\n        if (EqualityComparer<T>.Default.Equals(field, value))\n        {\n            return;\n        }\n\n        field = value;\n        RaisePropertyChanged(propertyName);\n    }\n}\n\npublic class TimerObject : BindableBase, IDisposable\n{\n    private IDisposable Disposable { get; }\n\n    private long _count;\n    public long Count\n    {\n        get { return _count; }\n        private set { SetProperty(ref _count, value); }\n    }\n\n    public TimerObject()\n    {\n        Disposable = Observable.Interval(TimeSpan.FromSeconds(1))\n            .Subscribe(_ => Count++);\n    }\n\n    public void Dispose()\n    {\n        Disposable.Dispose();\n    }\n}\n```\n\nThis is a simple class that counts up the `Count` property per second.\n\nWrap the class to ViewModel layer using ReactiveProperty.\n\n```csharp\npublic class TimerObjectViewModel : IDisposable\n{\n    public TimerObject Model { get; }\n\n    public ReadOnlyReactiveProperty<string> CountMessage { get; }\n\n    public TimerObjectViewModel(TimerObject timerObject)\n    {\n        Model = timerObject;\n        CountMessage = Model.ObserveProperty(x => x.Count)\n            .Select(x => $"Count value is {x}.")\n            .ToReadOnlyReactiveProperty();\n    }\n\n    public void Dispose()\n    {\n        Model.Dispose();\n    }\n}\n```\n\nManage `TimerObject` instances using the `ObservableCollection`.\nWe should provide `TimerObjectViewModel` instances to View layer, can use `ReadOnlyReactiveCollection` class.\n`ReadOnlyReactiveCollection` instance is created using `ToReadOnlyReactiveCollection` extension method. \n\n```csharp\npublic class ViewModel\n{\n    // TimerObject collection\n    private ReactiveCollection<TimerObject> ModelCollection { get; }\n    // TimerObjectViewModel collection\n    public ReadOnlyReactiveCollection<TimerObjectViewModel> ViewModelCollection { get; }\n\n    public ReactiveCommand AddCommand { get; }\n\n    public ReactiveCommand<TimerObjectViewModel> RemoveCommand { get; }\n\n    public ViewModel()\n    {\n        AddCommand = new ReactiveCommand();\n        ModelCollection = AddCommand\n            .Select(_ => new TimerObject())\n            .ToReactiveCollection();\n        // Create a ReadOnlyReactiveCollection instance using the converting logic.\n        ViewModelCollection = ModelCollection\n            .ToReadOnlyReactiveCollection(x => new TimerObjectViewModel(x));\n\n        RemoveCommand = new ReactiveCommand<TimerObjectViewModel>()\n            .WithSubscribe(x => ModelCollection.Remove(x.Model));\n    }\n}\n```\n\nTest view is below.\n\n```xml\n<Page x:Class="App1.MainPage"\n      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"\n      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"\n      xmlns:local="using:App1"\n      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"\n      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"\n      xmlns:viewModels="using:ViewModels"\n      mc:Ignorable="d"\n      x:Name="root">\n    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">\n        <Grid.RowDefinitions>\n            <RowDefinition Height="Auto" />\n            <RowDefinition />\n        </Grid.RowDefinitions>\n        <Button Content="Add"\n                Command="{x:Bind ViewModel.AddCommand}"\n                Margin="5" />\n        <ListView ItemsSource="{x:Bind ViewModel.ViewModelCollection}"\n                  Grid.Row="1">\n            <ListView.ItemTemplate>\n                <DataTemplate x:DataType="viewModels:TimerObjectViewModel">\n                    <Grid>\n                        <Grid.ColumnDefinitions>\n                            <ColumnDefinition Width="Auto" />\n                            <ColumnDefinition />\n                        </Grid.ColumnDefinitions>\n                        <Button Content="Remove"\n                                Command="{Binding ViewModel.RemoveCommand, ElementName=root}"\n                                CommandParameter="{x:Bind}"\n                                Margin="5" />\n                        <TextBlock Text="{x:Bind CountMessage.Value, Mode=OneWay}"\n                                   VerticalAlignment="Center"\n                                   Style="{ThemeResource BodyTextBlockStyle}"\n                                   Grid.Column="1" />\n                    </Grid>\n                </DataTemplate>\n            </ListView.ItemTemplate>\n        </ListView>\n    </Grid>\n</Page>\n```\n\n![ReadOnlyReactiveCollection](./images/collections-reactivecollection-readonly-collection.gif)\n\n\nWhen the instance was removed in the `ReadOnlyReactiveCollection`, then the `Dispose` method is called. If you don\'t need this behavior, then set the `disposeElement` argument to `false` in `ToReadOnlyReactiveCollection()`.\n\n```csharp\nViewModelCollection = ModelCollection\n    .ToReadOnlyReactiveCollection(x => new TimerObjectViewModel(x), disposeElement: false);\n```\n\n### Create from IObservable\n\n`ReadOnlyReactiveCollection` can be created from `IObservable`, it is the same as the `ReactiveCollection`. But, `ReadOnlyReactiveCollection` doesn\'t have collection operation methods.\n`ToReadOnlyReactiveCollection` extension method has an `onReset` argument which is `IObservable<Unit>`.\nWhen this argument raises a value, then the collection is cleared.\n\n```csharp\npublic class ViewModel\n{\n    public ReadOnlyReactiveCollection<string> Messages { get; }\n\n    public ReactiveCommand ResetCommand { get; }\n\n    public ViewModel()\n    {\n        ResetCommand = new ReactiveCommand();\n        Messages = Observable.Interval(TimeSpan.FromSeconds(1))\n            .Select(_ => DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"))\n            .ToReadOnlyReactiveCollection(ResetCommand.ToUnit());\n    }\n}\n```\n\n```xml\n<Page x:Class="App1.MainPage"\n      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"\n      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"\n      xmlns:local="using:App1"\n      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"\n      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"\n      mc:Ignorable="d">\n    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">\n        <Grid.RowDefinitions>\n            <RowDefinition Height="Auto" />\n            <RowDefinition />\n        </Grid.RowDefinitions>\n        <Button Content="Reset"\n                Command="{x:Bind ViewModel.ResetCommand}"\n                Margin="5" />\n        <ListView ItemsSource="{x:Bind ViewModel.Messages}"\n                  Grid.Row="1" />\n    </Grid>\n</Page>\n```\n\nWhen the `ResetCommand` is executed, clear the Messages.\n\n![Reset](./images/collections-reactivecollection-readonly-collection-reset.gif)\n\n## IFilteredReadOnlyObservableCollection\n\nA collection which filters in realtime from `ObservableCollection`.\n`IFilteredReadOnlyObservableCollection` watches the `PropertyChanged` event of the source collection item and the `CollectionChanged` event.\n\n```csharp\npublic class ValueHolder : INotifyPropertyChanged\n{\n    public event PropertyChangedEventHandler PropertyChanged;\n\n    public int Id { get; set; }\n\n    private int _value;\n    public int Value\n    {\n        get => _value;\n        set\n        {\n            _value = value;\n            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value)));\n        }\n    }\n\n    public ValueHolder()\n    {\n        var r = new Random();\n        Observable.Interval(TimeSpan.FromSeconds(1))\n            .ObserveOnUIDispatcher()\n            .Subscribe(_ => Value = r.Next(10));\n    }\n}\n\npublic class ViewModel\n{\n    public ReactiveCollection<ValueHolder> ValuesSource { get; }\n\n    public IFilteredReadOnlyObservableCollection<ValueHolder> Values { get; }\n\n    public ReactiveCommand AddCommand { get; }\n\n    public ViewModel()\n    {\n        AddCommand = new ReactiveCommand();\n        ValuesSource = AddCommand\n            .Select(_ => new ValueHolder { Id = ValuesSource.Count })\n            .ToReactiveCollection();\n        Values = ValuesSource.ToFilteredReadOnlyObservableCollection(\n            x => x.Value > 7);\n    }\n}\n```\n\n> `ObserveOnUIDispatcher` extension method switches to the UI thread from the current thread.\n\n\n```xml\n<Page x:Class="App1.MainPage"\n      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"\n      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"\n      xmlns:local="using:App1"\n      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"\n      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"\n      xmlns:viewModels="using:ViewModels"\n      mc:Ignorable="d"\n      x:Name="root">\n    <Page.Resources>\n        <DataTemplate x:Key="valueHolderDataTemplate"\n                      x:DataType="viewModels:ValueHolder">\n            <TextBlock>\n                <Run Text="Id: " />\n                <Run Text="{x:Bind Id}" />\n                <Run Text=", Value: " />\n                <Run Text="{x:Bind Value, Mode=OneWay}" />\n            </TextBlock>\n        </DataTemplate>\n    </Page.Resources>\n    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">\n        <Grid.RowDefinitions>\n            <RowDefinition Height="Auto" />\n            <RowDefinition Height="Auto" />\n            <RowDefinition />\n        </Grid.RowDefinitions>\n        <Grid.ColumnDefinitions>\n            <ColumnDefinition />\n            <ColumnDefinition />\n        </Grid.ColumnDefinitions>\n        <Button Content="Add"\n                Command="{x:Bind ViewModel.AddCommand}"\n                Margin="5" />\n        <TextBlock Text="Values"\n                   Style="{ThemeResource TitleTextBlockStyle}"\n                   Grid.Row="1" />\n        <ListView ItemsSource="{x:Bind ViewModel.ValuesSource}"\n                  ItemTemplate="{StaticResource valueHolderDataTemplate}"\n                  Grid.Row="2" />\n        <TextBlock Text="Filtered Values"\n                   Style="{ThemeResource TitleTextBlockStyle}"\n                   Grid.Row="1"\n                   Grid.Column="1" />\n        <ListView ItemsSource="{x:Bind ViewModel.Values}"\n                  ItemTemplate="{StaticResource valueHolderDataTemplate}"\n                  Grid.Row="2"\n                  Grid.Column="1" />\n    </Grid>\n</Page>\n```\n\n![IFilteredReadOnlyObservableCollection](./images/collections-filtered-collection.gif)\n\nWhen the Value property is greater than 7, then display the value in the Filtered Values ListView (right side).\n\nIf you want to change update elements trigger from CollectionChanged event to other, then you can customize it using another overload method that has `IObservable<T> sourceElementStatusChanged` argument.\n\nFor example, you want to filter nested property of elements on a collection.\n\n```csharp\n// An object that has nested object property\npublic class NestedPropertyObject\n{\n    public string Id { get; } => Guid.NewGuid().ToString();\n    public ReactivePropertySlim<bool> NestedObject { get; } = new ReactivePropertySlim<bool>(true);\n}\n\n\n// Trigger\nvar sourceCollection = new ObservableCollection<NestedPropertyObject>\n{\n    new NestedPropertyObject(),\n    new NestedPropertyObject(),\n    new NestedPropertyObject(),\n};\n\nvar filteredCollection = sourceCollection.ToFilteredReadOnlyObservableCollection(\n    x => x.NestedObject.Value,\n    source.ObserveElementProperty(x => x.NestedObject.Value).Select(x => x.Instance)\n);\n\nConsole.WriteLine(filteredCollection.Count); // 3\nsourceCollection[1].NestedObject.Value = false;\nConsole.WriteLine(filteredCollection.Count); // 2\n```\n\n> `collection.ToFilteredReadOnlyObservableCollection(x => x.SomeProperty)` is just a shortcut `collection.ToFilteredReadOnlyObservableCollection(x => x.SomeProperty, collection..ObserveElementPropertyChanged().Select(x => x.Sender))`.\n', 'message': 'Merge pull request #300 from runceel/main\n\nRelease v8.0.0-pre', 'author_name': 'GitHub', 'lang': 'md'}