From 54ddbf5e175c1cc0a096a04ba616e3612f9b04e7 Mon Sep 17 00:00:00 2001
From: Glenn <5834289+glennawatson@users.noreply.github.com>
Date: Wed, 12 May 2021 11:46:43 +1000
Subject: [PATCH 1/4] Create ReactiveRecord.cs
---
.../ReactiveObject/ReactiveRecord.cs | 111 ++++++++++++++++++
1 file changed, 111 insertions(+)
create mode 100644 src/ReactiveUI/ReactiveObject/ReactiveRecord.cs
diff --git a/src/ReactiveUI/ReactiveObject/ReactiveRecord.cs b/src/ReactiveUI/ReactiveObject/ReactiveRecord.cs
new file mode 100644
index 0000000000..8e3bd51502
--- /dev/null
+++ b/src/ReactiveUI/ReactiveObject/ReactiveRecord.cs
@@ -0,0 +1,111 @@
+// Copyright (c) 2021 .NET Foundation and Contributors. All rights reserved.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for full license information.
+
+using System;
+using System.ComponentModel;
+using System.Reactive;
+using System.Runtime.Serialization;
+using System.Threading;
+
+namespace ReactiveUI
+{
+ ///
+ /// ReactiveObject is the base object for ViewModel classes, and it
+ /// implements INotifyPropertyChanged. In addition, ReactiveObject provides
+ /// Changing and Changed Observables to monitor object changes.
+ ///
+ [DataContract]
+ public record ReactiveRecord : IReactiveNotifyPropertyChanged, IHandleObservableErrors, IReactiveObject
+ {
+ private readonly Lazy>> _changing;
+ private readonly Lazy>> _changed;
+ private readonly Lazy _propertyChangingEventsSubscribed;
+ private readonly Lazy _propertyChangedEventsSubscribed;
+ private readonly Lazy> _thrownExceptions;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ReactiveRecord()
+ {
+ _changing = new Lazy>>(() => ((IReactiveObject)this).GetChangingObservable(), LazyThreadSafetyMode.PublicationOnly);
+ _changed = new Lazy>>(() => ((IReactiveObject)this).GetChangedObservable(), LazyThreadSafetyMode.PublicationOnly);
+ _propertyChangingEventsSubscribed = new Lazy(
+ () =>
+ {
+ this.SubscribePropertyChangingEvents();
+ return Unit.Default;
+ },
+ LazyThreadSafetyMode.PublicationOnly);
+ _propertyChangedEventsSubscribed = new Lazy(
+ () =>
+ {
+ this.SubscribePropertyChangedEvents();
+ return Unit.Default;
+ },
+ LazyThreadSafetyMode.PublicationOnly);
+ _thrownExceptions = new Lazy>(this.GetThrownExceptionsObservable, LazyThreadSafetyMode.PublicationOnly);
+ }
+
+ ///
+ public event PropertyChangingEventHandler? PropertyChanging
+ {
+ add
+ {
+ _ = _propertyChangingEventsSubscribed.Value;
+ PropertyChangingHandler += value;
+ }
+ remove => PropertyChangingHandler -= value;
+ }
+
+ ///
+ public event PropertyChangedEventHandler? PropertyChanged
+ {
+ add
+ {
+ _ = _propertyChangedEventsSubscribed.Value;
+ PropertyChangedHandler += value;
+ }
+ remove => PropertyChangedHandler -= value;
+ }
+
+ private event PropertyChangingEventHandler? PropertyChangingHandler;
+
+ private event PropertyChangedEventHandler? PropertyChangedHandler;
+
+ ///
+ [IgnoreDataMember]
+ public IObservable> Changing => _changing.Value;
+
+ ///
+ [IgnoreDataMember]
+ public IObservable> Changed => _changed.Value;
+
+ ///
+ [IgnoreDataMember]
+ public IObservable ThrownExceptions => _thrownExceptions.Value;
+
+ ///
+ void IReactiveObject.RaisePropertyChanging(PropertyChangingEventArgs args) => PropertyChangingHandler?.Invoke(this, args);
+
+ ///
+ void IReactiveObject.RaisePropertyChanged(PropertyChangedEventArgs args) => PropertyChangedHandler?.Invoke(this, args);
+
+ ///
+ public IDisposable SuppressChangeNotifications() => IReactiveObjectExtensions.SuppressChangeNotifications(this);
+
+ ///
+ /// Determines if change notifications are enabled or not.
+ ///
+ /// A value indicating whether change notifications are enabled.
+ public bool AreChangeNotificationsEnabled() => IReactiveObjectExtensions.AreChangeNotificationsEnabled(this);
+
+ ///
+ /// Delays notifications until the return IDisposable is disposed.
+ ///
+ /// A disposable which when disposed will send delayed notifications.
+ public IDisposable DelayChangeNotifications() => IReactiveObjectExtensions.DelayChangeNotifications(this);
+ }
+}
From c0bf3f3399705ca56d1389918c7be72c144469b6 Mon Sep 17 00:00:00 2001
From: Glenn Watson
Date: Wed, 12 May 2021 11:48:15 +1000
Subject: [PATCH 2/4] Add IsExternalInit
---
src/ReactiveUI/IsExternalInit.cs | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
create mode 100644 src/ReactiveUI/IsExternalInit.cs
diff --git a/src/ReactiveUI/IsExternalInit.cs b/src/ReactiveUI/IsExternalInit.cs
new file mode 100644
index 0000000000..6124ad128c
--- /dev/null
+++ b/src/ReactiveUI/IsExternalInit.cs
@@ -0,0 +1,17 @@
+// Copyright (c) 2019-2021 ReactiveUI Association Incorporated. All rights reserved.
+// ReactiveUI Association Incorporated licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for full license information.
+
+using System.ComponentModel;
+
+namespace System.Runtime.CompilerServices
+{
+ ///
+ /// Reserved to be used by the compiler for tracking metadata.
+ /// This class should not be used by developers in source code.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ internal static class IsExternalInit
+ {
+ }
+}
\ No newline at end of file
From 26314c8ea98d1aa78509ab38cdc9bd2a8161622c Mon Sep 17 00:00:00 2001
From: Glenn Watson
Date: Wed, 12 May 2021 11:56:21 +1000
Subject: [PATCH 3/4] Add version file bump
---
.editorconfig | 32 +++++++++++++++++---------------
version.json | 2 +-
2 files changed, 18 insertions(+), 16 deletions(-)
diff --git a/.editorconfig b/.editorconfig
index ee3eb6c50b..de41f1de01 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -10,12 +10,11 @@ root = true
insert_final_newline = true
indent_style = space
indent_size = 4
-
-[project.json]
-indent_size = 2
+trim_trailing_whitespace = true
# C# files
[*.cs]
+
# New line preferences
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
@@ -42,11 +41,6 @@ dotnet_style_qualification_for_property = false:suggestion
dotnet_style_qualification_for_method = false:suggestion
dotnet_style_qualification_for_event = false:suggestion
-# only use var when it's obvious what the variable type is
-csharp_style_var_for_built_in_types = false:none
-csharp_style_var_when_type_is_apparent = true:suggestion
-csharp_style_var_elsewhere = true:suggestion
-
# Types: use keywords instead of BCL types, and permit var only when the type is clear
csharp_style_var_for_built_in_types = false:suggestion
csharp_style_var_when_type_is_apparent = false:none
@@ -62,14 +56,14 @@ dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.required_modifiers = const
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
-# static fields should have s_ prefix
+# static fields should have _ prefix
dotnet_naming_rule.static_fields_should_have_prefix.severity = suggestion
dotnet_naming_rule.static_fields_should_have_prefix.symbols = static_fields
dotnet_naming_rule.static_fields_should_have_prefix.style = static_prefix_style
dotnet_naming_symbols.static_fields.applicable_kinds = field
dotnet_naming_symbols.static_fields.required_modifiers = static
dotnet_naming_symbols.static_fields.applicable_accessibilities = private, internal, private_protected
-dotnet_naming_style.static_prefix_style.required_prefix = s_
+dotnet_naming_style.static_prefix_style.required_prefix = _
dotnet_naming_style.static_prefix_style.capitalization = camel_case
# internal and private fields should be _camelCase
@@ -84,7 +78,7 @@ dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
# Code style defaults
csharp_using_directive_placement = outside_namespace:suggestion
dotnet_sort_system_directives_first = true
-csharp_prefer_braces = true:silent
+csharp_prefer_braces = true:suggestion
csharp_preserve_single_line_blocks = true:none
csharp_preserve_single_line_statements = false:none
csharp_prefer_static_local_function = true:suggestion
@@ -105,8 +99,8 @@ dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggesti
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_auto_properties = true:suggestion
-dotnet_style_prefer_conditional_expression_over_assignment = true:silent
-dotnet_style_prefer_conditional_expression_over_return = true:silent
+dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion
+dotnet_style_prefer_conditional_expression_over_return = true:suggestion
csharp_prefer_simple_default_expression = true:suggestion
# Expression-bodied members
@@ -436,9 +430,12 @@ curly_bracket_next_line = true
indent_brace_style = Allman
# Xml project files
-[*.{csproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}]
+[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}]
indent_size = 2
+[*.{csproj,vbproj,proj,nativeproj,locproj}]
+charset = utf-8
+
# Xml build files
[*.builds]
indent_size = 2
@@ -451,8 +448,13 @@ indent_size = 2
[*.{props,targets,config,nuspec}]
indent_size = 2
+# YAML config files
+[*.{yml,yaml}]
+indent_size = 2
+
# Shell scripts
[*.sh]
end_of_line = lf
-[*.{cmd, bat}]
+
+[*.{cmd,bat}]
end_of_line = crlf
diff --git a/version.json b/version.json
index bb2e7b696b..df72b119dc 100644
--- a/version.json
+++ b/version.json
@@ -1,6 +1,6 @@
{
"$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
- "version": "13.2",
+ "version": "13.3",
"publicReleaseRefSpec": [
"^refs/heads/master$", // we release out of master
"^refs/heads/main$",
From 5e3623a529d495155a6f51a38638220342d35ddb Mon Sep 17 00:00:00 2001
From: Glenn Watson
Date: Wed, 12 May 2021 12:14:06 +1000
Subject: [PATCH 4/4] Fix tests
---
...provalTests.ReactiveUI.net472.approved.txt | 26 +++++++++++++++++++
...provalTests.ReactiveUI.net5.0.approved.txt | 26 +++++++++++++++++++
...ests.ReactiveUI.netcoreapp3.1.approved.txt | 26 +++++++++++++++++++
src/ReactiveUI/IsExternalInit.cs | 7 ++---
4 files changed, 82 insertions(+), 3 deletions(-)
diff --git a/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.net472.approved.txt b/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.net472.approved.txt
index d4a511ec6d..6d507f4cc2 100644
--- a/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.net472.approved.txt
+++ b/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.net472.approved.txt
@@ -631,6 +631,32 @@ namespace ReactiveUI
public ReactivePropertyChangingEventArgs(TSender sender, string? propertyName) { }
public TSender Sender { get; }
}
+ [System.Runtime.Serialization.DataContract]
+ public class ReactiveRecord : ReactiveUI.IHandleObservableErrors, ReactiveUI.IReactiveNotifyPropertyChanged, ReactiveUI.IReactiveObject, Splat.IEnableLogger, System.ComponentModel.INotifyPropertyChanged, System.ComponentModel.INotifyPropertyChanging, System.IEquatable
+ {
+ public ReactiveRecord() { }
+ protected ReactiveRecord(ReactiveUI.ReactiveRecord original) { }
+ [System.Runtime.Serialization.IgnoreDataMember]
+ public System.IObservable> Changed { get; }
+ [System.Runtime.Serialization.IgnoreDataMember]
+ public System.IObservable> Changing { get; }
+ protected virtual System.Type EqualityContract { get; }
+ [System.Runtime.Serialization.IgnoreDataMember]
+ public System.IObservable ThrownExceptions { get; }
+ public event System.ComponentModel.PropertyChangedEventHandler? PropertyChanged;
+ public event System.ComponentModel.PropertyChangingEventHandler? PropertyChanging;
+ public virtual ReactiveUI.ReactiveRecord $() { }
+ public bool AreChangeNotificationsEnabled() { }
+ public System.IDisposable DelayChangeNotifications() { }
+ public virtual bool Equals(ReactiveUI.ReactiveRecord? other) { }
+ public override bool Equals(object? obj) { }
+ public override int GetHashCode() { }
+ protected virtual bool PrintMembers(System.Text.StringBuilder builder) { }
+ public System.IDisposable SuppressChangeNotifications() { }
+ public override string ToString() { }
+ public static bool operator !=(ReactiveUI.ReactiveRecord? r1, ReactiveUI.ReactiveRecord? r2) { }
+ public static bool operator ==(ReactiveUI.ReactiveRecord? r1, ReactiveUI.ReactiveRecord? r2) { }
+ }
public static class Reflection
{
public static string ExpressionToPropertyNames(System.Linq.Expressions.Expression expression) { }
diff --git a/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.net5.0.approved.txt b/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.net5.0.approved.txt
index bd6ceac01d..57330ed16f 100644
--- a/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.net5.0.approved.txt
+++ b/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.net5.0.approved.txt
@@ -626,6 +626,32 @@ namespace ReactiveUI
public ReactivePropertyChangingEventArgs(TSender sender, string? propertyName) { }
public TSender Sender { get; }
}
+ [System.Runtime.Serialization.DataContract]
+ public class ReactiveRecord : ReactiveUI.IHandleObservableErrors, ReactiveUI.IReactiveNotifyPropertyChanged, ReactiveUI.IReactiveObject, Splat.IEnableLogger, System.ComponentModel.INotifyPropertyChanged, System.ComponentModel.INotifyPropertyChanging, System.IEquatable
+ {
+ public ReactiveRecord() { }
+ protected ReactiveRecord(ReactiveUI.ReactiveRecord original) { }
+ [System.Runtime.Serialization.IgnoreDataMember]
+ public System.IObservable> Changed { get; }
+ [System.Runtime.Serialization.IgnoreDataMember]
+ public System.IObservable> Changing { get; }
+ protected virtual System.Type EqualityContract { get; }
+ [System.Runtime.Serialization.IgnoreDataMember]
+ public System.IObservable ThrownExceptions { get; }
+ public event System.ComponentModel.PropertyChangedEventHandler? PropertyChanged;
+ public event System.ComponentModel.PropertyChangingEventHandler? PropertyChanging;
+ public virtual ReactiveUI.ReactiveRecord $() { }
+ public bool AreChangeNotificationsEnabled() { }
+ public System.IDisposable DelayChangeNotifications() { }
+ public virtual bool Equals(ReactiveUI.ReactiveRecord? other) { }
+ public override bool Equals(object? obj) { }
+ public override int GetHashCode() { }
+ protected virtual bool PrintMembers(System.Text.StringBuilder builder) { }
+ public System.IDisposable SuppressChangeNotifications() { }
+ public override string ToString() { }
+ public static bool operator !=(ReactiveUI.ReactiveRecord? r1, ReactiveUI.ReactiveRecord? r2) { }
+ public static bool operator ==(ReactiveUI.ReactiveRecord? r1, ReactiveUI.ReactiveRecord? r2) { }
+ }
public static class Reflection
{
public static string ExpressionToPropertyNames(System.Linq.Expressions.Expression expression) { }
diff --git a/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.netcoreapp3.1.approved.txt b/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.netcoreapp3.1.approved.txt
index 20ce1ee2ca..7b2e43d2b9 100644
--- a/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.netcoreapp3.1.approved.txt
+++ b/src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.netcoreapp3.1.approved.txt
@@ -624,6 +624,32 @@ namespace ReactiveUI
public ReactivePropertyChangingEventArgs(TSender sender, string? propertyName) { }
public TSender Sender { get; }
}
+ [System.Runtime.Serialization.DataContract]
+ public class ReactiveRecord : ReactiveUI.IHandleObservableErrors, ReactiveUI.IReactiveNotifyPropertyChanged, ReactiveUI.IReactiveObject, Splat.IEnableLogger, System.ComponentModel.INotifyPropertyChanged, System.ComponentModel.INotifyPropertyChanging, System.IEquatable
+ {
+ public ReactiveRecord() { }
+ protected ReactiveRecord(ReactiveUI.ReactiveRecord original) { }
+ [System.Runtime.Serialization.IgnoreDataMember]
+ public System.IObservable> Changed { get; }
+ [System.Runtime.Serialization.IgnoreDataMember]
+ public System.IObservable> Changing { get; }
+ protected virtual System.Type EqualityContract { get; }
+ [System.Runtime.Serialization.IgnoreDataMember]
+ public System.IObservable ThrownExceptions { get; }
+ public event System.ComponentModel.PropertyChangedEventHandler? PropertyChanged;
+ public event System.ComponentModel.PropertyChangingEventHandler? PropertyChanging;
+ public virtual ReactiveUI.ReactiveRecord $() { }
+ public bool AreChangeNotificationsEnabled() { }
+ public System.IDisposable DelayChangeNotifications() { }
+ public virtual bool Equals(ReactiveUI.ReactiveRecord? other) { }
+ public override bool Equals(object? obj) { }
+ public override int GetHashCode() { }
+ protected virtual bool PrintMembers(System.Text.StringBuilder builder) { }
+ public System.IDisposable SuppressChangeNotifications() { }
+ public override string ToString() { }
+ public static bool operator !=(ReactiveUI.ReactiveRecord? r1, ReactiveUI.ReactiveRecord? r2) { }
+ public static bool operator ==(ReactiveUI.ReactiveRecord? r1, ReactiveUI.ReactiveRecord? r2) { }
+ }
public static class Reflection
{
public static string ExpressionToPropertyNames(System.Linq.Expressions.Expression expression) { }
diff --git a/src/ReactiveUI/IsExternalInit.cs b/src/ReactiveUI/IsExternalInit.cs
index 6124ad128c..2255ac3117 100644
--- a/src/ReactiveUI/IsExternalInit.cs
+++ b/src/ReactiveUI/IsExternalInit.cs
@@ -1,5 +1,6 @@
-// Copyright (c) 2019-2021 ReactiveUI Association Incorporated. All rights reserved.
-// ReactiveUI Association Incorporated licenses this file to you under the MIT license.
+// Copyright (c) 2021 .NET Foundation and Contributors. All rights reserved.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.
using System.ComponentModel;
@@ -14,4 +15,4 @@ namespace System.Runtime.CompilerServices
internal static class IsExternalInit
{
}
-}
\ No newline at end of file
+}