From 45af63627b1d332d2108a249ab5ef152633f4b90 Mon Sep 17 00:00:00 2001 From: Kazuki Ota Date: Fri, 29 Apr 2022 23:23:22 +0900 Subject: [PATCH 01/14] update a sample for blazer --- .../BlazorSample.Shared/Pages/Index.razor | 47 +++++++++++++++---- .../ViewModels/HelloWorldViewModel.cs | 26 ++++++++++ ...dexViewModel.cs => ValidationViewModel.cs} | 4 +- Samples/Blazor/BlazorServerApp/App.razor | 2 +- Samples/Blazor/BlazorServerApp/Program.cs | 3 +- Samples/Blazor/BlazorWasmApp/App.razor | 2 +- Samples/Blazor/BlazorWasmApp/Program.cs | 3 +- 7 files changed, 72 insertions(+), 15 deletions(-) create mode 100644 Samples/Blazor/BlazorSample.Shared/ViewModels/HelloWorldViewModel.cs rename Samples/Blazor/BlazorSample.Shared/ViewModels/{IndexViewModel.cs => ValidationViewModel.cs} (94%) diff --git a/Samples/Blazor/BlazorSample.Shared/Pages/Index.razor b/Samples/Blazor/BlazorSample.Shared/Pages/Index.razor index 79d42307..cc8bc717 100644 --- a/Samples/Blazor/BlazorSample.Shared/Pages/Index.razor +++ b/Samples/Blazor/BlazorSample.Shared/Pages/Index.razor @@ -1,27 +1,43 @@ -@using Reactive.Bindings.Components +@using Reactive.Bindings +@using Reactive.Bindings.Extensions +@using Reactive.Bindings.Components +@using System.Reactive.Linq +@using System.Reactive.Disposables +@using System.Reactive.Concurrency @page "/" -@inject IndexViewModel _viewModel +@implements IDisposable +@inject ValidationViewModel _validationViewModel +@inject HelloWorldViewModel _helloWorldViewModel -

ReactivePropertiesValidator sample

+

ReactiveProperty samples

- +

Hello world

+ + +
+ @_helloWorldViewModel.Output.Value +
+ +

Validation sample

