diff --git a/src/SamplesApp/UITests.Shared/UITests.Shared.projitems b/src/SamplesApp/UITests.Shared/UITests.Shared.projitems
index d9bb1b4d2c44..8195fb07a00d 100644
--- a/src/SamplesApp/UITests.Shared/UITests.Shared.projitems
+++ b/src/SamplesApp/UITests.Shared/UITests.Shared.projitems
@@ -2378,6 +2378,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
@@ -7182,6 +7186,9 @@
PersonPicturePage.xaml
+
+ PersonPictureLateBindingPage.xaml
+
Pivot_CustomContent_Automated.xaml
diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/PersonPictureTests/PersonPictureLateBindingPage.xaml b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/PersonPictureTests/PersonPictureLateBindingPage.xaml
new file mode 100644
index 000000000000..f9cabbb1bb51
--- /dev/null
+++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/PersonPictureTests/PersonPictureLateBindingPage.xaml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/PersonPictureTests/PersonPictureLateBindingPage.xaml.cs b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/PersonPictureTests/PersonPictureLateBindingPage.xaml.cs
new file mode 100644
index 000000000000..cccf100a02d5
--- /dev/null
+++ b/src/SamplesApp/UITests.Shared/Windows_UI_Xaml_Controls/PersonPictureTests/PersonPictureLateBindingPage.xaml.cs
@@ -0,0 +1,40 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See LICENSE in the project root for license information.
+
+using System;
+using System.Collections.ObjectModel;
+using MUXControlsTestApp.Utilities;
+using Uno.UI.Samples.Controls;
+using Windows.ApplicationModel.Contacts;
+using System.Threading.Tasks;
+
+namespace MUXControlsTestApp
+{
+ [SampleControlInfo(
+ "MUX",
+ "PersonPictureLateBinding",
+ description: "Shows a PersonPicture control and a Textblock with a name. \n" +
+ "The PersonPicture control image is set after 1 second delay. \n" +
+ "The image should be displayed after the delay.",
+ isManualTest: true)]
+#pragma warning disable UXAML0002 // does not explicitly define the Microsoft.UI.Xaml.Controls.UserControl base type in code behind.
+ public sealed partial class PersonPictureLateBindingPage
+#pragma warning restore UXAML0002 // does not explicitly define the Microsoft.UI.Xaml.Controls.UserControl base type in code behind.
+ {
+ public string ImagePath { get; } = "ms-appx:///Assets/ingredient2.png";
+
+ public string LeName { get; } = "James Bondi";
+
+ public PersonPictureLateBindingPage()
+ {
+ this.InitializeComponent();
+ _ = SetImagePathWithDelay();
+ }
+
+ private async Task SetImagePathWithDelay()
+ {
+ await Task.Delay(1000);
+ DataContext = this;
+ }
+ }
+}
diff --git a/src/Uno.UI/Microsoft/UI/Xaml/Controls/PersonPicture/PersonPicture.cs b/src/Uno.UI/Microsoft/UI/Xaml/Controls/PersonPicture/PersonPicture.cs
index 0d7fd206d9d0..9fd98701201b 100644
--- a/src/Uno.UI/Microsoft/UI/Xaml/Controls/PersonPicture/PersonPicture.cs
+++ b/src/Uno.UI/Microsoft/UI/Xaml/Controls/PersonPicture/PersonPicture.cs
@@ -203,23 +203,33 @@ void UpdateIfReady()
var templateSettings = TemplateSettings;
templateSettings.ActualInitials = initials;
- if (imageSrc != null)
+
+ if (imageSrc is not null)
{
- var imageBrush = templateSettings.ActualImageBrush;
- if (imageBrush == null)
+ if (templateSettings.ActualImageBrush is ImageBrush imageBrush)
{
- imageBrush = new ImageBrush();
- imageBrush.Stretch = Stretch.UniformToFill;
- templateSettings.ActualImageBrush = imageBrush;
+ imageBrush.ImageSource = imageSrc;
+ }
+ else
+ {
+ templateSettings.ActualImageBrush = new ImageBrush()
+ {
+ ImageSource = imageSrc,
+ Stretch = Stretch.UniformToFill
+ };
}
-
- imageBrush.ImageSource = imageSrc;
}
else
{
templateSettings.ActualImageBrush = null;
}
+#if __IOS__
+ if (templateSettings.ActualImageBrush is ImageBrush brush)
+ {
+ brush.ImageOpened += RefreshPhoto;
+ }
+#endif
// If the control is converted to 'Group-mode', we'll clear individual-specific information.
// When IsGroup evaluates to false, we will restore state.
if (IsGroup)
@@ -228,7 +238,11 @@ void UpdateIfReady()
}
else
{
- if (imageSrc != null)
+ if (imageSrc is not null
+#if __IOS__
+ && imageSrc.IsOpened
+#endif
+ )
{
VisualStateManager.GoToState(this, "Photo", false);
}
@@ -245,6 +259,18 @@ void UpdateIfReady()
UpdateAutomationName();
}
+#if __IOS__
+ void RefreshPhoto(object sender, RoutedEventArgs e)
+ {
+ VisualStateManager.GoToState(this, "Photo", false);
+
+ if (TemplateSettings.ActualImageBrush is { } brush)
+ {
+ brush.ImageOpened -= RefreshPhoto;
+ }
+ }
+#endif
+
void UpdateBadge()
{
if (BadgeImageSource != null)
diff --git a/src/Uno.UI/UI/Xaml/Media/ImageSource.iOS.cs b/src/Uno.UI/UI/Xaml/Media/ImageSource.iOS.cs
index 31926877edaf..a94258af0251 100644
--- a/src/Uno.UI/UI/Xaml/Media/ImageSource.iOS.cs
+++ b/src/Uno.UI/UI/Xaml/Media/ImageSource.iOS.cs
@@ -55,6 +55,11 @@ public static NSUrlSession DefaultSession
static public implicit operator ImageSource(UIImage image) => new ImageSource(image);
+ ///
+ /// Indicates that this source has already been opened (So TryOpenSync will return true!)
+ ///
+ internal bool IsOpened => _imageData.HasData;
+
private static UIImage? OpenBundleFromString(string? bundle)
{
if (!bundle.IsNullOrWhiteSpace())