@@ -12,7 +12,6 @@ namespace Devolutions.AvaloniaControls.Helpers;
1212using Avalonia . Data ;
1313using Avalonia . Data . Converters ;
1414using Avalonia . LogicalTree ;
15- using Avalonia . Markup . Xaml . MarkupExtensions ;
1615
1716[ RequiresUnreferencedCode ( "BindingEvaluator require preserved types" ) ]
1817[ RequiresDynamicCode ( "BindingEvaluator require preserved types" ) ]
@@ -223,24 +222,26 @@ private static Expression BuildNullSafePropertyAccess(Expression root, string pa
223222
224223 private static Expression BuildNullSafePropertyAccess ( Expression receiver , string [ ] propertyNames , int index )
225224 {
226- if ( index == propertyNames . Length )
225+ while ( true )
227226 {
228- return Expression . Convert ( receiver , typeof ( object ) ) ;
229- }
227+ if ( index == propertyNames . Length )
228+ {
229+ return Expression . Convert ( receiver , typeof ( object ) ) ;
230+ }
230231
231- if ( receiver . Type . IsValueType && Nullable . GetUnderlyingType ( receiver . Type ) is null )
232- {
233- return BuildNullSafePropertyAccess ( Expression . PropertyOrField ( receiver , propertyNames [ index ] ) , propertyNames , index + 1 ) ;
234- }
232+ if ( receiver . Type . IsValueType && Nullable . GetUnderlyingType ( receiver . Type ) is null )
233+ {
234+ receiver = Expression . PropertyOrField ( receiver , propertyNames [ index ++ ] ) ;
235+ continue ;
236+ }
235237
236- ParameterExpression receiverValue = Expression . Variable ( receiver . Type , $ "segment{ index } ") ;
237- return Expression . Block (
238- [ receiverValue ] ,
239- Expression . Assign ( receiverValue , receiver ) ,
240- Expression . Condition (
241- Expression . Equal ( receiverValue , Expression . Constant ( null , receiver . Type ) ) ,
242- Expression . Constant ( AvaloniaProperty . UnsetValue , typeof ( object ) ) ,
243- BuildNullSafePropertyAccess ( Expression . PropertyOrField ( receiverValue , propertyNames [ index ] ) , propertyNames , index + 1 ) ) ) ;
238+ ParameterExpression receiverValue = Expression . Variable ( receiver . Type , $ "segment{ index } ") ;
239+ return Expression . Block ( [ receiverValue ] ,
240+ Expression . Assign ( receiverValue , receiver ) ,
241+ Expression . Condition ( Expression . Equal ( receiverValue , Expression . Constant ( null , receiver . Type ) ) ,
242+ Expression . Constant ( AvaloniaProperty . UnsetValue , typeof ( object ) ) ,
243+ BuildNullSafePropertyAccess ( Expression . PropertyOrField ( receiverValue , propertyNames [ index ] ) , propertyNames , index + 1 ) ) ) ;
244+ }
244245 }
245246
246247 private static StyledElement ? FindLogicalAncestorOfType ( StyledElement start , Type ancestorType )
@@ -424,9 +425,7 @@ private bool TryBuildIntermediateRawGetter(BindingBase binding, [NotNullWhen(tru
424425 object ? value = propertyGetter ( row ) ;
425426 if ( ReferenceEquals ( value , AvaloniaProperty . UnsetValue ) )
426427 {
427- return ReferenceEquals ( fallbackValue , AvaloniaProperty . UnsetValue )
428- ? AvaloniaProperty . UnsetValue
429- : fallbackValue ;
428+ return fallbackValue ;
430429 }
431430
432431 if ( value is null && ! ReferenceEquals ( targetNullValue , AvaloniaProperty . UnsetValue ) )
@@ -438,9 +437,7 @@ private bool TryBuildIntermediateRawGetter(BindingBase binding, [NotNullWhen(tru
438437 }
439438 catch
440439 {
441- return ReferenceEquals ( fallbackValue , AvaloniaProperty . UnsetValue )
442- ? AvaloniaProperty . UnsetValue
443- : fallbackValue ;
440+ return fallbackValue ;
444441 }
445442 } ;
446443 }
@@ -453,20 +450,22 @@ private static bool TryGetIntermediateRawParts(
453450 {
454451 switch ( binding )
455452 {
456- case Binding { Path : { Length : > 0 } bindingPath } b when b . Converter is null
457- && b . StringFormat is null
458- && b . Source == AvaloniaProperty . UnsetValue
459- && string . IsNullOrEmpty ( b . ElementName )
460- && b . RelativeSource is null :
453+ case Binding { Path : { Length : > 0 } bindingPath } b
454+ when b . Converter is null
455+ && b . StringFormat is null
456+ && b . Source == AvaloniaProperty . UnsetValue
457+ && string . IsNullOrEmpty ( b . ElementName )
458+ && b . RelativeSource is null :
461459 path = bindingPath ;
462460 fallbackValue = b . FallbackValue ;
463461 targetNullValue = b . TargetNullValue ;
464462 break ;
465463
466464 // Note: `CompiledBindingExtension` IS a `CompiledBinding`.
467- case CompiledBinding c when c . Converter is null
468- && c . StringFormat is null
469- && c . Source == AvaloniaProperty . UnsetValue :
465+ case CompiledBinding c
466+ when c . Converter is null
467+ && c . StringFormat is null
468+ && c . Source == AvaloniaProperty . UnsetValue :
470469 path = c . Path ? . ToString ( ) ;
471470 fallbackValue = c . FallbackValue ;
472471 targetNullValue = c . TargetNullValue ;
@@ -479,10 +478,7 @@ private static bool TryGetIntermediateRawParts(
479478 return false ;
480479 }
481480
482- return ( ! ReferenceEquals ( fallbackValue , AvaloniaProperty . UnsetValue )
483- || ! ReferenceEquals ( targetNullValue , AvaloniaProperty . UnsetValue ) )
484- && ! string . IsNullOrEmpty ( path )
485- && IsSimpleDotPath ( path ) ;
481+ return ! string . IsNullOrEmpty ( path ) && IsSimpleDotPath ( path ) ;
486482 }
487483
488484 private static bool TryBuildIntermediateExpression < TDataContext > ( BindingBase binding , [ NotNullWhen ( true ) ] out Expression < Func < TDataContext , string > > ? expression )
0 commit comments