@@ -37,6 +37,167 @@ public abstract class ObservableValidator : ObservableObject, INotifyDataErrorIn
37
37
/// <inheritdoc/>
38
38
public bool HasErrors => this . totalErrors > 0 ;
39
39
40
+ /// <summary>
41
+ /// Compares the current and new values for a given property. If the value has changed,
42
+ /// raises the <see cref="ObservableObject.PropertyChanging"/> event, updates the property with
43
+ /// the new value, then raises the <see cref="ObservableObject.PropertyChanged"/> event.
44
+ /// </summary>
45
+ /// <typeparam name="T">The type of the property that changed.</typeparam>
46
+ /// <param name="field">The field storing the property's value.</param>
47
+ /// <param name="newValue">The property's value after the change occurred.</param>
48
+ /// <param name="validate">If <see langword="true"/>, <paramref name="newValue"/> will also be validated.</param>
49
+ /// <param name="propertyName">(optional) The name of the property that changed.</param>
50
+ /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
51
+ /// <remarks>
52
+ /// This method is just like <see cref="ObservableObject.SetProperty{T}(ref T,T,string)"/>, just with the addition
53
+ /// of the <paramref name="validate"/> parameter. If that is set to <see langword="true"/>, the new value will be
54
+ /// validated and <see cref="ErrorsChanged"/> will be raised if needed. Following the behavior of the base method,
55
+ /// the <see cref="ObservableObject.PropertyChanging"/> and <see cref="ObservableObject.PropertyChanged"/> events
56
+ /// are not raised if the current and new value for the target property are the same.
57
+ /// </remarks>
58
+ protected bool SetProperty < T > ( ref T field , T newValue , bool validate , [ CallerMemberName ] string ? propertyName = null )
59
+ {
60
+ if ( validate )
61
+ {
62
+ ValidateProperty ( newValue , propertyName ) ;
63
+ }
64
+
65
+ return SetProperty ( ref field , newValue , propertyName ) ;
66
+ }
67
+
68
+ /// <summary>
69
+ /// Compares the current and new values for a given property. If the value has changed,
70
+ /// raises the <see cref="ObservableObject.PropertyChanging"/> event, updates the property with
71
+ /// the new value, then raises the <see cref="ObservableObject.PropertyChanged"/> event.
72
+ /// See additional notes about this overload in <see cref="SetProperty{T}(ref T,T,bool,string)"/>.
73
+ /// </summary>
74
+ /// <typeparam name="T">The type of the property that changed.</typeparam>
75
+ /// <param name="field">The field storing the property's value.</param>
76
+ /// <param name="newValue">The property's value after the change occurred.</param>
77
+ /// <param name="comparer">The <see cref="IEqualityComparer{T}"/> instance to use to compare the input values.</param>
78
+ /// <param name="validate">If <see langword="true"/>, <paramref name="newValue"/> will also be validated.</param>
79
+ /// <param name="propertyName">(optional) The name of the property that changed.</param>
80
+ /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
81
+ protected bool SetProperty < T > ( ref T field , T newValue , IEqualityComparer < T > comparer , bool validate , [ CallerMemberName ] string ? propertyName = null )
82
+ {
83
+ if ( validate )
84
+ {
85
+ ValidateProperty ( newValue , propertyName ) ;
86
+ }
87
+
88
+ return SetProperty ( ref field , newValue , comparer , propertyName ) ;
89
+ }
90
+
91
+ /// <summary>
92
+ /// Compares the current and new values for a given property. If the value has changed,
93
+ /// raises the <see cref="ObservableObject.PropertyChanging"/> event, updates the property with
94
+ /// the new value, then raises the <see cref="ObservableObject.PropertyChanged"/> event. Similarly to
95
+ /// the <see cref="ObservableObject.SetProperty{T}(T,T,Action{T},string)"/> method, this overload should only be
96
+ /// used when <see cref="ObservableObject.SetProperty{T}(ref T,T,string)"/> can't be used directly.
97
+ /// </summary>
98
+ /// <typeparam name="T">The type of the property that changed.</typeparam>
99
+ /// <param name="oldValue">The current property value.</param>
100
+ /// <param name="newValue">The property's value after the change occurred.</param>
101
+ /// <param name="callback">A callback to invoke to update the property value.</param>
102
+ /// <param name="validate">If <see langword="true"/>, <paramref name="newValue"/> will also be validated.</param>
103
+ /// <param name="propertyName">(optional) The name of the property that changed.</param>
104
+ /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
105
+ /// <remarks>
106
+ /// This method is just like <see cref="ObservableObject.SetProperty{T}(T,T,Action{T},string)"/>, just with the addition
107
+ /// of the <paramref name="validate"/> parameter. As such, following the behavior of the base method,
108
+ /// the <see cref="ObservableObject.PropertyChanging"/> and <see cref="ObservableObject.PropertyChanged"/> events
109
+ /// are not raised if the current and new value for the target property are the same.
110
+ /// </remarks>
111
+ protected bool SetProperty < T > ( T oldValue , T newValue , Action < T > callback , bool validate , [ CallerMemberName ] string ? propertyName = null )
112
+ {
113
+ if ( validate )
114
+ {
115
+ ValidateProperty ( newValue , propertyName ) ;
116
+ }
117
+
118
+ return SetProperty ( oldValue , newValue , callback , propertyName ) ;
119
+ }
120
+
121
+ /// <summary>
122
+ /// Compares the current and new values for a given property. If the value has changed,
123
+ /// raises the <see cref="ObservableObject.PropertyChanging"/> event, updates the property with
124
+ /// the new value, then raises the <see cref="ObservableObject.PropertyChanged"/> event.
125
+ /// See additional notes about this overload in <see cref="SetProperty{T}(T,T,Action{T},bool,string)"/>.
126
+ /// </summary>
127
+ /// <typeparam name="T">The type of the property that changed.</typeparam>
128
+ /// <param name="oldValue">The current property value.</param>
129
+ /// <param name="newValue">The property's value after the change occurred.</param>
130
+ /// <param name="comparer">The <see cref="IEqualityComparer{T}"/> instance to use to compare the input values.</param>
131
+ /// <param name="callback">A callback to invoke to update the property value.</param>
132
+ /// <param name="validate">If <see langword="true"/>, <paramref name="newValue"/> will also be validated.</param>
133
+ /// <param name="propertyName">(optional) The name of the property that changed.</param>
134
+ /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
135
+ protected bool SetProperty < T > ( T oldValue , T newValue , IEqualityComparer < T > comparer , Action < T > callback , bool validate , [ CallerMemberName ] string ? propertyName = null )
136
+ {
137
+ if ( validate )
138
+ {
139
+ ValidateProperty ( newValue , propertyName ) ;
140
+ }
141
+
142
+ return SetProperty ( oldValue , newValue , comparer , callback , propertyName ) ;
143
+ }
144
+
145
+ /// <summary>
146
+ /// Compares the current and new values for a given nested property. If the value has changed,
147
+ /// raises the <see cref="ObservableObject.PropertyChanging"/> event, updates the property and then raises the
148
+ /// <see cref="ObservableObject.PropertyChanged"/> event. The behavior mirrors that of
149
+ /// <see cref="ObservableObject.SetProperty{TModel,T}(T,T,TModel,Action{TModel,T},string)"/>, with the difference being that this
150
+ /// method is used to relay properties from a wrapped model in the current instance. For more info, see the docs for
151
+ /// <see cref="ObservableObject.SetProperty{TModel,T}(T,T,TModel,Action{TModel,T},string)"/>.
152
+ /// </summary>
153
+ /// <typeparam name="TModel">The type of model whose property (or field) to set.</typeparam>
154
+ /// <typeparam name="T">The type of property (or field) to set.</typeparam>
155
+ /// <param name="oldValue">The current property value.</param>
156
+ /// <param name="newValue">The property's value after the change occurred.</param>
157
+ /// <param name="model">The model </param>
158
+ /// <param name="callback">The callback to invoke to set the target property value, if a change has occurred.</param>
159
+ /// <param name="validate">If <see langword="true"/>, <paramref name="newValue"/> will also be validated.</param>
160
+ /// <param name="propertyName">(optional) The name of the property that changed.</param>
161
+ /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
162
+ protected bool SetProperty < TModel , T > ( T oldValue , T newValue , TModel model , Action < TModel , T > callback , bool validate , [ CallerMemberName ] string ? propertyName = null )
163
+ {
164
+ if ( validate )
165
+ {
166
+ ValidateProperty ( newValue , propertyName ) ;
167
+ }
168
+
169
+ return SetProperty ( oldValue , newValue , model , callback , propertyName ) ;
170
+ }
171
+
172
+ /// <summary>
173
+ /// Compares the current and new values for a given nested property. If the value has changed,
174
+ /// raises the <see cref="ObservableObject.PropertyChanging"/> event, updates the property and then raises the
175
+ /// <see cref="ObservableObject.PropertyChanged"/> event. The behavior mirrors that of
176
+ /// <see cref="ObservableObject.SetProperty{TModel,T}(T,T,IEqualityComparer{T},TModel,Action{TModel,T},string)"/>,
177
+ /// with the difference being that this method is used to relay properties from a wrapped model in the
178
+ /// current instance. For more info, see the docs for
179
+ /// <see cref="ObservableObject.SetProperty{TModel,T}(T,T,IEqualityComparer{T},TModel,Action{TModel,T},string)"/>.
180
+ /// </summary>
181
+ /// <typeparam name="TModel">The type of model whose property (or field) to set.</typeparam>
182
+ /// <typeparam name="T">The type of property (or field) to set.</typeparam>
183
+ /// <param name="oldValue">The current property value.</param>
184
+ /// <param name="newValue">The property's value after the change occurred.</param>
185
+ /// <param name="comparer">The <see cref="IEqualityComparer{T}"/> instance to use to compare the input values.</param>
186
+ /// <param name="model">The model </param>
187
+ /// <param name="callback">The callback to invoke to set the target property value, if a change has occurred.</param>
188
+ /// <param name="validate">If <see langword="true"/>, <paramref name="newValue"/> will also be validated.</param>
189
+ /// <param name="propertyName">(optional) The name of the property that changed.</param>
190
+ /// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
191
+ protected bool SetProperty < TModel , T > ( T oldValue , T newValue , IEqualityComparer < T > comparer , TModel model , Action < TModel , T > callback , bool validate , [ CallerMemberName ] string ? propertyName = null )
192
+ {
193
+ if ( validate )
194
+ {
195
+ ValidateProperty ( newValue , propertyName ) ;
196
+ }
197
+
198
+ return SetProperty ( oldValue , newValue , comparer , model , callback , propertyName ) ;
199
+ }
200
+
40
201
/// <inheritdoc/>
41
202
[ Pure ]
42
203
public IEnumerable GetErrors ( string ? propertyName )
@@ -77,9 +238,8 @@ private IEnumerable GetAllErrors()
77
238
/// </summary>
78
239
/// <param name="value">The value to test for the specified property.</param>
79
240
/// <param name="propertyName">The name of the property to validate.</param>
80
- /// <returns>Whether or not the validation was successful.</returns>
81
241
/// <exception cref="ArgumentNullException">Thrown when <paramref name="propertyName"/> is <see langword="null"/>.</exception>
82
- protected bool ValidateProperty ( object ? value , [ CallerMemberName ] string ? propertyName = null )
242
+ private void ValidateProperty ( object ? value , string ? propertyName )
83
243
{
84
244
if ( propertyName is null )
85
245
{
@@ -138,8 +298,6 @@ protected bool ValidateProperty(object? value, [CallerMemberName] string? proper
138
298
{
139
299
ErrorsChanged ? . Invoke ( this , new DataErrorsChangedEventArgs ( propertyName ) ) ;
140
300
}
141
-
142
- return isValid ;
143
301
}
144
302
145
303
/// <summary>
0 commit comments