@@ -37,6 +37,167 @@ public abstract class ObservableValidator : ObservableObject, INotifyDataErrorIn
3737 /// <inheritdoc/>
3838 public bool HasErrors => this . totalErrors > 0 ;
3939
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+
40201 /// <inheritdoc/>
41202 [ Pure ]
42203 public IEnumerable GetErrors ( string ? propertyName )
@@ -77,9 +238,8 @@ private IEnumerable GetAllErrors()
77238 /// </summary>
78239 /// <param name="value">The value to test for the specified property.</param>
79240 /// <param name="propertyName">The name of the property to validate.</param>
80- /// <returns>Whether or not the validation was successful.</returns>
81241 /// <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 )
83243 {
84244 if ( propertyName is null )
85245 {
@@ -138,8 +298,6 @@ protected bool ValidateProperty(object? value, [CallerMemberName] string? proper
138298 {
139299 ErrorsChanged ? . Invoke ( this , new DataErrorsChangedEventArgs ( propertyName ) ) ;
140300 }
141-
142- return isValid ;
143301 }
144302
145303 /// <summary>
0 commit comments