@@ -100,13 +100,14 @@ protected virtual async Task<bool> ValidateAsync()
100
100
if ( this . Validator == null )
101
101
throw new InvalidOperationException ( "Can't run validation if a validator hasn't been set" ) ;
102
102
103
- bool anyChanged = false ;
104
-
105
103
// We need the ConfigureAwait(false), as we might be called synchronously
106
104
// However this means that the stuff after the await can be run in parallel on multiple threads
107
105
// Therefore, we need the lock
108
106
// However, we can't raise PropertyChanged events from within the lock, otherwise deadlock
109
107
var results = await this . Validator . ValidateAllPropertiesAsync ( ) . ConfigureAwait ( false ) ;
108
+ if ( results == null )
109
+ results = new Dictionary < string , IEnumerable < string > > ( ) ;
110
+
110
111
var changedProperties = new List < string > ( ) ;
111
112
await this . propertyErrorsLock . WaitAsync ( ) . ConfigureAwait ( false ) ;
112
113
{
@@ -119,21 +120,19 @@ protected virtual async Task<bool> ValidateAsync()
119
120
continue ;
120
121
else
121
122
this . propertyErrors [ kvp . Key ] = newErrors ;
122
- anyChanged = true ;
123
123
changedProperties . Add ( kvp . Key ) ;
124
124
}
125
125
126
126
// If they haven't included a key in their validation results, that counts as no validation error
127
127
foreach ( var removedKey in this . propertyErrors . Keys . Except ( results . Keys ) . ToArray ( ) )
128
128
{
129
129
this . propertyErrors [ removedKey ] = null ;
130
- anyChanged = true ;
131
130
changedProperties . Add ( removedKey ) ;
132
131
}
133
132
}
134
133
this . propertyErrorsLock . Release ( ) ;
135
134
136
- if ( anyChanged )
135
+ if ( changedProperties . Count > 0 )
137
136
this . OnValidationStateChanged ( changedProperties ) ;
138
137
139
138
return ! this . HasErrors ;
@@ -182,16 +181,16 @@ protected bool ValidateProperty([CallerMemberName] string propertyName = null)
182
181
/// <summary>
183
182
/// Validate a single property asynchronously, by name.
184
183
/// </summary>
185
- /// <param name="propertyName">Property to validate. Validates all properties if null or String.Empty</param>
184
+ /// <param name="propertyName">Property to validate. Validates the entire model if null or <see cref=" String.Empty"/> </param>
186
185
/// <returns>True if the property validated successfully</returns>
187
186
/// <remarks>If you override this, you MUST fire ErrorsChanged and call OnValidationStateChanged() if appropriate</remarks>
188
187
protected virtual async Task < bool > ValidatePropertyAsync ( [ CallerMemberName ] string propertyName = null )
189
188
{
190
189
if ( this . Validator == null )
191
190
throw new InvalidOperationException ( "Can't run validation if a validator hasn't been set" ) ;
192
191
193
- if ( String . IsNullOrEmpty ( propertyName ) )
194
- return await this . ValidateAsync ( ) . ConfigureAwait ( false ) ;
192
+ if ( propertyName == null )
193
+ propertyName = String . Empty ;
195
194
196
195
// To allow synchronous calling of this method, we need to resume on the ThreadPool.
197
196
// Therefore, we might resume on any thread, hence the need for a lock
@@ -234,12 +233,12 @@ protected override async void OnPropertyChanged(string propertyName)
234
233
}
235
234
236
235
/// <summary>
237
- /// Called whenever the error state of any properties changes. Calls NotifyOfPropertyChange(() => this. HasErrors) by default
236
+ /// Called whenever the error state of any properties changes. Calls NotifyOfPropertyChange(" HasErrors" ) by default
238
237
/// </summary>
239
238
/// <param name="changedProperties">List of property names which have changed validation state</param>
240
239
protected virtual void OnValidationStateChanged ( IEnumerable < string > changedProperties )
241
240
{
242
- this . NotifyOfPropertyChange ( ( ) => this . HasErrors ) ;
241
+ this . NotifyOfPropertyChange ( " HasErrors" ) ;
243
242
foreach ( var property in changedProperties )
244
243
{
245
244
this . RaiseErrorsChanged ( property ) ;
@@ -264,14 +263,16 @@ protected virtual void RaiseErrorsChanged(string propertyName)
264
263
/// <returns>The validation errors for the property or entity.</returns>
265
264
public virtual IEnumerable GetErrors ( string propertyName )
266
265
{
267
- string [ ] errors = null ;
266
+ string [ ] errors ;
267
+
268
+ if ( propertyName == null )
269
+ propertyName = String . Empty ;
268
270
269
271
// We'll just have to wait synchronously for this. Oh well. The lock shouldn't be long.
270
272
// Everything that awaits uses ConfigureAwait(false), so we shouldn't deadlock if someone calls this on the main thread
271
273
this . propertyErrorsLock . Wait ( ) ;
272
274
{
273
- if ( this . propertyErrors . ContainsKey ( propertyName ) )
274
- errors = this . propertyErrors [ propertyName ] ;
275
+ this . propertyErrors . TryGetValue ( propertyName , out errors ) ;
275
276
}
276
277
this . propertyErrorsLock . Release ( ) ;
277
278
0 commit comments