Open mikernet opened 3 years ago
Thanks for the report. Can you create a repro sample of the problem ? The code seems simple enough, but it'll be easier to make sure this is actually related to BitmapImage.
Give me a sec with this, I'm trying a few things out to trace the issue - the above sample code actually works, the file path is just case sensitive on iOS (which makes sense) and I didn't have the casing correct so the dumbed-down version above doesn't actually reproduce the issue. Our code works fine on WASM and UWP but iOS refuses to show the image for some odd reason. I'll follow up on this and edit the problem once I figure out more.
Okay, so setting UriSource
actually works fine but SetSource()
/ SetSourceAsync()
does not:
public static BitmapImage GetBitmap(ImageType imageType, long? id)
{
var image = new BitmapImage();
LoadImage();
return image;
async void LoadImage()
{
try {
await Task.Delay(100);
string fname = @"Assets/Logo.png";
StorageFolder InstallationFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
var imageStream = new MemoryStream();
using (var fs = File.OpenRead(Path.Combine(InstallationFolder.Path, fname))) {
fs.CopyTo(imageStream);
}
// option 1 (works):
image.UriSource = new Uri("ms-appx:///Assets/Logo.png");
// option 2 (doesn't work):
image.SetSource(imageStream.AsRandomAccessStream());
}
catch (Exception ex) {
Console.WriteLine(ex.Message);
}
Console.WriteLine("Image set");
}
}
If I leave all the code untouched except for picking either option 1 or option 2, it works in the former case but fails to show the image in the latter case on iOS. It does not hit the exception catch block. Both options work fine on WASM and UWP.
I'll throw a repro project up on github if you like.
I changed the code in my post above a bit - if I comment out the await Task.Delay
line then it works, so it's definitely an issue with calling SetSource()
after a delay.
Here's the minimal repro you can just paste into any test project - just change the file name to an image in the assets folder and set an image's source to the method's return value:
public static BitmapImage GetBitmap()
{
var image = new BitmapImage();
LoadImage();
return image;
async void LoadImage()
{
//await Task.Delay(100);
string fname = @"Assets/Logo.png";
StorageFolder InstallationFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
using (var fs = File.OpenRead(Path.Combine(InstallationFolder.Path, fname))) {
image.SetSource(fs.AsRandomAccessStream());
}
}
}
It works until you uncomment the await
line.
It looks like the image is opened only once per consumer. We should multi-target the pattern used for wasm and skia (i.e. the Subscribe
), and enable the ForceLoad
which invokes the InvalidateSource()
method which will updates all listeners (i.e. images and brushes).
Could you point me towards the area in source where these changes need to be made?
Unfortunately, there seem to be some layout regressions in 3.6.0-dev.latest that prevent me from being able to use it in iOS so I'm probably going to have to backport the changes to 3.5.1 or figure out what is going on there. I'll try to PR the fix to this image issue since working around this issue is going to be a royal PITA for how we have things setup across the application.
i created a button to set a component Image source like that:
imgLogo.Source = GetBitmap();
(using SetSourceAsync instead SetSource)
What i could see, there`s a intermitent behavior. When you click a few times, eventually you get a blank image. Not sure if this is only in debugging. Still verifying.
@dr1rrb Hi! I tried to reproduce your code. However, SetSource() wont work in any platform, not only iOS. Using a Static GetImage method and XAML binding didn`t worked as well.
Using SetSourceAsync() works fine, besides having the intermitence i mentioned las comment. Do you mind to confirm your code please? Maybe it has been solved for SetSourceAsync( ) but not yet for SetSource( ).
Hi @iury-kc, to which code do you refer? The repro from @mikernet ?
I don't remember having investigated nor tested this issue, the only thing is that if we are about to significantly change ImageSource
, I want to make sure we are following the new pattern of the Subscribe
. A long time ago when we started to dev uno we took a wrong approach to switch on each known kind of ImageSource
directly in Image
and ImageBrush
(to mention only those), which drives us to copy the same code again and again on each platform and having some weird specific issues like this one.
@dr1rrb Oops. Tagged the wrong member. i mean @mikernet
Hi!
Moving the delegate internal event EventHandler Invalidated;
from WritableBitmap to ImageSource and calling the OnInvalidated when BitmapImage has changed ( URI, stream ....) solved the problem on iOS. That made the code cleaner and easier to understand.
Test is done.
The pattern used by SKIA files still doesn`t work. Still investigating what is the problem there. As it will take a time to solve for all platforms, should I continue investigation or should I pause?
Did a PR that should close this issue. Also, we have Android similar behavior been solved on issue: https://github.com/unoplatform/uno/issues/7288. For that we probably will solve for SKIA/WASM as well. If not, will create a separated issue to manage those platforms.
https://github.com/unoplatform/uno/pull/12076 might fix this.
Current behavior
Consider the following code:
And a XAML binding such as:
The image never shows anything. This works fine in UWP and WASM.
Expected behavior
The image should show whatever the source is set to later.
Workaround
Bind to an image source that fires a property changed notification when it is finished loading and provides a "ready"
BitmapImage
, but this would require considerable changes to the application architecture to facilitate.Environment
Nuget Package:
Nuget Package Version(s): 3.5.0-dev.385, 3,5.1, 3.6.0-dev.378
Affected platform(s):
Anything else we need to know?
I'm guessing this may be a problem on other platforms (i.e. Android) as well, but I'm not sure as of right now.