+ +
- - + +
- - + +
- Full name: @_viewModel.FullName.Value + Full name: @_validationViewModel.FullName.Value
@@ -35,6 +51,7 @@ } @code { + private readonly CompositeDisposable _disposable = new(); private string? _message; private void InvalidSubmit(EditContext context) @@ -46,4 +63,16 @@ { _message = "ValidSubmit was invoked."; } + + protected override void OnInitialized() + { + _validationViewModel.AddTo(_disposable); + _helloWorldViewModel.AddTo(_disposable); + + _helloWorldViewModel.Output + .Subscribe(_ => InvokeAsync(StateHasChanged)) + .AddTo(_disposable); + } + + public void Dispose() => _disposable.Dispose(); } diff --git a/Samples/Blazor/BlazorSample.Shared/ViewModels/HelloWorldViewModel.cs b/Samples/Blazor/BlazorSample.Shared/ViewModels/HelloWorldViewModel.cs new file mode 100644 index 00000000..c895aa53 --- /dev/null +++ b/Samples/Blazor/BlazorSample.Shared/ViewModels/HelloWorldViewModel.cs @@ -0,0 +1,26 @@ +using System.Reactive.Disposables; +using System.Reactive.Linq; +using Reactive.Bindings; +using Reactive.Bindings.Extensions; + +namespace BlazorSample.Shared.ViewModels; + +public class HelloWorldViewModel : IDisposable +{ + private readonly CompositeDisposable _disposable = new(); + + public ReactivePropertySlim Input { get; } + public ReadOnlyReactivePropertySlim Output { get; } + + public HelloWorldViewModel() + { + Input = new ReactivePropertySlim("") + .AddTo(_disposable); + Output = Input + .Select(x => x.ToUpperInvariant()) + .ToReadOnlyReactivePropertySlim("") + .AddTo(_disposable); + } + + public void Dispose() => _disposable.Dispose(); +} diff --git a/Samples/Blazor/BlazorSample.Shared/ViewModels/IndexViewModel.cs b/Samples/Blazor/BlazorSample.Shared/ViewModels/ValidationViewModel.cs similarity index 94% rename from Samples/Blazor/BlazorSample.Shared/ViewModels/IndexViewModel.cs rename to Samples/Blazor/BlazorSample.Shared/ViewModels/ValidationViewModel.cs index 4c716626..2e0ecca0 100644 --- a/Samples/Blazor/BlazorSample.Shared/ViewModels/IndexViewModel.cs +++ b/Samples/Blazor/BlazorSample.Shared/ViewModels/ValidationViewModel.cs @@ -6,7 +6,7 @@ namespace BlazorSample.Shared.ViewModels; -public class IndexViewModel : IDisposable +public class ValidationViewModel : IDisposable { private readonly CompositeDisposable _disposables = new(); @@ -18,7 +18,7 @@ public class IndexViewModel : IDisposable public ReactiveProperty LastName { get; } public ReadOnlyReactivePropertySlim FullName { get; } - public IndexViewModel() + public ValidationViewModel() { var reactivePropertyMode = ReactivePropertyMode.Default | ReactivePropertyMode.IgnoreInitialValidationError; FirstName = new ReactiveProperty("", mode: reactivePropertyMode) diff --git a/Samples/Blazor/BlazorServerApp/App.razor b/Samples/Blazor/BlazorServerApp/App.razor index 5ad7119f..7ea6f775 100644 --- a/Samples/Blazor/BlazorServerApp/App.razor +++ b/Samples/Blazor/BlazorServerApp/App.razor @@ -1,5 +1,5 @@ @using BlazorSample.Shared.ViewModels - + diff --git a/Samples/Blazor/BlazorServerApp/Program.cs b/Samples/Blazor/BlazorServerApp/Program.cs index 77a08a6a..ae71739c 100644 --- a/Samples/Blazor/BlazorServerApp/Program.cs +++ b/Samples/Blazor/BlazorServerApp/Program.cs @@ -9,7 +9,8 @@ builder.Services.AddRazorPages(); builder.Services.AddServerSideBlazor(); builder.Services.AddSingleton(); -builder.Services.AddTransient(); +builder.Services.AddTransient(); +builder.Services.AddTransient(); var app = builder.Build(); diff --git a/Samples/Blazor/BlazorWasmApp/App.razor b/Samples/Blazor/BlazorWasmApp/App.razor index 5ad7119f..7ea6f775 100644 --- a/Samples/Blazor/BlazorWasmApp/App.razor +++ b/Samples/Blazor/BlazorWasmApp/App.razor @@ -1,5 +1,5 @@ @using BlazorSample.Shared.ViewModels - + diff --git a/Samples/Blazor/BlazorWasmApp/Program.cs b/Samples/Blazor/BlazorWasmApp/Program.cs index 3ba5bd4d..22be29d8 100644 --- a/Samples/Blazor/BlazorWasmApp/Program.cs +++ b/Samples/Blazor/BlazorWasmApp/Program.cs @@ -7,7 +7,8 @@ builder.RootComponents.Add("#app"); builder.RootComponents.Add("head::after"); -builder.Services.AddTransient(); +builder.Services.AddTransient(); +builder.Services.AddTransient(); builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); await builder.Build().RunAsync(); From 885ed12e87ff99b0bb4a2b1348fa69d1ee266f04 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 29 Apr 2022 14:40:21 +0000 Subject: [PATCH 02/14] Bump async from 2.6.3 to 2.6.4 in /docs Bumps [async](https://github.com/caolan/async) from 2.6.3 to 2.6.4. - [Release notes](https://github.com/caolan/async/releases) - [Changelog](https://github.com/caolan/async/blob/v2.6.4/CHANGELOG.md) - [Commits](https://github.com/caolan/async/compare/v2.6.3...v2.6.4) --- updated-dependencies: - dependency-name: async dependency-type: indirect ... Signed-off-by: dependabot[bot] --- docs/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/package-lock.json b/docs/package-lock.json index bc34ef09..948f6327 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -1975,9 +1975,9 @@ "dev": true }, "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "dev": true, "requires": { "lodash": "^4.17.14" From 24e9e112c6e220a568757e15efe7d64656792c72 Mon Sep 17 00:00:00 2001 From: Kazuki Ota Date: Fri, 29 Apr 2022 23:54:23 +0900 Subject: [PATCH 03/14] add documents for blazor --- docs/docs/.vuepress/config.js | 1 + docs/docs/getting-started/blazor.md | 125 ++++++++++++++++++ .../images/blazor-helloworld.png | Bin 0 -> 41957 bytes 3 files changed, 126 insertions(+) create mode 100644 docs/docs/getting-started/blazor.md create mode 100644 docs/docs/getting-started/images/blazor-helloworld.png diff --git a/docs/docs/.vuepress/config.js b/docs/docs/.vuepress/config.js index bd4eff9f..c4e14de6 100644 --- a/docs/docs/.vuepress/config.js +++ b/docs/docs/.vuepress/config.js @@ -14,6 +14,7 @@ module.exports = { { text: 'Xamarin.Forms', link: '/getting-started/xf.html' }, { text: 'Avalonia', link: '/getting-started/avalonia.html' }, { text: 'Uno Platform', link: '/getting-started/uno-platform.html' }, + { text: 'Blazor', link: '/getting-started/blazor.html' }, { text: 'Add code snippets', link: '/getting-started/add-snippets.html' }, ] }, diff --git a/docs/docs/getting-started/blazor.md b/docs/docs/getting-started/blazor.md new file mode 100644 index 00000000..c38e52a8 --- /dev/null +++ b/docs/docs/getting-started/blazor.md @@ -0,0 +1,125 @@ +# Getting start for Blazor + +Blazor is for development framework for Single Page Application using C#. + +See below: + +[ASP.NET Core Blazor](https://docs.microsoft.com/en-us/aspnet/core/blazor/) + +ReactiveProperty also works both of Blazor Server and Blazor WebAssembly. But Blazor WebAssembly doen't support all operations of Reactive Extensions. For example, `Delay` extension method doesn't work on Blazor WASM. +If you want to use ReactiveProperty on Blazor WASM, then please care to not use unsupported features. + +## Create a project + +- Create a Blazor Server or WebAssembly project. +- Install ReactiveProperty.Blazor package from NuGet. + +## Edit codes + +- Create a class what name is `IndexViewModel`. +- Edit the class like fillowing: + +```csharp +using Reactive.Bindings; +using Reactive.Bindings.Extensions; +using System.Reactive.Disposables; +using System.Reactive.Linq; + +namespace BlazorApp1; + +public class IndexViewModel : IDisposable +{ + private CompositeDisposable _disposable = new(); + + public ReactivePropertySlim Input { get; } + public ReadOnlyReactivePropertySlim Output { get; } + + public IndexViewModel() + { + Input = new ReactivePropertySlim("") + .AddTo(_disposable); + Output = Input + .Select(x => x.ToUpperInvariant()) + .ToReadOnlyReactivePropertySlim("") + .AddTo(_disposable); + } + + public void Dispose() => _disposable.Dispose(); +} +``` + +- Edit Index.razor like below: + +```csharp +@page "/" +@using System.Reactive.Disposables +@using Reactive.Bindings.Extensions +@implements IDisposable + +Index + +

Hello, world!

+ + +
+@_viewModel.Output.Value +
+ +@code { + private readonly CompositeDisposable _disposable = new(); + private IndexViewModel _viewModel = default!; + + protected override void OnInitialized() + { + _viewModel = new IndexViewModel() + .AddTo(_disposable); + + // Observe changing Output property, and call StateHasChanged on UI thread. + _viewModel.Output + .Subscribe(x => InvokeAsync(StateHasChanged)) + .AddTo(_disposable); + } + + public void Dispose() => _disposable.Dispose(); +} +``` + +- Launch this app + +You can see below result: + +![Launch the app](.images/blazor-helloworld.png) + +## Other topics for Blazor + +### Dependency Injection + +If you want to inject ViewModels to page, then please register ViewModels to DI container on Program.cs like below: + +```csharp +builder.Services.AddTransient(); +``` + +And inject to page like `@inject IndexViewModel _viewModel`. + + +### Integrate validation feature + +If you want to use validation feature of ReactiveProperty with Blazor's EditForm component, then you can use `Reactive.Bindings.Components.ReactivePropertiesValidator` component. + +`ReactivePropertiesValidator` can be used same as `DataAnnotationsValidator` component like below: + +```csharp + + @* needs @using Reactive.Bindings.Components *@ + + + +
+ + + +
+``` + +Please see Blazor's sample app under Samples/Blazor folder to know more details. The page using it is Pages/Index.razor page of BlazorSample.Shared project. diff --git a/docs/docs/getting-started/images/blazor-helloworld.png b/docs/docs/getting-started/images/blazor-helloworld.png new file mode 100644 index 0000000000000000000000000000000000000000..ba2df8f649077e969827503ca2171db304fde599 GIT binary patch literal 41957 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®7E|oOx_wXNpYJ_#b994x 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 A8vp Date: Sat, 30 Apr 2022 00:00:10 +0900 Subject: [PATCH 04/14] add Delay --- docs/docs/getting-started/blazor.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/getting-started/blazor.md b/docs/docs/getting-started/blazor.md index c38e52a8..bfc377e3 100644 --- a/docs/docs/getting-started/blazor.md +++ b/docs/docs/getting-started/blazor.md @@ -39,6 +39,7 @@ public class IndexViewModel : IDisposable Input = new ReactivePropertySlim("") .AddTo(_disposable); Output = Input + .Delay(TimeSpan.FromSeconds(2)) // Important! Delay method doesn't work on Blazor WASM. If you are working on WASM, then please remove this line. .Select(x => x.ToUpperInvariant()) .ToReadOnlyReactivePropertySlim("") .AddTo(_disposable); From 291a91db5dfe2f23a607cb9f62e68012d0cb67ea Mon Sep 17 00:00:00 2001 From: Kazuki Ota Date: Sat, 30 Apr 2022 00:03:29 +0900 Subject: [PATCH 05/14] fix typo --- docs/docs/getting-started/blazor.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/getting-started/blazor.md b/docs/docs/getting-started/blazor.md index bfc377e3..e3633113 100644 --- a/docs/docs/getting-started/blazor.md +++ b/docs/docs/getting-started/blazor.md @@ -89,7 +89,7 @@ public class IndexViewModel : IDisposable You can see below result: -![Launch the app](.images/blazor-helloworld.png) +![Launch the app](./images/blazor-helloworld.png) ## Other topics for Blazor From 8f52ab0b2b9294ae01de3147defc7846639f14da Mon Sep 17 00:00:00 2001 From: Kazuki Ota Date: Sat, 30 Apr 2022 11:12:44 +0900 Subject: [PATCH 06/14] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9dd066f6..53326e7e 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ Binding code: It's very simple. -ReactiveProperty doesn't provide base class by ViewModel, which means that ReactiveProperty can be used together with another MVVM library like Prism, MVVMLight, etc... +ReactiveProperty doesn't provide base class by ViewModel, which means that ReactiveProperty can be used together with another MVVM libraries such as Prism, Microsoft.Toolkit.Mvvm and etc. ## Documentation @@ -140,6 +140,7 @@ ReactiveProperty doesn't provide base class by ViewModel, which means that React |[ReactiveProperty](https://www.nuget.org/packages/ReactiveProperty/)|![](https://img.shields.io/nuget/v/ReactiveProperty.svg)![](https://img.shields.io/nuget/dt/ReactiveProperty.svg)|The package includes all core features, and the target platform is .NET Standard 2.0. It fits almost all situations.| |[ReactiveProperty.Core](https://www.nuget.org/packages/ReactiveProperty.Core/)|![](https://img.shields.io/nuget/v/ReactiveProperty.Core.svg)![](https://img.shields.io/nuget/dt/ReactiveProperty.Core.svg)|The package includes minimum classes such as `ReactivePropertySlim` and `ReadOnlyReactivePropertySlim`. And this doesn't have any dependency even System.Reactive. If you don't need Rx features, then it fits.| |[ReactiveProperty.WPF](https://www.nuget.org/packages/ReactiveProperty.WPF/)|![](https://img.shields.io/nuget/v/ReactiveProperty.WPF.svg)![](https://img.shields.io/nuget/dt/ReactiveProperty.WPF.svg)|The package includes EventToReactiveProperty and EventToReactiveCommand for WPF. This is for .NET Core 3.0 or later and .NET Framework 4.7.2 or later.| +|[ReactiveProperty.Blazor](https://www.nuget.org/packages/ReactiveProperty.Blazor/)|![](https://img.shields.io/nuget/v/ReactiveProperty.Blazor.svg)![](https://img.shields.io/nuget/dt/ReactiveProperty.Blazor.svg)|The package includes validation support for EditForm component of Blazor with ReactiveProperty validation feature. This is for .NET 6.0 or later. | |[ReactiveProperty.UWP](https://www.nuget.org/packages/ReactiveProperty.UWP/)|![](https://img.shields.io/nuget/v/ReactiveProperty.UWP.svg)![](https://img.shields.io/nuget/dt/ReactiveProperty.UWP.svg)|The package includes EventToReactiveProperty and EventToReactiveCommand for UWP.| |[ReactiveProperty.XamarinAndroid](https://www.nuget.org/packages/ReactiveProperty.XamarinAndroid/)|![](https://img.shields.io/nuget/v/ReactiveProperty.XamarinAndroid.svg)![](https://img.shields.io/nuget/dt/ReactiveProperty.XamarinAndroid.svg)|The package includes many extension methods to create IObservable from events for Xamarin.Android native.| |[ReactiveProperty.XamariniOS](https://www.nuget.org/packages/ReactiveProperty.XamariniOS/)|![](https://img.shields.io/nuget/v/ReactiveProperty.XamariniOS.svg)![](https://img.shields.io/nuget/dt/ReactiveProperty.XamariniOS.svg)|The package includes many extension methods to bind ReactiveProperty and ReactiveCommand to Xamarin.iOS native controls.| From 2494135d2083a97ec9c5ee1fb5e19ead873e6185 Mon Sep 17 00:00:00 2001 From: Kazuki Ota Date: Sun, 8 May 2022 10:20:21 +0900 Subject: [PATCH 07/14] add nullable --- .../Binding/RxBindingExtensions.cs | 32 ++++++++++--------- .../Binding/RxCommandExtensions.cs | 4 ++- .../INotifyPropertyChangedExtensions.cs | 10 +++--- .../PairwiseObservableExtensions.cs | 4 +-- .../Extensions/RetryObservableExtensions.cs | 4 +-- 5 files changed, 28 insertions(+), 26 deletions(-) diff --git a/Source/ReactiveProperty.NETStandard/Binding/RxBindingExtensions.cs b/Source/ReactiveProperty.NETStandard/Binding/RxBindingExtensions.cs index 43d0e51a..357a2e68 100644 --- a/Source/ReactiveProperty.NETStandard/Binding/RxBindingExtensions.cs +++ b/Source/ReactiveProperty.NETStandard/Binding/RxBindingExtensions.cs @@ -1,4 +1,6 @@ -using System; +// This namespace is not used almost all cases. low priority to add nullable annnotation. +#nullable disable +using System; using System.Diagnostics; using System.Linq.Expressions; using System.Reactive; @@ -34,11 +36,11 @@ public static IDisposable BindTo( TTarget target, Expression> propertySelector, BindingMode mode = BindingMode.OneWay, - Func? convert = null, - Func? convertBack = null, - IObservable? targetUpdateTrigger = null, - TProperty? propertyFallbackValue = default(TProperty), - T? sourceFallbackValue = default(T)) + Func convert = null, + Func convertBack = null, + IObservable targetUpdateTrigger = null, + TProperty propertyFallbackValue = default(TProperty), + T sourceFallbackValue = default(T)) { if (convert == null) { @@ -101,8 +103,8 @@ public static IDisposable BindTo( this ReadOnlyReactiveProperty self, TTarget target, Expression> propertySelector, - Func? convert = null, - TProperty? propertyFallbackValue = default(TProperty)) + Func convert = null, + TProperty propertyFallbackValue = default(TProperty)) { if (convert == null) { @@ -138,11 +140,11 @@ public static IDisposable BindTo( TTarget target, Expression> propertySelector, BindingMode mode = BindingMode.OneWay, - Func? convert = null, - Func? convertBack = null, - IObservable? targetUpdateTrigger = null, - TProperty? propertyFallbackValue = default(TProperty), - T? sourceFallbackValue = default(T)) + Func convert = null, + Func convertBack = null, + IObservable targetUpdateTrigger = null, + TProperty propertyFallbackValue = default(TProperty), + T sourceFallbackValue = default(T)) { if (convert == null) { @@ -205,8 +207,8 @@ public static IDisposable BindTo( this ReadOnlyReactivePropertySlim self, TTarget target, Expression> propertySelector, - Func? convert = null, - TProperty? propertyFallbackValue = default(TProperty)) + Func convert = null, + TProperty propertyFallbackValue = default(TProperty)) { if (convert == null) { diff --git a/Source/ReactiveProperty.NETStandard/Binding/RxCommandExtensions.cs b/Source/ReactiveProperty.NETStandard/Binding/RxCommandExtensions.cs index b6c24595..b0a9dd58 100644 --- a/Source/ReactiveProperty.NETStandard/Binding/RxCommandExtensions.cs +++ b/Source/ReactiveProperty.NETStandard/Binding/RxCommandExtensions.cs @@ -1,4 +1,6 @@ -using System; +// This namespace is not used almost all cases. low priority to add nullable annnotation. +#nullable disable +using System; namespace Reactive.Bindings.Binding; diff --git a/Source/ReactiveProperty.NETStandard/Extensions/INotifyPropertyChangedExtensions.cs b/Source/ReactiveProperty.NETStandard/Extensions/INotifyPropertyChangedExtensions.cs index 459c57dd..d6ee8c46 100644 --- a/Source/ReactiveProperty.NETStandard/Extensions/INotifyPropertyChangedExtensions.cs +++ b/Source/ReactiveProperty.NETStandard/Extensions/INotifyPropertyChangedExtensions.cs @@ -244,7 +244,7 @@ public static ReactiveProperty ToReactivePropertyAsSynchronized observer, x => x) .StartWith(observer.GetPropertyPathValue())) - .ToReactiveProperty(raiseEventScheduler, mode: mode); + .ToReactiveProperty(raiseEventScheduler, mode: mode); convertBack(result.Where(_ => !ignoreValidationErrorValue || !result.HasErrors)) .Subscribe(x => observer.SetPropertyPathValue(x)); return result; @@ -253,7 +253,7 @@ public static ReactiveProperty ToReactivePropertyAsSynchronized.LookupSet(propertySelector, out _); var result = convert(subject.ObserveProperty(propertySelector, isPushCurrentValueAtFirst: true)) - .ToReactiveProperty(raiseEventScheduler, mode: mode); + .ToReactiveProperty(raiseEventScheduler, mode: mode); convertBack(result.Where(_ => !ignoreValidationErrorValue || !result.HasErrors)) .Subscribe(x => setter(subject, x)); return result; @@ -347,8 +347,7 @@ public static ReactivePropertySlim ToReactivePropertySlimAsSynchronized { var result = new ReactivePropertySlim(mode: mode); var observer = PropertyObservable.CreateFromPropertySelector(subject, propertySelector); - IDisposable disposable = null; - disposable = convert(subject.ObserveProperty(propertySelector, isPushCurrentValueAtFirst: true)) + var disposable = convert(subject.ObserveProperty(propertySelector, isPushCurrentValueAtFirst: true)) .Subscribe(x => result.Value = x); convertBack(result) .Subscribe(x => observer.SetPropertyPathValue(x), _ => disposable.Dispose(), () => disposable.Dispose()); @@ -358,8 +357,7 @@ public static ReactivePropertySlim ToReactivePropertySlimAsSynchronized { var setter = AccessorCache.LookupSet(propertySelector, out _); var result = new ReactivePropertySlim(mode: mode); - IDisposable disposable = null; - disposable = convert(subject.ObserveProperty(propertySelector, isPushCurrentValueAtFirst: true)) + var disposable = convert(subject.ObserveProperty(propertySelector, isPushCurrentValueAtFirst: true)) .Subscribe(x => result.Value = x); convertBack(result) .Subscribe(x => setter(subject, x), _ => disposable.Dispose(), () => disposable.Dispose()); diff --git a/Source/ReactiveProperty.NETStandard/Extensions/PairwiseObservableExtensions.cs b/Source/ReactiveProperty.NETStandard/Extensions/PairwiseObservableExtensions.cs index b808faad..d3576492 100644 --- a/Source/ReactiveProperty.NETStandard/Extensions/PairwiseObservableExtensions.cs +++ b/Source/ReactiveProperty.NETStandard/Extensions/PairwiseObservableExtensions.cs @@ -21,7 +21,7 @@ public static IObservable Pairwise(this IObservable source, Func(observer => { - var prev = default(T); + T prev = default!; var isFirst = true; return source.Subscribe(x => @@ -36,7 +36,7 @@ public static IObservable Pairwise(this IObservable source, Func OnErrorRetry( var empty = Observable.Empty(); var count = 0; - IObservable? self = null; + IObservable self = null!; self = source.Catch((TException ex) => { onError(ex); return (++count < retryCount) ? (dueTime == TimeSpan.Zero) - ? self!.SubscribeOn(Scheduler.CurrentThread) + ? self.SubscribeOn(Scheduler.CurrentThread) : empty.Delay(dueTime, delayScheduler).Concat(self).SubscribeOn(Scheduler.CurrentThread) : Observable.Throw(ex); }); From 914a8a3bbc4c5726f922d7ab07c950a36ec40c6b Mon Sep 17 00:00:00 2001 From: Kazuki Ota Date: Fri, 27 May 2022 09:23:14 +0900 Subject: [PATCH 08/14] Add test for reproducing for Issue 379. --- .../FilteredReadOnlyObservableCollectionTest.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Test/ReactiveProperty.NETStandard.Tests/Helpers/FilteredReadOnlyObservableCollectionTest.cs b/Test/ReactiveProperty.NETStandard.Tests/Helpers/FilteredReadOnlyObservableCollectionTest.cs index 03420bc8..673eb502 100644 --- a/Test/ReactiveProperty.NETStandard.Tests/Helpers/FilteredReadOnlyObservableCollectionTest.cs +++ b/Test/ReactiveProperty.NETStandard.Tests/Helpers/FilteredReadOnlyObservableCollectionTest.cs @@ -462,6 +462,23 @@ public void NestedPropertyCase() filtered.Select(x => x.Name).Is("tanaka2", "tanaka3", "tanaka4", "tanaka5"); } + [TestMethod] + public void ElementStatusChangedFactoryWithObservePropertyTest() + { + // https://github.com/runceel/ReactiveProperty/issues/379 + var observableCollection = new ObservableCollection(); + + var filteredCollection = observableCollection.ToFilteredReadOnlyObservableCollection( + filter: x => x.Name == "test", + elementStatusChangedFactory: x => x.ObserveProperty(x => x.Name)); + + AssertEx.DoesNotThrow(() => + { + var element = new Person(); + observableCollection.Add(element); // Exception thrown here (Issue 379) + }); + } + private class Person : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; From b648383b43d277bad8a100e020fa97b646b1c6b5 Mon Sep 17 00:00:00 2001 From: Kazuki Ota Date: Fri, 27 May 2022 09:33:37 +0900 Subject: [PATCH 09/14] format --- .../Helpers/CollectionUtilities.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Source/ReactiveProperty.NETStandard/Helpers/CollectionUtilities.cs b/Source/ReactiveProperty.NETStandard/Helpers/CollectionUtilities.cs index cc693276..5aebd1e9 100644 --- a/Source/ReactiveProperty.NETStandard/Helpers/CollectionUtilities.cs +++ b/Source/ReactiveProperty.NETStandard/Helpers/CollectionUtilities.cs @@ -154,11 +154,11 @@ internal static IObservable ObserveElementCore(observer => { - //--- cache element property subscriptions - var subscriptionCache = new Dictionary(); + //--- cache element property subscriptions + var subscriptionCache = new Dictionary(); - //--- subscribe / unsubscribe property which all elements have - void subscribe(IEnumerable elements) + //--- subscribe / unsubscribe property which all elements have + void subscribe(IEnumerable elements) { foreach (var x in elements) { @@ -177,14 +177,14 @@ void unsubscribeAll() } subscribe(source); - //--- hook collection changed - var disposable = source.CollectionChangedAsObservable().Subscribe(x => + //--- hook collection changed + var disposable = source.CollectionChangedAsObservable().Subscribe(x => { if (x.Action == NotifyCollectionChangedAction.Remove || x.Action == NotifyCollectionChangedAction.Replace) { - //--- unsubscribe - var oldItems = x.OldItems.Cast(); + //--- unsubscribe + var oldItems = x.OldItems.Cast(); foreach (var y in oldItems) { subscriptionCache[y].Dispose(); @@ -206,8 +206,8 @@ void unsubscribeAll() } }); - //--- unsubscribe - return Disposable.Create(() => + //--- unsubscribe + return Disposable.Create(() => { disposable.Dispose(); unsubscribeAll(); From da7cc551a3d9705bd46e34438aa1a5b1e0e4827f Mon Sep 17 00:00:00 2001 From: Kazuki Ota Date: Fri, 27 May 2022 09:34:15 +0900 Subject: [PATCH 10/14] Fix #379 --- .../Helpers/FilteredReadOnlyObservableCollection.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/ReactiveProperty.NETStandard/Helpers/FilteredReadOnlyObservableCollection.cs b/Source/ReactiveProperty.NETStandard/Helpers/FilteredReadOnlyObservableCollection.cs index 221b4611..f2febb17 100644 --- a/Source/ReactiveProperty.NETStandard/Helpers/FilteredReadOnlyObservableCollection.cs +++ b/Source/ReactiveProperty.NETStandard/Helpers/FilteredReadOnlyObservableCollection.cs @@ -86,14 +86,14 @@ public FilteredReadOnlyObservableCollection(TCollection source, Func(source, (x, observer) => elementChangedFactory(x).Subscribe(_ => observer.OnNext(x))) .Subscribe(SourceElementChanged) .AddTo(Subscription); - - // collection changed(support single changed only) - source.CollectionChanged += Source_CollectionChanged; } private void SourceElementChanged(TElement x) From 102e78ea42d4ca250b06a80dfff77429da53e347 Mon Sep 17 00:00:00 2001 From: Kazuki Ota Date: Fri, 27 May 2022 09:51:59 +0900 Subject: [PATCH 11/14] increment version number to 8.1.1 --- Source/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Directory.Build.props b/Source/Directory.Build.props index 5db16283..648900db 100644 --- a/Source/Directory.Build.props +++ b/Source/Directory.Build.props @@ -1,7 +1,7 @@ Reactive.Bindings - 8.1.0 + 8.1.1 neuecc xin9le okazuki https://github.com/runceel/ReactiveProperty rx mvvm async rx-main reactive From c35d8562f3d6000a3dbd13d23f21933cd423b036 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Jun 2022 20:12:30 +0000 Subject: [PATCH 12/14] Bump eventsource from 1.0.7 to 1.1.1 in /docs Bumps [eventsource](https://github.com/EventSource/eventsource) from 1.0.7 to 1.1.1. - [Release notes](https://github.com/EventSource/eventsource/releases) - [Changelog](https://github.com/EventSource/eventsource/blob/master/HISTORY.md) - [Commits](https://github.com/EventSource/eventsource/compare/v1.0.7...v1.1.1) --- updated-dependencies: - dependency-name: eventsource dependency-type: indirect ... Signed-off-by: dependabot[bot] --- docs/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/package-lock.json b/docs/package-lock.json index 948f6327..cabf966d 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -4247,9 +4247,9 @@ "dev": true }, "eventsource": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz", - "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.1.tgz", + "integrity": "sha512-qV5ZC0h7jYIAOhArFJgSfdyz6rALJyb270714o7ZtNnw2WSJ+eexhKtE0O8LYPRsHZHf2osHKZBxGPvm3kPkCA==", "dev": true, "requires": { "original": "^1.0.0" From 44ce88dae8e0f61361cedf1bb86f3a573aa305c7 Mon Sep 17 00:00:00 2001 From: Kazuki Ota Date: Sun, 5 Jun 2022 19:51:08 +0900 Subject: [PATCH 13/14] add nullable --- .../INotifyCollectionChangedExtensions.cs | 5 +++- .../INotifyPropertyChangedExtensions.cs | 8 +++---- .../Helpers/CollectionUtilities.cs | 5 ++-- .../IEventToReactiveConverter.cs | 4 ++-- .../Interactivity/ReactiveConverter.cs | 6 ++--- .../Internals/PropertyObservable.cs | 4 ++-- .../Internals/PropertyPathNode.cs | 2 +- .../ReactiveProperty.cs | 24 +++++++++---------- .../ReactivePropertyExtensions.cs | 4 ++-- .../ListAdapter.cs | 6 ++--- .../ReactiveProperty.Platform.Android.csproj | 1 + .../ReactiveProperty.Platform.iOS.csproj | 1 + 12 files changed, 38 insertions(+), 32 deletions(-) diff --git a/Source/ReactiveProperty.NETStandard/Extensions/INotifyCollectionChangedExtensions.cs b/Source/ReactiveProperty.NETStandard/Extensions/INotifyCollectionChangedExtensions.cs index 776d0150..2bd56876 100644 --- a/Source/ReactiveProperty.NETStandard/Extensions/INotifyCollectionChangedExtensions.cs +++ b/Source/ReactiveProperty.NETStandard/Extensions/INotifyCollectionChangedExtensions.cs @@ -12,6 +12,9 @@ namespace Reactive.Bindings.Extensions; +// TODO: remove this line later. +#nullable disable + ///

/// INotify Collection Changed Extensions /// @@ -49,7 +52,7 @@ public static IObservable ObserveAddChangedItems(this INotifyCollectionC public static IObservable ObserveRemoveChanged(this INotifyCollectionChanged source) => source.CollectionChangedAsObservable() .Where(e => e.Action == NotifyCollectionChangedAction.Remove) - .Select(e => (T)e.OldItems[0]); + .Select(e => (T)e.OldItems[0]!); /// /// Observe CollectionChanged:Remove. diff --git a/Source/ReactiveProperty.NETStandard/Extensions/INotifyPropertyChangedExtensions.cs b/Source/ReactiveProperty.NETStandard/Extensions/INotifyPropertyChangedExtensions.cs index d6ee8c46..400cfd6a 100644 --- a/Source/ReactiveProperty.NETStandard/Extensions/INotifyPropertyChangedExtensions.cs +++ b/Source/ReactiveProperty.NETStandard/Extensions/INotifyPropertyChangedExtensions.cs @@ -116,8 +116,7 @@ public static ReactiveProperty ToReactivePropertyAsSynchronized observer, x => x) - .StartWith(observer.GetPropertyPathValue()) - .ToReactiveProperty(raiseEventScheduler, mode: mode); + .ToReactiveProperty(raiseEventScheduler, initialValue: observer.GetPropertyPathValue(), mode: mode); result .Where(_ => !ignoreValidationErrorValue || !result.HasErrors) .Subscribe(x => observer.SetPropertyPathValue(x)); @@ -125,8 +124,9 @@ public static ReactiveProperty ToReactivePropertyAsSynchronized.LookupGet(propertySelector, out var _); + var result = subject.ObserveSimpleProperty(propertySelector, isPushCurrentValueAtFirst: false) + .ToReactiveProperty(raiseEventScheduler, initialValue: getter(subject), mode: mode); var setter = AccessorCache.LookupSet(propertySelector, out _); result .Where(_ => !ignoreValidationErrorValue || !result.HasErrors) diff --git a/Source/ReactiveProperty.NETStandard/Helpers/CollectionUtilities.cs b/Source/ReactiveProperty.NETStandard/Helpers/CollectionUtilities.cs index 5aebd1e9..01672d09 100644 --- a/Source/ReactiveProperty.NETStandard/Helpers/CollectionUtilities.cs +++ b/Source/ReactiveProperty.NETStandard/Helpers/CollectionUtilities.cs @@ -86,8 +86,9 @@ public static IObservable> ObserveElementObser if (!(propertySelector.Body is MemberExpression memberExpression)) { if (!(propertySelector.Body is UnaryExpression unaryExpression)) { throw new ArgumentException(nameof(propertySelector)); } - memberExpression = unaryExpression.Operand as MemberExpression; - if (memberExpression == null) { throw new ArgumentException(nameof(propertySelector)); } + var operand = unaryExpression.Operand as MemberExpression; + if (operand == null) { throw new ArgumentException(nameof(propertySelector)); } + memberExpression = operand; } var propertyInfo = memberExpression.Member as PropertyInfo; diff --git a/Source/ReactiveProperty.NETStandard/Interactivity/IEventToReactiveConverter.cs b/Source/ReactiveProperty.NETStandard/Interactivity/IEventToReactiveConverter.cs index 14bbfe65..f3bc14c3 100644 --- a/Source/ReactiveProperty.NETStandard/Interactivity/IEventToReactiveConverter.cs +++ b/Source/ReactiveProperty.NETStandard/Interactivity/IEventToReactiveConverter.cs @@ -14,12 +14,12 @@ public interface IEventToReactiveConverter /// Gets or sets the associate object. /// /// The associate object. - object AssociateObject { get; set; } + object? AssociateObject { get; set; } /// /// Converts the specified source. /// /// The source. /// - IObservable Convert(IObservable source); + IObservable Convert(IObservable source); } diff --git a/Source/ReactiveProperty.NETStandard/Interactivity/ReactiveConverter.cs b/Source/ReactiveProperty.NETStandard/Interactivity/ReactiveConverter.cs index 5ac40a96..eb77fa81 100644 --- a/Source/ReactiveProperty.NETStandard/Interactivity/ReactiveConverter.cs +++ b/Source/ReactiveProperty.NETStandard/Interactivity/ReactiveConverter.cs @@ -17,19 +17,19 @@ public abstract class ReactiveConverter : IEventToReactiveConverter /// /// EventToReactiveCommand's AssociateObject /// - public object AssociateObject { get; set; } + public object? AssociateObject { get; set; } /// /// Converts the specified source. /// /// The source. /// - public IObservable Convert(IObservable source) => OnConvert(source.Cast()).Select(x => (object)x); + public IObservable Convert(IObservable source) => OnConvert(source.Select(x => (T?)x)).Select(x => (object?)x); /// /// Converts /// /// source /// dest - protected abstract IObservable OnConvert(IObservable source); + protected abstract IObservable OnConvert(IObservable source); } diff --git a/Source/ReactiveProperty.NETStandard/Internals/PropertyObservable.cs b/Source/ReactiveProperty.NETStandard/Internals/PropertyObservable.cs index 13709568..1ed30b28 100644 --- a/Source/ReactiveProperty.NETStandard/Internals/PropertyObservable.cs +++ b/Source/ReactiveProperty.NETStandard/Internals/PropertyObservable.cs @@ -7,7 +7,7 @@ namespace Reactive.Bindings.Internals; internal sealed class PropertyObservable : IObservable, IDisposable { - private PropertyPathNode RootNode { get; set; } + private PropertyPathNode? RootNode { get; set; } internal void SetRootNode(PropertyPathNode rootNode) { RootNode?.SetCallback(null); @@ -17,7 +17,7 @@ internal void SetRootNode(PropertyPathNode rootNode) public TProperty GetPropertyPathValue() { var value = RootNode?.GetPropertyPathValue(); - return value != null ? (TProperty)value : default; + return value != null ? (TProperty)value : default!; } public string Path => RootNode?.Path; diff --git a/Source/ReactiveProperty.NETStandard/Internals/PropertyPathNode.cs b/Source/ReactiveProperty.NETStandard/Internals/PropertyPathNode.cs index 6a5888b4..e5c66344 100644 --- a/Source/ReactiveProperty.NETStandard/Internals/PropertyPathNode.cs +++ b/Source/ReactiveProperty.NETStandard/Internals/PropertyPathNode.cs @@ -24,7 +24,7 @@ public PropertyPathNode(string propertyName) private Type? PrevSourceType { get; set; } public PropertyPathNode? Next { get; private set; } public PropertyPathNode? Prev { get; private set; } - public void SetCallback(Action callback) + public void SetCallback(Action? callback) { _callback = callback; Next?.SetCallback(callback); diff --git a/Source/ReactiveProperty.NETStandard/ReactiveProperty.cs b/Source/ReactiveProperty.NETStandard/ReactiveProperty.cs index b3b518f5..62983a5b 100644 --- a/Source/ReactiveProperty.NETStandard/ReactiveProperty.cs +++ b/Source/ReactiveProperty.NETStandard/ReactiveProperty.cs @@ -82,7 +82,7 @@ public class ReactiveProperty : IReactiveProperty, IObserverLinkedList private Lazy> ErrorsTrigger { get; } - private Lazy, IObservable>>> ValidatorStore { get; } = new Lazy, IObservable>>>(() => new List, IObservable>>()); + private Lazy, IObservable>>> ValidatorStore { get; } = new Lazy, IObservable>>>(() => new List, IObservable>>()); /// /// PropertyChanged raise on ReactivePropertyScheduler @@ -283,7 +283,7 @@ public override string ToString() => /// /// If success return IO<null>, failure return IO<IEnumerable>(Errors). /// Self. - public ReactiveProperty SetValidateNotifyError(Func, IObservable> validator) + public ReactiveProperty SetValidateNotifyError(Func, IObservable> validator) { ValidatorStore.Value.Add(validator); //--- cache validation functions var validators = ValidatorStore.Value @@ -304,12 +304,12 @@ public ReactiveProperty SetValidateNotifyError(Func, IObservab } var strings = xs - .OfType() - .Where(x => x != null); + .Where(x => x != null) + .OfType(); var others = xs - .Where(x => !(x is string)) + .Where(x => x is not string) .Where(x => x != null) - .SelectMany(x => x.Cast()); + .SelectMany(x => x!.Cast()); return strings.Concat(others); }) .Subscribe(x => @@ -339,15 +339,15 @@ public ReactiveProperty SetValidateNotifyError(Func, IObservab /// /// If success return IO<null>, failure return IO<IEnumerable>(Errors). /// Self. - public ReactiveProperty SetValidateNotifyError(Func, IObservable> validator) => - SetValidateNotifyError(xs => validator(xs).Cast()); + public ReactiveProperty SetValidateNotifyError(Func, IObservable> validator) => + SetValidateNotifyError(xs => validator(xs).Select(x => (IEnumerable?)x)); /// /// Set INotifyDataErrorInfo's asynchronous validation. /// /// Validation logic /// Self. - public ReactiveProperty SetValidateNotifyError(Func> validator) => + public ReactiveProperty SetValidateNotifyError(Func> validator) => SetValidateNotifyError(xs => xs.SelectMany(x => validator(x))); /// @@ -355,7 +355,7 @@ public ReactiveProperty SetValidateNotifyError(Func> val /// /// Validation logic /// Self. - public ReactiveProperty SetValidateNotifyError(Func> validator) => + public ReactiveProperty SetValidateNotifyError(Func> validator) => SetValidateNotifyError(xs => xs.SelectMany(x => validator(x))); /// @@ -363,7 +363,7 @@ public ReactiveProperty SetValidateNotifyError(Func> validato /// /// Validation logic /// Self. - public ReactiveProperty SetValidateNotifyError(Func validator) => + public ReactiveProperty SetValidateNotifyError(Func validator) => SetValidateNotifyError(xs => xs.Select(x => validator(x))); /// @@ -371,7 +371,7 @@ public ReactiveProperty SetValidateNotifyError(Func validator /// /// Validation logic /// Self. - public ReactiveProperty SetValidateNotifyError(Func validator) => + public ReactiveProperty SetValidateNotifyError(Func validator) => SetValidateNotifyError(xs => xs.Select(x => validator(x))); /// diff --git a/Source/ReactiveProperty.NETStandard/ReactivePropertyExtensions.cs b/Source/ReactiveProperty.NETStandard/ReactivePropertyExtensions.cs index a5bf0611..851f8b43 100644 --- a/Source/ReactiveProperty.NETStandard/ReactivePropertyExtensions.cs +++ b/Source/ReactiveProperty.NETStandard/ReactivePropertyExtensions.cs @@ -20,7 +20,7 @@ public static class ReactivePropertyExtensions /// Target ReactiveProperty /// Target property as expression /// Self - public static ReactiveProperty SetValidateAttribute(this ReactiveProperty self, Expression>> selfSelector) + public static ReactiveProperty SetValidateAttribute(this ReactiveProperty self, Expression?>> selfSelector) { var memberExpression = (MemberExpression)selfSelector.Body; var propertyInfo = (PropertyInfo)memberExpression.Member; @@ -54,7 +54,7 @@ public static ReactiveProperty SetValidateAttribute(this ReactiveProperty< /// /// Property type /// Target ReactiveProperty - public static IObservable ObserveValidationErrorMessage(this ReactiveProperty self) => + public static IObservable ObserveValidationErrorMessage(this ReactiveProperty self) => self.ObserveErrorChanged .Select(x => x?.OfType()?.FirstOrDefault()); } diff --git a/Source/ReactiveProperty.Platform.Android/ListAdapter.cs b/Source/ReactiveProperty.Platform.Android/ListAdapter.cs index 9ec0d224..827c9f6b 100644 --- a/Source/ReactiveProperty.Platform.Android/ListAdapter.cs +++ b/Source/ReactiveProperty.Platform.Android/ListAdapter.cs @@ -26,7 +26,7 @@ public class ListAdapter : BaseAdapter /// create view /// set row data /// get id - public ListAdapter(IList list, Func createRowView, Action setRowData, Func? getId = null) + public ListAdapter(IList list, Func createRowView, Action setRowData, Func getId = null) { List = list ?? throw new ArgumentNullException(nameof(list)); CreateRowView = createRowView ?? throw new ArgumentNullException(nameof(createRowView)); @@ -65,7 +65,7 @@ public ListAdapter(IList list, Func createRowView, ActionTo be added. /// To be added. /// To be added. - public override View GetView(int position, View? convertView, ViewGroup? parent) + public override View GetView(int position, View convertView, ViewGroup parent) { if (convertView == null) { @@ -91,6 +91,6 @@ public static class ListExtensions /// fill row data /// get id /// ListAdapter - public static ListAdapter ToAdapter(this IList self, Func createRowView, Action setRowData, Func? getId = null) => + public static ListAdapter ToAdapter(this IList self, Func createRowView, Action setRowData, Func getId = null) => new(self, createRowView, setRowData, getId); } diff --git a/Source/ReactiveProperty.Platform.Android/ReactiveProperty.Platform.Android.csproj b/Source/ReactiveProperty.Platform.Android/ReactiveProperty.Platform.Android.csproj index 3e5e9c81..219d3c5d 100644 --- a/Source/ReactiveProperty.Platform.Android/ReactiveProperty.Platform.Android.csproj +++ b/Source/ReactiveProperty.Platform.Android/ReactiveProperty.Platform.Android.csproj @@ -7,6 +7,7 @@ true key.snk ReactiveProperty.XamarinAndroid provides many useful extension methods for Xamarin.Android that can be used with ReactiveProperty. + disable diff --git a/Source/ReactiveProperty.Platform.iOS/ReactiveProperty.Platform.iOS.csproj b/Source/ReactiveProperty.Platform.iOS/ReactiveProperty.Platform.iOS.csproj index cd902632..f455f7ed 100644 --- a/Source/ReactiveProperty.Platform.iOS/ReactiveProperty.Platform.iOS.csproj +++ b/Source/ReactiveProperty.Platform.iOS/ReactiveProperty.Platform.iOS.csproj @@ -7,6 +7,7 @@ true key.snk ReactiveProperty.XamariniOS provides many useful extension methods for Xamarin.iOS that can be used with ReactiveProperty. + disable From d61a3a3f4bd21337f4cedccf2214fc52e0a59b05 Mon Sep 17 00:00:00 2001 From: Kazuki Ota Date: Sun, 5 Jun 2022 19:51:59 +0900 Subject: [PATCH 14/14] increment version nnumber --- Source/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Directory.Build.props b/Source/Directory.Build.props index 648900db..ff7dcdec 100644 --- a/Source/Directory.Build.props +++ b/Source/Directory.Build.props @@ -1,7 +1,7 @@ Reactive.Bindings - 8.1.1 + 8.1.2 neuecc xin9le okazuki https://github.com/runceel/ReactiveProperty rx mvvm async rx-main reactive