@@ -60,39 +60,24 @@ protected override void RemoveContainer()
6060 /// <inheritdoc/>
6161 public override Graphics . Size GetDesiredSize ( double widthConstraint , double heightConstraint )
6262 {
63- // AspectFit + non-Fill alignment: cap Max* to intrinsic bitmap so alignment (Center/Start/End) works.
64- // Only set once when Max* still Infinity and we have decoded size; else mirror VirtualView Maximum*.
65- // Without this the Image measures to available space and alignment appears ignored.
63+ // Compute a possible size without mutating platform properties during measure.
64+ var possibleSize = base . GetDesiredSize ( widthConstraint , heightConstraint ) ;
65+
66+ // For AspectFit + non-Fill alignment, don't exceed intrinsic bitmap size so alignment works.
6667 if ( VirtualView . Aspect == Aspect . AspectFit
6768 && VirtualView . HorizontalLayoutAlignment != Primitives . LayoutAlignment . Fill
6869 && VirtualView . VerticalLayoutAlignment != Primitives . LayoutAlignment . Fill )
6970 {
70- // First (and only) chance to lock to intrinsic size.
71- if ( PlatformView . MaxWidth == double . PositiveInfinity
72- && PlatformView . MaxHeight == double . PositiveInfinity )
71+ var imageSize = GetImageSize ( ) ;
72+ if ( imageSize . Width > 0 && imageSize . Height > 0 )
7373 {
74- // Clamp to decoded pixel size if available.
75- var imageSize = GetImageSize ( ) ;
76-
77- if ( imageSize . Width != 0 && imageSize . Height != 0 )
78- {
79- PlatformView . MaxWidth = imageSize . Width ;
80- PlatformView . MaxHeight = imageSize . Height ;
81- }
82- }
83- }
84- else
85- {
86- // Other scenarios: honor user Maximum* values.
87- if ( VirtualView . MaximumHeight != PlatformView . MaxHeight
88- || VirtualView . MaximumWidth != PlatformView . MaxWidth )
89- {
90- PlatformView . MaxWidth = VirtualView . MaximumWidth ;
91- PlatformView . MaxHeight = VirtualView . MaximumHeight ;
74+ return new Graphics . Size (
75+ Math . Min ( possibleSize . Width , imageSize . Width ) ,
76+ Math . Min ( possibleSize . Height , imageSize . Height ) ) ;
9277 }
9378 }
9479
95- return base . GetDesiredSize ( widthConstraint , heightConstraint ) ;
80+ return possibleSize ;
9681 }
9782
9883 /// <summary>
@@ -152,6 +137,9 @@ public static void MapAspect(IImageHandler handler, IImage image)
152137 {
153138 handler . UpdateValue ( nameof ( IViewHandler . ContainerView ) ) ;
154139 handler . PlatformView ? . UpdateAspect ( image ) ;
140+ // Aspect changes may affect whether we cap to intrinsic size
141+ if ( handler is ImageHandler ih )
142+ ih . UpdatePlatformMaxConstraints ( ) ;
155143 }
156144
157145 /// <summary>
@@ -175,15 +163,57 @@ public static void MapSource(IImageHandler handler, IImage image) =>
175163 /// </summary>
176164 /// <param name="handler">The associated handler.</param>
177165 /// <param name="image">The associated <see cref="Image"/> instance.</param>
178- public static Task MapSourceAsync ( IImageHandler handler , IImage image ) =>
179- handler . SourceLoader . UpdateImageSourceAsync ( ) ;
166+ public static Task MapSourceAsync ( IImageHandler handler , IImage image )
167+ {
168+ // Reset platform caps so we don't keep stale values between sources
169+ if ( handler is ImageHandler ih && ih . PlatformView is not null )
170+ {
171+ ih . PlatformView . MaxWidth = double . PositiveInfinity ;
172+ ih . PlatformView . MaxHeight = double . PositiveInfinity ;
173+ }
174+
175+ return handler . SourceLoader . UpdateImageSourceAsync ( ) ;
176+ }
180177
181178 void OnImageOpened ( object sender , RoutedEventArgs e )
182179 {
183180 // Because this resolves from a task we should validate that the
184181 // handler hasn't been disconnected
185182 if ( this . IsConnected ( ) )
183+ {
186184 UpdateValue ( nameof ( IImage . IsAnimationPlaying ) ) ;
185+ // Apply platform constraints when the decoded size is available
186+ UpdatePlatformMaxConstraints ( ) ;
187+ }
188+ }
189+
190+ /// <summary>
191+ /// Updates platform MaxWidth/MaxHeight based on current aspect/alignment and decoded image size.
192+ /// Avoids doing this during GetDesiredSize to prevent side effects across layout passes.
193+ /// </summary>
194+ private void UpdatePlatformMaxConstraints ( )
195+ {
196+ if ( PlatformView is null || VirtualView is null )
197+ return ;
198+
199+ bool isAspectFitNonFill = VirtualView . Aspect == Aspect . AspectFit
200+ && VirtualView . HorizontalLayoutAlignment != Primitives . LayoutAlignment . Fill
201+ && VirtualView . VerticalLayoutAlignment != Primitives . LayoutAlignment . Fill ;
202+
203+ if ( isAspectFitNonFill )
204+ {
205+ var sz = GetImageSize ( ) ;
206+ if ( sz . Width > 0 && sz . Height > 0 )
207+ {
208+ PlatformView . MaxWidth = sz . Width ;
209+ PlatformView . MaxHeight = sz . Height ;
210+ return ;
211+ }
212+ }
213+
214+ // Otherwise mirror the view's declared maximums
215+ PlatformView . MaxWidth = VirtualView . MaximumWidth ;
216+ PlatformView . MaxHeight = VirtualView . MaximumHeight ;
187217 }
188218
189219 private Graphics . Size GetImageSize ( )
@@ -195,7 +225,7 @@ private Graphics.Size GetImageSize()
195225 {
196226 return new Graphics . Size ( bitmap . PixelWidth , bitmap . PixelHeight ) ;
197227 }
198- // If not available, set to zero
228+ // If not available, return zero
199229 }
200230 return Graphics . Size . Zero ;
201231 }
0 commit comments